@ui5/builder 4.1.4 → 4.1.6
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 +14 -1
- package/lib/lbt/bundle/Builder.js +3 -2
- package/lib/lbt/bundle/ResolvedBundleDefinition.js +1 -0
- package/lib/lbt/bundle/Resolver.js +11 -0
- package/lib/lbt/resources/ModuleInfo.js +2 -1
- package/lib/lbt/resources/ResourcePool.js +5 -2
- package/lib/processors/jsdoc/lib/transformApiJson.js +95 -22
- package/lib/processors/jsdoc/lib/ui5/plugin.js +64 -10
- package/lib/processors/jsdoc/lib/ui5/template/publish.js +28 -0
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,18 @@
|
|
|
2
2
|
All notable changes to this project will be documented in this file.
|
|
3
3
|
This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
4
4
|
|
|
5
|
-
A list of unreleased changes can be found [here](https://github.com/SAP/ui5-builder/compare/v4.1.
|
|
5
|
+
A list of unreleased changes can be found [here](https://github.com/SAP/ui5-builder/compare/v4.1.6...HEAD).
|
|
6
|
+
|
|
7
|
+
<a name="v4.1.6"></a>
|
|
8
|
+
## [v4.1.6] - 2026-04-08
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
- **Bundler:** Also detect import.meta as ESM indicator [`58013d5`](https://github.com/SAP/ui5-builder/commit/58013d5a75e3fbf245b0042fb0b81f4e729a7a55)
|
|
11
|
+
- **Bundler:** Skip ESM modules during bundling and log errors [`d28f63a`](https://github.com/SAP/ui5-builder/commit/d28f63a6ace823d9fcfac23312c09e66be6fb7d4)
|
|
12
|
+
- **Bundler:** Reduce noise from ESM parse errors [`bd574bb`](https://github.com/SAP/ui5-builder/commit/bd574bb231cc4e5f1af0b12c12c3365dee5eb80d)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
<a name="v4.1.5"></a>
|
|
16
|
+
## [v4.1.5] - 2026-03-25
|
|
6
17
|
|
|
7
18
|
<a name="v4.1.4"></a>
|
|
8
19
|
## [v4.1.4] - 2026-02-16
|
|
@@ -1016,6 +1027,8 @@ to load the custom bundle file instead.
|
|
|
1016
1027
|
|
|
1017
1028
|
### Features
|
|
1018
1029
|
- Add ability to configure component preloads and custom bundles [`2241e5f`](https://github.com/SAP/ui5-builder/commit/2241e5ff98fd95f1f80cc74959655ae7a9c660e7)
|
|
1030
|
+
[v4.1.6]: https://github.com/SAP/ui5-builder/compare/v4.1.5...v4.1.6
|
|
1031
|
+
[v4.1.5]: https://github.com/SAP/ui5-builder/compare/v4.1.4...v4.1.5
|
|
1019
1032
|
[v4.1.4]: https://github.com/SAP/ui5-builder/compare/v4.1.3...v4.1.4
|
|
1020
1033
|
[v4.1.3]: https://github.com/SAP/ui5-builder/compare/v4.1.2...v4.1.3
|
|
1021
1034
|
[v4.1.2]: https://github.com/SAP/ui5-builder/compare/v4.1.1...v4.1.2
|
|
@@ -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) => {
|
|
@@ -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
|
-
|
|
@@ -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
|
}
|
|
@@ -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
|
/*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ui5/builder",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.6",
|
|
4
4
|
"description": "UI5 CLI - Builder",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "SAP SE",
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
"less-openui5": "^0.11.6",
|
|
135
135
|
"pretty-data": "^0.40.0",
|
|
136
136
|
"semver": "^7.7.4",
|
|
137
|
-
"terser": "^5.46.
|
|
137
|
+
"terser": "^5.46.1",
|
|
138
138
|
"workerpool": "^9.3.4",
|
|
139
139
|
"xml2js": "^0.6.2"
|
|
140
140
|
},
|
|
@@ -142,23 +142,23 @@
|
|
|
142
142
|
"@eslint/js": "^9.14.0",
|
|
143
143
|
"@istanbuljs/esm-loader-hook": "^0.3.0",
|
|
144
144
|
"@jridgewell/trace-mapping": "^0.3.31",
|
|
145
|
-
"@ui5/project": "^4.0.
|
|
145
|
+
"@ui5/project": "^4.0.15",
|
|
146
146
|
"ava": "^6.4.1",
|
|
147
147
|
"chokidar-cli": "^3.0.0",
|
|
148
148
|
"cross-env": "^10.1.0",
|
|
149
149
|
"docdash": "^2.0.2",
|
|
150
|
-
"eslint": "^9.39.
|
|
150
|
+
"eslint": "^9.39.4",
|
|
151
151
|
"eslint-config-google": "^0.14.0",
|
|
152
152
|
"eslint-plugin-ava": "^15.1.0",
|
|
153
153
|
"eslint-plugin-jsdoc": "61.5.0",
|
|
154
154
|
"esmock": "^2.7.3",
|
|
155
155
|
"globals": "^16.5.0",
|
|
156
|
-
"knip": "^5.
|
|
156
|
+
"knip": "^5.88.1",
|
|
157
157
|
"line-column": "^1.0.2",
|
|
158
158
|
"nyc": "^17.1.0",
|
|
159
159
|
"open-cli": "^8.0.0",
|
|
160
160
|
"rimraf": "^6.1.3",
|
|
161
|
-
"sinon": "^21.
|
|
161
|
+
"sinon": "^21.1.2",
|
|
162
162
|
"tap-xunit": "^2.4.1"
|
|
163
163
|
}
|
|
164
164
|
}
|