@ui5/builder 5.0.0-alpha.3 → 5.0.0-alpha.5
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 +54 -0
- package/lib/lbt/bundle/Builder.js +3 -2
- package/lib/lbt/bundle/ResolvedBundleDefinition.js +1 -0
- package/lib/lbt/bundle/Resolver.js +20 -0
- package/lib/lbt/calls/SapUiDefine.js +1 -1
- package/lib/lbt/resources/ModuleInfo.js +2 -1
- package/lib/lbt/resources/ResourceFilterList.js +10 -0
- package/lib/lbt/resources/ResourcePool.js +5 -2
- package/lib/processors/bundlers/flexChangesBundler.js +17 -6
- package/lib/processors/bundlers/moduleBundler.js +1 -1
- package/lib/processors/jsdoc/jsdocGenerator.js +2 -1
- package/lib/processors/jsdoc/lib/transformApiJson.js +96 -23
- package/lib/processors/jsdoc/lib/ui5/plugin.js +64 -10
- package/lib/processors/jsdoc/lib/ui5/template/publish.js +28 -0
- package/lib/processors/nonAsciiEscaper.js +1 -1
- package/lib/processors/stringReplacer.js +2 -1
- package/lib/tasks/buildThemes.js +1 -1
- package/lib/tasks/bundlers/generateFlexChangesBundle.js +3 -1
- package/lib/tasks/escapeNonAsciiCharacters.js +10 -3
- package/lib/tasks/generateResourcesJson.js +1 -1
- package/lib/tasks/minify.js +21 -4
- package/lib/tasks/replaceBuildtime.js +21 -17
- package/lib/tasks/replaceCopyright.js +23 -17
- package/lib/tasks/replaceVersion.js +21 -16
- package/package.json +15 -15
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,60 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
|
|
|
4
4
|
|
|
5
5
|
A list of unreleased changes can be found [here](https://github.com/SAP/ui5-builder/compare/v4.0.11...HEAD).
|
|
6
6
|
|
|
7
|
+
## [5.0.0-alpha.5](https://github.com/UI5/cli/compare/builder-v5.0.0-alpha.4...builder-v5.0.0-alpha.5) (2026-06-24)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* **builder:** Adapt build tasks for incremental builds ([ace5ebb](https://github.com/UI5/cli/commit/ace5ebb6bf10b7d72db6397460f12e9040121456))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* **builder:** Also detect import.meta as ESM indicator ([5d1dcb7](https://github.com/UI5/cli/commit/5d1dcb719056eba85dc13271493baa8d5cbd1bd1))
|
|
18
|
+
* **builder:** Reduce noise from ESM parse errors ([4e7f69a](https://github.com/UI5/cli/commit/4e7f69aede38571dcd4643414ff54ab6131a5c73))
|
|
19
|
+
* **builder:** Skip ESM modules during bundling and log errors ([20bcdf2](https://github.com/UI5/cli/commit/20bcdf212c30569a6aba5c7c61d5717bfd9b1d0b))
|
|
20
|
+
* **builder:** Update lbt/bundle/Resolver to ensure deterministic ordering of raw modules ([9d19923](https://github.com/UI5/cli/commit/9d19923437f41f511cb51fb8477e7a2dec1f0d13))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Dependencies
|
|
24
|
+
|
|
25
|
+
* Bump espree from 10.4.0 to 11.2.0 ([#1381](https://github.com/UI5/cli/issues/1381)) ([29a00b2](https://github.com/UI5/cli/commit/29a00b236e4c410e4a47ccb0842e851ff9e2ab4a))
|
|
26
|
+
* Update npm dependencies ([0ac8ebb](https://github.com/UI5/cli/commit/0ac8ebbb5ffe9fc6e4455244cf5da50e4c540c5c))
|
|
27
|
+
* The following workspace dependencies were updated
|
|
28
|
+
* dependencies
|
|
29
|
+
* @ui5/fs bumped from ^5.0.0-alpha.4 to ^5.0.0-alpha.5
|
|
30
|
+
* @ui5/logger bumped from ^5.0.0-alpha.4 to ^5.0.0-alpha.5
|
|
31
|
+
* devDependencies
|
|
32
|
+
* @ui5/project bumped from ^5.0.0-alpha.4 to ^5.0.0-alpha.5
|
|
33
|
+
|
|
34
|
+
## [5.0.0-alpha.4](https://github.com/UI5/cli/compare/builder-v5.0.0-alpha.3...builder-v5.0.0-alpha.4) (2026-03-24)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
### Features
|
|
38
|
+
|
|
39
|
+
* **builder:** Add dynamic section for API reference during JSDoc build ([47970f7](https://github.com/UI5/cli/commit/47970f74c4adf63625e4f330f19090083f563f82))
|
|
40
|
+
* **builder:** Add hierarchical subsection support for API reference sections ([49a3ef5](https://github.com/UI5/cli/commit/49a3ef569074ff84b5f6dfc2cfc619cd1654c2c8))
|
|
41
|
+
* **builder:** Automatically add [@lends](https://github.com/lends) tag to extend calls during JSdoc build ([3547f42](https://github.com/UI5/cli/commit/3547f425b33663f7e5e2618a6d876fe018058d99))
|
|
42
|
+
* **builder:** In JSDoc build, push the deprecation of namespaces down to the contained APIs ([71c08f2](https://github.com/UI5/cli/commit/71c08f2bb1d2cfee34ab9ca2e9e6042b5e67ae0c))
|
|
43
|
+
* **builder:** Mark cross-references to typedefs in the api.json (SDK variant) ([a474700](https://github.com/UI5/cli/commit/a47470050e804192bfab857f6c224faa6e445e10))
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
### Bug Fixes
|
|
47
|
+
|
|
48
|
+
* **builder:** Improve JSDoc support for "module:" syntax ([aca05f0](https://github.com/UI5/cli/commit/aca05f0b75561f33842ccb30248ede3a82f2ae46))
|
|
49
|
+
* **builder:** JSDoc: avoid errors when symbol has no events ([6e517e6](https://github.com/UI5/cli/commit/6e517e6c7f480784b93e37e94dcf74e0a689427f))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
### Dependencies
|
|
53
|
+
|
|
54
|
+
* The following workspace dependencies were updated
|
|
55
|
+
* dependencies
|
|
56
|
+
* @ui5/fs bumped from ^5.0.0-alpha.3 to ^5.0.0-alpha.4
|
|
57
|
+
* @ui5/logger bumped from ^5.0.0-alpha.3 to ^5.0.0-alpha.4
|
|
58
|
+
* devDependencies
|
|
59
|
+
* @ui5/project bumped from ^5.0.0-alpha.3 to ^5.0.0-alpha.4
|
|
60
|
+
|
|
7
61
|
## [5.0.0-alpha.3](https://github.com/UI5/cli/compare/builder-v5.0.0-alpha.2...builder-v5.0.0-alpha.3) (2026-02-13)
|
|
8
62
|
|
|
9
63
|
|
|
@@ -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}`);
|
|
@@ -39,7 +39,7 @@ class SapUiDefineCall {
|
|
|
39
39
|
this.dependencies = this.dependencyArray.elements.map( (elem) => {
|
|
40
40
|
const value = getStringValue(elem);
|
|
41
41
|
if ( !value ) {
|
|
42
|
-
throw new TypeError();
|
|
42
|
+
throw new TypeError(`dependency element is not a string literal in module ${this.name}`);
|
|
43
43
|
}
|
|
44
44
|
return resolveRelativeRequireJSName(this.name, value);
|
|
45
45
|
});
|
|
@@ -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.
|
|
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
|
|
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 && (
|
|
81
|
-
|
|
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
|
|
84
|
-
"
|
|
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,
|
|
@@ -58,7 +58,7 @@ const log = getLogger("builder:processors:bundlers:moduleBundler");
|
|
|
58
58
|
* Excludes should be marked with a leading exclamation mark '!'. The order of filters is relevant; a later
|
|
59
59
|
* exclusion overrides an earlier inclusion, and vice versa.
|
|
60
60
|
*
|
|
61
|
-
* <
|
|
61
|
+
* <i>Example:</i>
|
|
62
62
|
*
|
|
63
63
|
* ```js
|
|
64
64
|
* // Includes everything from "some/path/to/module/",
|
|
@@ -163,10 +163,11 @@ async function buildJsdoc({sourcePath, configPath}) {
|
|
|
163
163
|
"--verbose",
|
|
164
164
|
sourcePath
|
|
165
165
|
];
|
|
166
|
-
const exitCode = await new Promise((resolve
|
|
166
|
+
const exitCode = await new Promise((resolve, reject) => {
|
|
167
167
|
const child = spawn("node", args, {
|
|
168
168
|
stdio: ["ignore", "ignore", "inherit"]
|
|
169
169
|
});
|
|
170
|
+
child.on("error", reject);
|
|
170
171
|
child.on("close", resolve);
|
|
171
172
|
});
|
|
172
173
|
|
|
@@ -47,10 +47,10 @@ const typeParser = new TypeParser();
|
|
|
47
47
|
* @param {string} sLibraryFile Path to the .library file of the library, used to extract further documentation information
|
|
48
48
|
* @param {string|string[]} vDependencyAPIFiles Path of folder that contains api.json files of predecessor libs or
|
|
49
49
|
* an array of paths of those files
|
|
50
|
-
* @param {string}
|
|
50
|
+
* @param {string} sSectionsDir Path to the directory containing the sources for the sections (FAQ, documentation, etc.) in the API Reference
|
|
51
51
|
* @returns {Promise} A Promise that resolves after the transformation has been completed
|
|
52
52
|
*/
|
|
53
|
-
function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
53
|
+
function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles, sSectionsDir, options) {
|
|
54
54
|
const fs = options && options.fs || require("fs");
|
|
55
55
|
const returnOutputFiles = options && !!options.returnOutputFiles;
|
|
56
56
|
|
|
@@ -59,7 +59,7 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
59
59
|
log.info(" output file: " + sOutputFile);
|
|
60
60
|
log.info(" library file: " + sLibraryFile);
|
|
61
61
|
log.info(" dependency dir: " + vDependencyAPIFiles);
|
|
62
|
-
log.info("
|
|
62
|
+
log.info(" sections src dir: " + sSectionsDir);
|
|
63
63
|
if (options && options.fs) {
|
|
64
64
|
log.info("Using custom fs.");
|
|
65
65
|
}
|
|
@@ -156,9 +156,10 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
156
156
|
* UI5Types: ["sap.ui.core.Control"] // skip template if its value is "${0}" (default value)
|
|
157
157
|
* }
|
|
158
158
|
* @param {string} sComplexType
|
|
159
|
+
* @param {Object<string,object>} oAllDependentAPIs Map of entity names to their symbol
|
|
159
160
|
* @returns {{template=: string, UI5Types=: string[]}}
|
|
160
161
|
*/
|
|
161
|
-
function parseUI5Types(sComplexType) {
|
|
162
|
+
function parseUI5Types(sComplexType, oAllDependentAPIs) {
|
|
162
163
|
let oParsed;
|
|
163
164
|
try {
|
|
164
165
|
oParsed = typeParser.parseSimpleTypes(sComplexType, isUI5Type);
|
|
@@ -176,6 +177,14 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
176
177
|
|
|
177
178
|
if (oParsed.simpleTypes?.length) { // it can be empty if none of the included simple types satisfied the filter function
|
|
178
179
|
result.UI5Types = oParsed.simpleTypes;
|
|
180
|
+
|
|
181
|
+
// check whether the type refers to a typedef and set a marker
|
|
182
|
+
if (result.template == null && result.UI5Types.length === 1) {
|
|
183
|
+
const symbol = oAllDependentAPIs[result.UI5Types[0]];
|
|
184
|
+
if (symbol?.kind === "typedef" && Array.isArray(symbol.properties)) {
|
|
185
|
+
result.refersToTypedef = true;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
179
188
|
}
|
|
180
189
|
|
|
181
190
|
return result;
|
|
@@ -266,6 +275,8 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
266
275
|
* @param {object} oChainObject chain object
|
|
267
276
|
*/
|
|
268
277
|
const transformApiJson = function (oChainObject) {
|
|
278
|
+
const {oAllDependentAPIs} = oChainObject;
|
|
279
|
+
|
|
269
280
|
// Function is a copy from: LibraryInfo.js => LibraryInfo.prototype._getActualComponent => "match" inline method
|
|
270
281
|
function matchComponent(sModuleName, sPattern) {
|
|
271
282
|
sModuleName = sModuleName.toLowerCase();
|
|
@@ -435,7 +446,7 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
435
446
|
// Types
|
|
436
447
|
oParameter.types = [];
|
|
437
448
|
if (oParameter.type) {
|
|
438
|
-
oParameter.typeInfo = parseUI5Types(oParameter.type);
|
|
449
|
+
oParameter.typeInfo = parseUI5Types(oParameter.type, oAllDependentAPIs);
|
|
439
450
|
// Keep file size in check
|
|
440
451
|
delete oParameter.type;
|
|
441
452
|
}
|
|
@@ -520,7 +531,7 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
520
531
|
// Type
|
|
521
532
|
if (oSymbol.kind !== "enum") { // enum properties don't have an own type
|
|
522
533
|
if (oProperty.type) {
|
|
523
|
-
oProperty.typeInfo = parseUI5Types(oProperty.type);
|
|
534
|
+
oProperty.typeInfo = parseUI5Types(oProperty.type, oAllDependentAPIs);
|
|
524
535
|
// Keep file size in check
|
|
525
536
|
delete oProperty.type;
|
|
526
537
|
}
|
|
@@ -560,7 +571,7 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
560
571
|
|
|
561
572
|
// Type
|
|
562
573
|
if (oProperty.type) {
|
|
563
|
-
oProperty.typeInfo = parseUI5Types(oProperty.type);
|
|
574
|
+
oProperty.typeInfo = parseUI5Types(oProperty.type, oAllDependentAPIs);
|
|
564
575
|
// Keep file size in check
|
|
565
576
|
delete oProperty.type;
|
|
566
577
|
}
|
|
@@ -657,7 +668,7 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
657
668
|
Object.keys(aParams).forEach((sParam) => {
|
|
658
669
|
const sSince = aParams[sParam].since;
|
|
659
670
|
const oDeprecated = aParams[sParam].deprecated;
|
|
660
|
-
const oEvtInSymbol = oSymbol.events
|
|
671
|
+
const oEvtInSymbol = oSymbol.events?.find((e) => e.name === oEvent.name);
|
|
661
672
|
const oParamInSymbol = oEvtInSymbol && oEvtInSymbol.parameters[0] &&
|
|
662
673
|
oEvtInSymbol.parameters[0].parameterProperties &&
|
|
663
674
|
oEvtInSymbol.parameters[0].parameterProperties.getParameters &&
|
|
@@ -687,7 +698,7 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
687
698
|
|
|
688
699
|
// Link Enabled
|
|
689
700
|
if (oSetting.type) {
|
|
690
|
-
oSetting.typeInfo = parseUI5Types(oSetting.type);
|
|
701
|
+
oSetting.typeInfo = parseUI5Types(oSetting.type, oAllDependentAPIs);
|
|
691
702
|
delete oSetting.type; // Keep file size in check
|
|
692
703
|
}
|
|
693
704
|
|
|
@@ -756,7 +767,7 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
756
767
|
oEvent.parameters.forEach((oParameter) => {
|
|
757
768
|
|
|
758
769
|
if (oParameter.type) {
|
|
759
|
-
oParameter.typeInfo = parseUI5Types(oParameter.type);
|
|
770
|
+
oParameter.typeInfo = parseUI5Types(oParameter.type, oAllDependentAPIs);
|
|
760
771
|
delete oParameter.type; // Keep file size in check
|
|
761
772
|
}
|
|
762
773
|
|
|
@@ -789,7 +800,7 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
789
800
|
if (oSymbol.methods) {
|
|
790
801
|
|
|
791
802
|
// Pre-process methods
|
|
792
|
-
methods.buildMethodsModel(oSymbol.methods);
|
|
803
|
+
methods.buildMethodsModel(oSymbol.methods, oAllDependentAPIs);
|
|
793
804
|
|
|
794
805
|
oSymbol.methods.forEach((oMethod) => {
|
|
795
806
|
|
|
@@ -950,6 +961,14 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
950
961
|
}
|
|
951
962
|
|
|
952
963
|
function loadDependencyLibraryFiles (oChainObject) {
|
|
964
|
+
const oAllDependentAPIs = oChainObject.oAllDependentAPIs = Object.create(null);
|
|
965
|
+
// add symbols from current library
|
|
966
|
+
if (oChainObject.fileData.symbols) {
|
|
967
|
+
for (const oSymbol of oChainObject.fileData.symbols) {
|
|
968
|
+
oAllDependentAPIs[oSymbol.name] = oSymbol;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
953
972
|
if (!oChainObject.aDependentLibraryFiles) {
|
|
954
973
|
return oChainObject;
|
|
955
974
|
}
|
|
@@ -978,6 +997,12 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
978
997
|
// In this case we don't add it to the dependency list to skip double iteration.
|
|
979
998
|
if (oData && oChainObject.fileData.library !== oData.library) {
|
|
980
999
|
oDependentAPIs[oData.library] = oData.symbols;
|
|
1000
|
+
|
|
1001
|
+
if (Array.isArray(oData.symbols)) {
|
|
1002
|
+
for (const oSymbol of oData.symbols) {
|
|
1003
|
+
oAllDependentAPIs[oSymbol.name] = oSymbol;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
981
1006
|
}
|
|
982
1007
|
});
|
|
983
1008
|
|
|
@@ -987,22 +1012,69 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
987
1012
|
}
|
|
988
1013
|
|
|
989
1014
|
/**
|
|
990
|
-
* Check for existence of
|
|
991
|
-
* (
|
|
1015
|
+
* Check for existence of sections data
|
|
1016
|
+
* (Sections data must be defined as *.md files in the <code>sSectionsDir</code>)
|
|
992
1017
|
* and add a boolean flag in case it exists
|
|
993
1018
|
*
|
|
994
1019
|
* @param oChainObject chain object
|
|
995
1020
|
*/
|
|
996
|
-
function
|
|
997
|
-
if (!
|
|
1021
|
+
function addFlagsForSectionsData(oChainObject) {
|
|
1022
|
+
if (!sSectionsDir) {
|
|
998
1023
|
return oChainObject;
|
|
999
1024
|
}
|
|
1025
|
+
|
|
1000
1026
|
const slibName = oChainObject.fileData.library;
|
|
1027
|
+
|
|
1001
1028
|
oChainObject.fileData.symbols.forEach(function(symbol) {
|
|
1002
|
-
const
|
|
1003
|
-
if (
|
|
1004
|
-
|
|
1029
|
+
const sComponentPath = symbol.name.replace(slibName, "").replace(/^[.]/, "").replace(/[.]/g, "/");
|
|
1030
|
+
if (!sComponentPath) {
|
|
1031
|
+
return;
|
|
1005
1032
|
}
|
|
1033
|
+
|
|
1034
|
+
const componentDir = path.join(sSectionsDir, sComponentPath);
|
|
1035
|
+
if (fs.existsSync(componentDir)) {
|
|
1036
|
+
try {
|
|
1037
|
+
const dirContents = fs.readdirSync(componentDir, { withFileTypes: true });
|
|
1038
|
+
|
|
1039
|
+
// Separate files and directories in one pass
|
|
1040
|
+
const mdFiles = [];
|
|
1041
|
+
const dirNames = new Set();
|
|
1042
|
+
dirContents.forEach((dirent) => {
|
|
1043
|
+
if (dirent.isFile() && dirent.name.endsWith('.md')) {
|
|
1044
|
+
mdFiles.push(dirent.name.replace(/\.md$/, ''));
|
|
1045
|
+
} else if (dirent.isDirectory()) {
|
|
1046
|
+
dirNames.add(dirent.name);
|
|
1047
|
+
}
|
|
1048
|
+
});
|
|
1049
|
+
|
|
1050
|
+
// Build customSections array with subsection support
|
|
1051
|
+
const customSections = mdFiles.map(function(sectionName) {
|
|
1052
|
+
// Check if there's a matching directory for this section
|
|
1053
|
+
if (dirNames.has(sectionName)) {
|
|
1054
|
+
try {
|
|
1055
|
+
const subsectionFiles = fs.readdirSync(path.join(componentDir, sectionName), { withFileTypes: true })
|
|
1056
|
+
.filter((dirent) => dirent.isFile() && dirent.name.endsWith('.md'))
|
|
1057
|
+
.map((dirent) => dirent.name.replace(/\.md$/, ''));
|
|
1058
|
+
|
|
1059
|
+
if (subsectionFiles.length > 0) {
|
|
1060
|
+
return { name: sectionName, hasSubsections: true, subsections: subsectionFiles };
|
|
1061
|
+
}
|
|
1062
|
+
} catch (error) {
|
|
1063
|
+
log.error('Error scanning subsection directory:', path.join(componentDir, sectionName), error);
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
return sectionName;
|
|
1067
|
+
});
|
|
1068
|
+
|
|
1069
|
+
if (customSections.length > 0) {
|
|
1070
|
+
symbol.customSections = customSections;
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
} catch (error) {
|
|
1074
|
+
log.error('Error scanning component sections directory:', componentDir, error);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1006
1078
|
});
|
|
1007
1079
|
return oChainObject;
|
|
1008
1080
|
}
|
|
@@ -2175,7 +2247,7 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
2175
2247
|
* Adjusts methods info so that it can be easily displayed in a table
|
|
2176
2248
|
* @param aMethods - the methods array initially coming from the server
|
|
2177
2249
|
*/
|
|
2178
|
-
buildMethodsModel: function (aMethods) {
|
|
2250
|
+
buildMethodsModel: function (aMethods, oAllDependentAPIs) {
|
|
2179
2251
|
var fnExtractParameterProperties = function (oParameter, aParameters, iDepth, aPhoneName) {
|
|
2180
2252
|
if (oParameter.parameterProperties) {
|
|
2181
2253
|
Object.keys(oParameter.parameterProperties).forEach(function (sProperty) {
|
|
@@ -2185,7 +2257,7 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
2185
2257
|
|
|
2186
2258
|
// Handle types
|
|
2187
2259
|
if (oProperty.type) {
|
|
2188
|
-
oProperty.typeInfo = parseUI5Types(oProperty.type);
|
|
2260
|
+
oProperty.typeInfo = parseUI5Types(oProperty.type, oAllDependentAPIs);
|
|
2189
2261
|
// Keep file size in check
|
|
2190
2262
|
delete oProperty.type;
|
|
2191
2263
|
}
|
|
@@ -2217,7 +2289,7 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
2217
2289
|
if (oMethod.parameters) {
|
|
2218
2290
|
oMethod.parameters.forEach(function (oParameter) {
|
|
2219
2291
|
if (oParameter.type) {
|
|
2220
|
-
oParameter.typeInfo = parseUI5Types(oParameter.type);
|
|
2292
|
+
oParameter.typeInfo = parseUI5Types(oParameter.type, oAllDependentAPIs);
|
|
2221
2293
|
// Keep file size in check
|
|
2222
2294
|
delete oParameter.type;
|
|
2223
2295
|
}
|
|
@@ -2238,7 +2310,7 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
2238
2310
|
// Handle return values
|
|
2239
2311
|
if (oMethod.returnValue && oMethod.returnValue.type) {
|
|
2240
2312
|
// Handle types
|
|
2241
|
-
oMethod.returnValue.typeInfo = parseUI5Types(oMethod.returnValue.type);
|
|
2313
|
+
oMethod.returnValue.typeInfo = parseUI5Types(oMethod.returnValue.type, oAllDependentAPIs);
|
|
2242
2314
|
}
|
|
2243
2315
|
|
|
2244
2316
|
});
|
|
@@ -2375,6 +2447,7 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
2375
2447
|
inputFile: sInputFile,
|
|
2376
2448
|
outputFile: sOutputFile,
|
|
2377
2449
|
libraryFile: sLibraryFile,
|
|
2450
|
+
sectionsDir: sSectionsDir,
|
|
2378
2451
|
aDependentLibraryFiles: Array.isArray(vDependencyAPIFiles) ? vDependencyAPIFiles : null
|
|
2379
2452
|
};
|
|
2380
2453
|
|
|
@@ -2387,7 +2460,7 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
2387
2460
|
.then(getAPIJSONPromise)
|
|
2388
2461
|
.then(loadDependencyLibraryFiles)
|
|
2389
2462
|
.then(transformApiJson)
|
|
2390
|
-
.then(
|
|
2463
|
+
.then(addFlagsForSectionsData)
|
|
2391
2464
|
.then(createApiRefApiJson);
|
|
2392
2465
|
return p;
|
|
2393
2466
|
|
|
@@ -73,7 +73,8 @@ const path = require('jsdoc/path');
|
|
|
73
73
|
const logger = require('jsdoc/util/logger');
|
|
74
74
|
const pluginConfig = (env.conf && env.conf.templates && env.conf.templates.ui5) || env.opts.sapui5 || {};
|
|
75
75
|
const escope = require("escope");
|
|
76
|
-
const
|
|
76
|
+
const templatePath = path.getResourcePath(env.opts.template) || "./template";
|
|
77
|
+
const {isSemVer} = require(`${templatePath}/utils/versionUtil`);
|
|
77
78
|
|
|
78
79
|
/* ---- logging ---- */
|
|
79
80
|
|
|
@@ -1220,11 +1221,13 @@ function collectClassInfo(extendCall, classDoclet) {
|
|
|
1220
1221
|
if ( classDoclet && classDoclet.augments && classDoclet.augments.length === 1 ) {
|
|
1221
1222
|
baseType = classDoclet.augments[0];
|
|
1222
1223
|
}
|
|
1224
|
+
const jsdocClassName = classDoclet?.kind === "class" ? classDoclet.alias || classDoclet.longname : undefined;
|
|
1225
|
+
|
|
1223
1226
|
if ( isMemberExpression(extendCall.callee) ) {
|
|
1224
1227
|
const baseCandidate = getResolvedObjectName(extendCall.callee.object);
|
|
1225
1228
|
if ( baseCandidate && baseType == null ) {
|
|
1226
1229
|
baseType = baseCandidate;
|
|
1227
|
-
} else if ( baseCandidate !== baseType ) {
|
|
1230
|
+
} else if ( baseCandidate !== toRuntimeMetadataName(baseType) ) {
|
|
1228
1231
|
future(`documented base type '${baseType}' doesn't match technical base type '${baseCandidate}'`);
|
|
1229
1232
|
}
|
|
1230
1233
|
}
|
|
@@ -1283,6 +1286,32 @@ function collectClassInfo(extendCall, classDoclet) {
|
|
|
1283
1286
|
}
|
|
1284
1287
|
|
|
1285
1288
|
const classInfoNode = extendCall.arguments[1];
|
|
1289
|
+
if (classInfoNode?.type === Syntax.ObjectExpression && jsdocClassName && addLeadingCommentNode) {
|
|
1290
|
+
// Take care of the @lends comment only
|
|
1291
|
+
// - when the class info is an object literal (otherwise lends makes no sense)
|
|
1292
|
+
// - when a class name is found (it might differ from the runtime metadata name)
|
|
1293
|
+
// - when the entity is documented as a class (or else '.prototype' would be wrong)
|
|
1294
|
+
const classInfoComment = getLeadingCommentNode(classInfoNode);
|
|
1295
|
+
if (classInfoComment == null) {
|
|
1296
|
+
// If the class info object doesn't have a @lends tag, add it
|
|
1297
|
+
const raw = `/** @lends ${jsdocClassName}.prototype */`;
|
|
1298
|
+
info(`lends comment injected for class '${jsdocClassName}'`);
|
|
1299
|
+
addLeadingCommentNode(classInfoNode, {
|
|
1300
|
+
type: "CommentBlock",
|
|
1301
|
+
raw,
|
|
1302
|
+
value: raw.slice(2,-2),
|
|
1303
|
+
loc: classInfoNode.loc
|
|
1304
|
+
});
|
|
1305
|
+
} else {
|
|
1306
|
+
// Otherwise check whether the name matches the name of the described class
|
|
1307
|
+
const doclet = new Doclet(getRawComment(classInfoComment), {});
|
|
1308
|
+
// The name after the @lends is surprisingly stored in the 'alias' property
|
|
1309
|
+
if (doclet.alias !== `${jsdocClassName}.prototype`) {
|
|
1310
|
+
future(`lends comment '${doclet.alias}' doesn't match documented class name '${jsdocClassName}'`);
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1286
1315
|
const classInfoMap = createPropertyMap(classInfoNode);
|
|
1287
1316
|
if ( classInfoMap && classInfoMap.metadata && classInfoMap.metadata.value.type !== Syntax.ObjectExpression ) {
|
|
1288
1317
|
warning(`class metadata exists but can't be analyzed. It is not of type 'ObjectExpression', but a '${classInfoMap.metadata.value.type}'.`);
|
|
@@ -1772,7 +1801,7 @@ function createAutoDoc(oClassInfo, classComment, doclet, node, parser, filename,
|
|
|
1772
1801
|
}
|
|
1773
1802
|
|
|
1774
1803
|
function name(prefix, n, _static) {
|
|
1775
|
-
return
|
|
1804
|
+
return jsdocClassName + rname(prefix, n, _static);
|
|
1776
1805
|
}
|
|
1777
1806
|
|
|
1778
1807
|
/*
|
|
@@ -1884,6 +1913,18 @@ function createAutoDoc(oClassInfo, classComment, doclet, node, parser, filename,
|
|
|
1884
1913
|
const p = m ? m.index : -1;
|
|
1885
1914
|
const hasSettingsDocs = rawClassComment.indexOf("The supported settings are:") >= 0;
|
|
1886
1915
|
const classAccess = doclet?.access ?? "public";
|
|
1916
|
+
|
|
1917
|
+
// If doclet exists and has an alias or longname, use that when building the fully qualified
|
|
1918
|
+
// names of methods or events.
|
|
1919
|
+
// Do this only when the doclet is of kind "class". Many TypeScript classes unfortunately
|
|
1920
|
+
// use a broken pattern with @namespace (needs to be deprecated in babel-plugin-transform-modules-ui5)
|
|
1921
|
+
const jsdocClassName =
|
|
1922
|
+
(doclet?.kind === "class" ? doclet.alias || doclet.longname : undefined) || oClassInfo.name;
|
|
1923
|
+
if (jsdocClassName !== oClassInfo.name) {
|
|
1924
|
+
info("jsdoc class name differs from runtime metadata name", jsdocClassName, oClassInfo.name);
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
const displayClassName = oClassInfo.name;
|
|
1887
1928
|
const visibility = createVisibilityTags(classAccess, doclet?.__ui5?.stakeholders);
|
|
1888
1929
|
const thisClass = 'this'; // oClassInfo.name
|
|
1889
1930
|
|
|
@@ -2007,7 +2048,7 @@ function createAutoDoc(oClassInfo, classComment, doclet, node, parser, filename,
|
|
|
2007
2048
|
}
|
|
2008
2049
|
|
|
2009
2050
|
newJSDoc([
|
|
2010
|
-
"Returns a metadata object for class " +
|
|
2051
|
+
"Returns a metadata object for class " + displayClassName + ".",
|
|
2011
2052
|
"",
|
|
2012
2053
|
"@returns {sap.ui.base.Metadata} Metadata object describing this class",
|
|
2013
2054
|
visibility,
|
|
@@ -2018,7 +2059,7 @@ function createAutoDoc(oClassInfo, classComment, doclet, node, parser, filename,
|
|
|
2018
2059
|
|
|
2019
2060
|
if ( !oClassInfo["final"] ) {
|
|
2020
2061
|
newJSDoc([
|
|
2021
|
-
"Creates a new subclass of class " +
|
|
2062
|
+
"Creates a new subclass of class " + displayClassName + " with name <code>sClassName</code>",
|
|
2022
2063
|
"and enriches it with the information contained in <code>oClassInfo</code>.",
|
|
2023
2064
|
"",
|
|
2024
2065
|
"<code>oClassInfo</code> might contain the same kind of information as described in {@link " + (oClassInfo.baseType ? oClassInfo.baseType + ".extend" : "sap.ui.base.Object.extend Object.extend") + "}.",
|
|
@@ -2304,7 +2345,7 @@ function createAutoDoc(oClassInfo, classComment, doclet, node, parser, filename,
|
|
|
2304
2345
|
"",
|
|
2305
2346
|
info.enableEventBubbling ? "This event bubbles up the control hierarchy." : "",
|
|
2306
2347
|
"",
|
|
2307
|
-
"@name " +
|
|
2348
|
+
"@name " + jsdocClassName + "#" + n,
|
|
2308
2349
|
"@event",
|
|
2309
2350
|
devStateTags,
|
|
2310
2351
|
"@param {sap.ui.base.Event} oControlEvent",
|
|
@@ -2321,10 +2362,10 @@ function createAutoDoc(oClassInfo, classComment, doclet, node, parser, filename,
|
|
|
2321
2362
|
newJSDoc(lines);
|
|
2322
2363
|
|
|
2323
2364
|
newJSDoc([
|
|
2324
|
-
"Attaches event handler <code>fnFunction</code> to the " + link + " event of this <code>" +
|
|
2365
|
+
"Attaches event handler <code>fnFunction</code> to the " + link + " event of this <code>" + displayClassName + "</code>.",
|
|
2325
2366
|
"",
|
|
2326
2367
|
"When called, the context of the event handler (its <code>this</code>) will be bound to <code>oListener</code> if specified, ",
|
|
2327
|
-
"otherwise it will be bound to this <code>" +
|
|
2368
|
+
"otherwise it will be bound to this <code>" + displayClassName + "</code> itself.",
|
|
2328
2369
|
"",
|
|
2329
2370
|
!newStyle && info.doc ? info.doc : "",
|
|
2330
2371
|
"",
|
|
@@ -2333,7 +2374,7 @@ function createAutoDoc(oClassInfo, classComment, doclet, node, parser, filename,
|
|
|
2333
2374
|
"@param {function(sap.ui.base.Event):void}",
|
|
2334
2375
|
" fnFunction The function to be called when the event occurs",
|
|
2335
2376
|
"@param {object}",
|
|
2336
|
-
" [oListener] Context object to call the event handler with. Defaults to this <code>" +
|
|
2377
|
+
" [oListener] Context object to call the event handler with. Defaults to this <code>" + displayClassName + "</code> itself",
|
|
2337
2378
|
"",
|
|
2338
2379
|
"@returns {" + thisClass + "} Reference to <code>this</code> in order to allow method chaining",
|
|
2339
2380
|
devStateTags,
|
|
@@ -2342,7 +2383,7 @@ function createAutoDoc(oClassInfo, classComment, doclet, node, parser, filename,
|
|
|
2342
2383
|
"@function"
|
|
2343
2384
|
]);
|
|
2344
2385
|
newJSDoc([
|
|
2345
|
-
"Detaches event handler <code>fnFunction</code> from the " + link + " event of this <code>" +
|
|
2386
|
+
"Detaches event handler <code>fnFunction</code> from the " + link + " event of this <code>" + displayClassName + "</code>.",
|
|
2346
2387
|
"",
|
|
2347
2388
|
"The passed function and listener object must match the ones used for event registration.",
|
|
2348
2389
|
"",
|
|
@@ -2439,6 +2480,7 @@ function toRuntimeMetadataName(longname) {
|
|
|
2439
2480
|
|
|
2440
2481
|
let isDocComment;
|
|
2441
2482
|
let getLeadingCommentNode;
|
|
2483
|
+
let addLeadingCommentNode;
|
|
2442
2484
|
|
|
2443
2485
|
// JSDoc added the node type <code>Syntax.File</code> with the same change that activated Babylon
|
|
2444
2486
|
// See https://github.com/jsdoc3/jsdoc/commit/ffec4a42291de6d68e6240f304b68d6abb82a869
|
|
@@ -2464,6 +2506,15 @@ if ( Syntax.File === 'File' ) {
|
|
|
2464
2506
|
return undefined;
|
|
2465
2507
|
};
|
|
2466
2508
|
|
|
2509
|
+
addLeadingCommentNode = function(node, comment) {
|
|
2510
|
+
node.leadingComments ??= [];
|
|
2511
|
+
let index = node.leadingComments.length;
|
|
2512
|
+
while (index > 0 && node.leadingComments[index - 1].type !== 'CommentBlock') {
|
|
2513
|
+
index--;
|
|
2514
|
+
}
|
|
2515
|
+
node.leadingComments.splice(index, 0, comment);
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2467
2518
|
} else {
|
|
2468
2519
|
|
|
2469
2520
|
// JSDoc versions before 3.5.0
|
|
@@ -2498,6 +2549,9 @@ if ( Syntax.File === 'File' ) {
|
|
|
2498
2549
|
|
|
2499
2550
|
return comment;
|
|
2500
2551
|
};
|
|
2552
|
+
|
|
2553
|
+
// not implemented for espree (no automatic injection of @lends comments)
|
|
2554
|
+
addLeadingCommentNode = undefined;
|
|
2501
2555
|
}
|
|
2502
2556
|
|
|
2503
2557
|
//--- comment related functions that are independent from the JSdoc version
|
|
@@ -231,6 +231,7 @@ function publish(symbolSet) {
|
|
|
231
231
|
|
|
232
232
|
// now resolve relationships
|
|
233
233
|
const aRootNamespaces = createNamespaceTree(allSymbols);
|
|
234
|
+
pushDownDeprecations(allSymbols);
|
|
234
235
|
createInheritanceTree(allSymbols);
|
|
235
236
|
collectMembers(allSymbols);
|
|
236
237
|
mergeEventDocumentation(allSymbols);
|
|
@@ -374,6 +375,33 @@ function makeNamespace(memberof) {
|
|
|
374
375
|
]);
|
|
375
376
|
}
|
|
376
377
|
|
|
378
|
+
function pushDownDeprecations() {
|
|
379
|
+
|
|
380
|
+
function pushDown(oSymbol, sInheritedDeprecation) {
|
|
381
|
+
if (oSymbol == null || !isFirstClassSymbol(oSymbol)) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
const sOwnDeprecation = oSymbol.deprecated;
|
|
385
|
+
if (sOwnDeprecation == null && sInheritedDeprecation != null) {
|
|
386
|
+
oSymbol.deprecated = sInheritedDeprecation;
|
|
387
|
+
info(`mark ${oSymbol.longname} as deprecated (${sInheritedDeprecation})`);
|
|
388
|
+
} else if (sOwnDeprecation != null) {
|
|
389
|
+
const info = extractSince(sOwnDeprecation);
|
|
390
|
+
const sinceBecause = info.since ? `As of version ${info.since}, because`: `Because`;
|
|
391
|
+
sInheritedDeprecation = `${sinceBecause} it is part of the deprecated package ${oSymbol.longname}`;
|
|
392
|
+
}
|
|
393
|
+
oSymbol.__ui5.children?.forEach((oChild) => pushDown(oChild, sInheritedDeprecation));
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// w/o a library name we can't start with the library namespace
|
|
397
|
+
if (!templateConf.uilib) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// start the push down at the library namespace to ensure locality
|
|
402
|
+
pushDown(lookup(templateConf.uilib));
|
|
403
|
+
}
|
|
404
|
+
|
|
377
405
|
//---- inheritance hierarchy ----------------------------------------------------------------------------
|
|
378
406
|
|
|
379
407
|
/*
|
|
@@ -83,8 +83,8 @@ async function nonAsciiEscaper({resources, options: {encoding}}) {
|
|
|
83
83
|
// only modify the resource's string if it was changed
|
|
84
84
|
if (escaped.modified) {
|
|
85
85
|
resource.setString(escaped.string);
|
|
86
|
+
return resource;
|
|
86
87
|
}
|
|
87
|
-
return resource;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
return Promise.all(resources.map(processResource));
|
|
@@ -21,9 +21,10 @@ export default function({resources, options: {pattern, replacement}}) {
|
|
|
21
21
|
return Promise.all(resources.map(async (resource) => {
|
|
22
22
|
const content = await resource.getString();
|
|
23
23
|
const newContent = content.replaceAll(pattern, replacement);
|
|
24
|
+
// only modify the resource's string if it was changed
|
|
24
25
|
if (content !== newContent) {
|
|
25
26
|
resource.setString(newContent);
|
|
27
|
+
return resource;
|
|
26
28
|
}
|
|
27
|
-
return resource;
|
|
28
29
|
}));
|
|
29
30
|
}
|
package/lib/tasks/buildThemes.js
CHANGED
|
@@ -192,7 +192,7 @@ export default async function({
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
let processedResources;
|
|
195
|
-
const useWorkers = !!taskUtil;
|
|
195
|
+
const useWorkers = !process.env.UI5_CLI_NO_WORKERS && !!taskUtil;
|
|
196
196
|
if (useWorkers) {
|
|
197
197
|
const threadMessageHandler = new FsMainThreadInterface(fsInterface(combo));
|
|
198
198
|
|
|
@@ -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
|
-
|
|
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
|
|
|
@@ -14,17 +14,24 @@ import nonAsciiEscaper from "../processors/nonAsciiEscaper.js";
|
|
|
14
14
|
*
|
|
15
15
|
* @param {object} parameters Parameters
|
|
16
16
|
* @param {@ui5/fs/DuplexCollection} parameters.workspace DuplexCollection to read and write files
|
|
17
|
+
* @param {string[]} [parameters.changedProjectResourcePaths] Set of changed resource paths within the project.
|
|
18
|
+
* This is only set if a cache is used and changes have been detected.
|
|
17
19
|
* @param {object} parameters.options Options
|
|
18
20
|
* @param {string} parameters.options.pattern Glob pattern to locate the files to be processed
|
|
19
21
|
* @param {string} parameters.options.encoding source file encoding either "UTF-8" or "ISO-8859-1"
|
|
20
22
|
* @returns {Promise<undefined>} Promise resolving with <code>undefined</code> once data has been written
|
|
21
23
|
*/
|
|
22
|
-
export default async function({workspace, options: {pattern, encoding}}) {
|
|
24
|
+
export default async function({workspace, changedProjectResourcePaths, options: {pattern, encoding}}) {
|
|
23
25
|
if (!encoding) {
|
|
24
26
|
throw new Error("[escapeNonAsciiCharacters] Mandatory option 'encoding' not provided");
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
|
|
29
|
+
let allResources;
|
|
30
|
+
if (changedProjectResourcePaths) {
|
|
31
|
+
allResources = await Promise.all(changedProjectResourcePaths.map((resource) => workspace.byPath(resource)));
|
|
32
|
+
} else {
|
|
33
|
+
allResources = await workspace.byGlob(pattern);
|
|
34
|
+
}
|
|
28
35
|
|
|
29
36
|
const processedResources = await nonAsciiEscaper({
|
|
30
37
|
resources: allResources,
|
|
@@ -33,5 +40,5 @@ export default async function({workspace, options: {pattern, encoding}}) {
|
|
|
33
40
|
}
|
|
34
41
|
});
|
|
35
42
|
|
|
36
|
-
await Promise.all(processedResources.map((resource) => workspace.write(resource)));
|
|
43
|
+
await Promise.all(processedResources.map((resource) => resource && workspace.write(resource)));
|
|
37
44
|
}
|
|
@@ -55,7 +55,7 @@ function getCreatorOptions(projectName) {
|
|
|
55
55
|
* Therefore it is also not supported in combination with self-contained build.
|
|
56
56
|
* </p>
|
|
57
57
|
*
|
|
58
|
-
* <
|
|
58
|
+
* <i>sample resources.json</i>
|
|
59
59
|
*
|
|
60
60
|
* ```js
|
|
61
61
|
* const resourcesJson = {
|
package/lib/tasks/minify.js
CHANGED
|
@@ -16,6 +16,8 @@ import fsInterface from "@ui5/fs/fsInterface";
|
|
|
16
16
|
* @param {object} parameters Parameters
|
|
17
17
|
* @param {@ui5/fs/DuplexCollection} parameters.workspace DuplexCollection to read and write files
|
|
18
18
|
* @param {@ui5/project/build/helpers/TaskUtil|object} [parameters.taskUtil] TaskUtil
|
|
19
|
+
* @param {string[]} [parameters.changedProjectResourcePaths] Set of changed resource paths within the project.
|
|
20
|
+
* This is only set if a cache is used and changes have been detected.
|
|
19
21
|
* @param {object} parameters.options Options
|
|
20
22
|
* @param {string} parameters.options.pattern Pattern to locate the files to be processed
|
|
21
23
|
* @param {boolean} [parameters.options.omitSourceMapResources=false] Whether source map resources shall
|
|
@@ -26,9 +28,24 @@ import fsInterface from "@ui5/fs/fsInterface";
|
|
|
26
28
|
* @returns {Promise<undefined>} Promise resolving with <code>undefined</code> once data has been written
|
|
27
29
|
*/
|
|
28
30
|
export default async function({
|
|
29
|
-
workspace, taskUtil,
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
workspace, taskUtil, changedProjectResourcePaths,
|
|
32
|
+
options: {pattern, omitSourceMapResources = false, useInputSourceMaps = true}
|
|
33
|
+
}) {
|
|
34
|
+
let resources;
|
|
35
|
+
if (changedProjectResourcePaths) {
|
|
36
|
+
resources = await Promise.all(
|
|
37
|
+
changedProjectResourcePaths
|
|
38
|
+
// Filtering out non-JS resources such as .map files
|
|
39
|
+
// FIXME: The changed resources should rather be matched against the provided pattern
|
|
40
|
+
.filter((resourcePath) => resourcePath.endsWith(".js"))
|
|
41
|
+
.map((resource) => workspace.byPath(resource))
|
|
42
|
+
);
|
|
43
|
+
} else {
|
|
44
|
+
resources = await workspace.byGlob(pattern);
|
|
45
|
+
}
|
|
46
|
+
if (resources.length === 0) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
32
49
|
const processedResources = await minifier({
|
|
33
50
|
resources,
|
|
34
51
|
fs: fsInterface(workspace),
|
|
@@ -36,7 +53,7 @@ export default async function({
|
|
|
36
53
|
options: {
|
|
37
54
|
addSourceMappingUrl: !omitSourceMapResources,
|
|
38
55
|
readSourceMappingUrl: !!useInputSourceMaps,
|
|
39
|
-
useWorkers: !!taskUtil,
|
|
56
|
+
useWorkers: !process.env.UI5_CLI_NO_WORKERS && !!taskUtil,
|
|
40
57
|
}
|
|
41
58
|
});
|
|
42
59
|
|
|
@@ -28,26 +28,30 @@ function getTimestamp() {
|
|
|
28
28
|
*
|
|
29
29
|
* @param {object} parameters Parameters
|
|
30
30
|
* @param {@ui5/fs/DuplexCollection} parameters.workspace DuplexCollection to read and write files
|
|
31
|
+
* @param {string[]} [parameters.changedProjectResourcePaths] Set of changed resource paths within the project.
|
|
32
|
+
* This is only set if a cache is used and changes have been detected.
|
|
31
33
|
* @param {object} parameters.options Options
|
|
32
34
|
* @param {string} parameters.options.pattern Pattern to locate the files to be processed
|
|
33
35
|
* @returns {Promise<undefined>} Promise resolving with <code>undefined</code> once data has been written
|
|
34
36
|
*/
|
|
35
|
-
export default function({workspace, options: {pattern}}) {
|
|
37
|
+
export default async function({workspace, changedProjectResourcePaths, options: {pattern}}) {
|
|
38
|
+
let resources;
|
|
39
|
+
if (changedProjectResourcePaths) {
|
|
40
|
+
resources = await Promise.all(changedProjectResourcePaths.map((resource) => workspace.byPath(resource)));
|
|
41
|
+
} else {
|
|
42
|
+
resources = await workspace.byGlob(pattern);
|
|
43
|
+
}
|
|
36
44
|
const timestamp = getTimestamp();
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return Promise.all(processedResources.map((resource) => {
|
|
50
|
-
return workspace.write(resource);
|
|
51
|
-
}));
|
|
52
|
-
});
|
|
45
|
+
const processedResources = await stringReplacer({
|
|
46
|
+
resources,
|
|
47
|
+
options: {
|
|
48
|
+
pattern: "${buildtime}",
|
|
49
|
+
replacement: timestamp
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
return Promise.all(processedResources.map((resource) => {
|
|
53
|
+
if (resource) {
|
|
54
|
+
return workspace.write(resource);
|
|
55
|
+
}
|
|
56
|
+
}));
|
|
53
57
|
}
|
|
@@ -24,32 +24,38 @@ import stringReplacer from "../processors/stringReplacer.js";
|
|
|
24
24
|
*
|
|
25
25
|
* @param {object} parameters Parameters
|
|
26
26
|
* @param {@ui5/fs/DuplexCollection} parameters.workspace DuplexCollection to read and write files
|
|
27
|
+
* @param {string[]} [parameters.changedProjectResourcePaths] Set of changed resource paths within the project.
|
|
28
|
+
* This is only set if a cache is used and changes have been detected.
|
|
27
29
|
* @param {object} parameters.options Options
|
|
28
30
|
* @param {string} parameters.options.copyright Replacement copyright
|
|
29
31
|
* @param {string} parameters.options.pattern Pattern to locate the files to be processed
|
|
30
32
|
* @returns {Promise<undefined>} Promise resolving with <code>undefined</code> once data has been written
|
|
31
33
|
*/
|
|
32
|
-
export default function({workspace, options: {copyright, pattern}}) {
|
|
34
|
+
export default async function({workspace, changedProjectResourcePaths, options: {copyright, pattern}}) {
|
|
33
35
|
if (!copyright) {
|
|
34
|
-
return
|
|
36
|
+
return;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
// Replace optional placeholder ${currentYear} with the current year
|
|
38
40
|
copyright = copyright.replace(/(?:\$\{currentYear\})/, new Date().getFullYear());
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
42
|
+
let resources;
|
|
43
|
+
if (changedProjectResourcePaths) {
|
|
44
|
+
resources = await Promise.all(changedProjectResourcePaths.map((resource) => workspace.byPath(resource)));
|
|
45
|
+
} else {
|
|
46
|
+
resources = await workspace.byGlob(pattern);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const processedResources = await stringReplacer({
|
|
50
|
+
resources,
|
|
51
|
+
options: {
|
|
52
|
+
pattern: /(?:\$\{copyright\}|@copyright@)/g,
|
|
53
|
+
replacement: copyright
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
return Promise.all(processedResources.map((resource) => {
|
|
57
|
+
if (resource) {
|
|
58
|
+
return workspace.write(resource);
|
|
59
|
+
}
|
|
60
|
+
}));
|
|
55
61
|
}
|
|
@@ -14,25 +14,30 @@ import stringReplacer from "../processors/stringReplacer.js";
|
|
|
14
14
|
*
|
|
15
15
|
* @param {object} parameters Parameters
|
|
16
16
|
* @param {@ui5/fs/DuplexCollection} parameters.workspace DuplexCollection to read and write files
|
|
17
|
+
* @param {string[]} [parameters.changedProjectResourcePaths] Set of changed resource paths within the project.
|
|
18
|
+
* This is only set if a cache is used and changes have been detected.
|
|
17
19
|
* @param {object} parameters.options Options
|
|
18
20
|
* @param {string} parameters.options.pattern Pattern to locate the files to be processed
|
|
19
21
|
* @param {string} parameters.options.version Replacement version
|
|
20
22
|
* @returns {Promise<undefined>} Promise resolving with <code>undefined</code> once data has been written
|
|
21
23
|
*/
|
|
22
|
-
export default function({workspace, options: {pattern, version}}) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
24
|
+
export default async function({workspace, changedProjectResourcePaths, options: {pattern, version}}) {
|
|
25
|
+
let resources;
|
|
26
|
+
if (changedProjectResourcePaths) {
|
|
27
|
+
resources = await Promise.all(changedProjectResourcePaths.map((resource) => workspace.byPath(resource)));
|
|
28
|
+
} else {
|
|
29
|
+
resources = await workspace.byGlob(pattern);
|
|
30
|
+
}
|
|
31
|
+
const processedResources = await stringReplacer({
|
|
32
|
+
resources,
|
|
33
|
+
options: {
|
|
34
|
+
pattern: /\$\{(?:project\.)?version\}/g,
|
|
35
|
+
replacement: version
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
await Promise.all(processedResources.map((resource) => {
|
|
39
|
+
if (resource) {
|
|
40
|
+
return workspace.write(resource);
|
|
41
|
+
}
|
|
42
|
+
}));
|
|
38
43
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ui5/builder",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.5",
|
|
4
4
|
"description": "UI5 CLI - Builder",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "SAP SE",
|
|
@@ -91,32 +91,32 @@
|
|
|
91
91
|
},
|
|
92
92
|
"dependencies": {
|
|
93
93
|
"@jridgewell/sourcemap-codec": "^1.5.5",
|
|
94
|
-
"@ui5/fs": "^5.0.0-alpha.
|
|
95
|
-
"@ui5/logger": "^5.0.0-alpha.
|
|
94
|
+
"@ui5/fs": "^5.0.0-alpha.5",
|
|
95
|
+
"@ui5/logger": "^5.0.0-alpha.5",
|
|
96
96
|
"cheerio": "1.0.0",
|
|
97
97
|
"escape-unicode": "^0.3.0",
|
|
98
98
|
"escope": "^4.0.0",
|
|
99
|
-
"espree": "^
|
|
99
|
+
"espree": "^11.2.0",
|
|
100
100
|
"graceful-fs": "^4.2.11",
|
|
101
|
-
"jsdoc": "^4.0.
|
|
101
|
+
"jsdoc": "^4.0.5",
|
|
102
102
|
"less-openui5": "^0.11.6",
|
|
103
103
|
"pretty-data": "^0.40.0",
|
|
104
|
-
"semver": "^7.
|
|
105
|
-
"terser": "^5.
|
|
106
|
-
"workerpool": "^10.0.
|
|
104
|
+
"semver": "^7.8.5",
|
|
105
|
+
"terser": "^5.48.0",
|
|
106
|
+
"workerpool": "^10.0.2",
|
|
107
107
|
"xml2js": "^0.6.2"
|
|
108
108
|
},
|
|
109
109
|
"devDependencies": {
|
|
110
110
|
"@istanbuljs/esm-loader-hook": "^0.3.0",
|
|
111
111
|
"@jridgewell/trace-mapping": "^0.3.31",
|
|
112
|
-
"@ui5/project": "^5.0.0-alpha.
|
|
112
|
+
"@ui5/project": "^5.0.0-alpha.5",
|
|
113
113
|
"ava": "^6.4.1",
|
|
114
|
-
"cross-env": "^
|
|
115
|
-
"eslint": "^
|
|
116
|
-
"esmock": "^2.7.
|
|
114
|
+
"cross-env": "^10.1.0",
|
|
115
|
+
"eslint": "^10.5.0",
|
|
116
|
+
"esmock": "^2.7.6",
|
|
117
117
|
"line-column": "^1.0.2",
|
|
118
|
-
"nyc": "^
|
|
119
|
-
"rimraf": "^6.
|
|
120
|
-
"sinon": "^21.
|
|
118
|
+
"nyc": "^18.0.0",
|
|
119
|
+
"rimraf": "^6.1.3",
|
|
120
|
+
"sinon": "^21.1.2"
|
|
121
121
|
}
|
|
122
122
|
}
|