@ui5/builder 3.0.0-beta.1 → 3.0.0-beta.3
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 +25 -1
- package/lib/lbt/analyzer/JSModuleAnalyzer.js +12 -12
- package/lib/lbt/resources/LibraryFileAnalyzer.js +1 -1
- package/lib/lbt/resources/ModuleInfo.js +1 -1
- package/lib/lbt/resources/ResourceCollector.js +1 -1
- package/lib/lbt/utils/ASTUtils.js +2 -0
- package/lib/lbt/utils/escapePropertiesFile.js +1 -1
- package/lib/lbt/utils/parseUtils.js +1 -1
- package/lib/processors/jsdoc/jsdocGenerator.js +6 -8
- package/lib/processors/jsdoc/lib/transformApiJson.cjs +5 -4
- package/lib/processors/jsdoc/lib/ui5/plugin.cjs +317 -44
- package/lib/processors/jsdoc/lib/ui5/template/publish.cjs +5 -1
- package/lib/processors/libraryLessGenerator.js +1 -1
- package/lib/processors/manifestCreator.js +1 -1
- package/lib/processors/nonAsciiEscaper.js +1 -1
- package/lib/processors/versionInfoGenerator.js +7 -7
- package/lib/tasks/bundlers/generateBundle.js +5 -2
- package/lib/tasks/bundlers/generateComponentPreload.js +6 -3
- package/lib/tasks/bundlers/generateLibraryPreload.js +13 -7
- package/lib/tasks/bundlers/utils/createModuleNameMapping.js +1 -1
- package/lib/tasks/generateCachebusterInfo.js +1 -1
- package/lib/tasks/taskRepository.js +1 -2
- package/package.json +19 -21
- package/lib/processors/bundlers/manifestBundler.js +0 -181
- package/lib/tasks/bundlers/generateManifestBundle.js +0 -58
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,29 @@
|
|
|
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-beta.
|
|
5
|
+
A list of unreleased changes can be found [here](https://github.com/SAP/ui5-builder/compare/v3.0.0-beta.3...HEAD).
|
|
6
|
+
|
|
7
|
+
<a name="v3.0.0-beta.3"></a>
|
|
8
|
+
## [v3.0.0-beta.3] - 2022-11-29
|
|
9
|
+
### Features
|
|
10
|
+
- **jsdoc:** Support destructuring of enums for defaultValue ([#775](https://github.com/SAP/ui5-builder/issues/775)) [`523f365`](https://github.com/SAP/ui5-builder/commit/523f365cb917997c5031d245309c21e9e4b3e311)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
<a name="v3.0.0-beta.2"></a>
|
|
14
|
+
## [v3.0.0-beta.2] - 2022-11-29
|
|
15
|
+
### Breaking Changes
|
|
16
|
+
- Removal of manifestBundler and generateManifestBundle ([#838](https://github.com/SAP/ui5-builder/issues/838)) [`07a5be2`](https://github.com/SAP/ui5-builder/commit/07a5be2b6d9aa23cf78ddd17951c832d6dec7bef)
|
|
17
|
+
- **JSDoc:** Fail build when jsdoc command failed ([#845](https://github.com/SAP/ui5-builder/issues/845)) [`c2916b4`](https://github.com/SAP/ui5-builder/commit/c2916b4f1d49b5500e4b51143d4e6065ac200eef)
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
- Support ES2022 language features ([#848](https://github.com/SAP/ui5-builder/issues/848)) [`f9b8457`](https://github.com/SAP/ui5-builder/commit/f9b845726731a0e02ec4a499e2a1a82a639174a8)
|
|
21
|
+
|
|
22
|
+
### BREAKING CHANGE
|
|
23
|
+
|
|
24
|
+
The `jsdocGenerator` processor and the corresponding `generateJsdoc` task will now throw an error when JSDoc reports an error (exit code != 0). This will also fail the build when running `ui5 build jsdoc`.
|
|
25
|
+
|
|
26
|
+
The manifestBundler processor and generateManifestBundle task has been removed because it is no longer required for the HTML5 repository in Cloud Foundry.
|
|
27
|
+
|
|
6
28
|
|
|
7
29
|
<a name="v3.0.0-beta.1"></a>
|
|
8
30
|
## [v3.0.0-beta.1] - 2022-11-07
|
|
@@ -787,6 +809,8 @@ to load the custom bundle file instead.
|
|
|
787
809
|
- Add ability to configure component preloads and custom bundles [`2241e5f`](https://github.com/SAP/ui5-builder/commit/2241e5ff98fd95f1f80cc74959655ae7a9c660e7)
|
|
788
810
|
|
|
789
811
|
|
|
812
|
+
[v3.0.0-beta.3]: https://github.com/SAP/ui5-builder/compare/v3.0.0-beta.2...v3.0.0-beta.3
|
|
813
|
+
[v3.0.0-beta.2]: https://github.com/SAP/ui5-builder/compare/v3.0.0-beta.1...v3.0.0-beta.2
|
|
790
814
|
[v3.0.0-beta.1]: https://github.com/SAP/ui5-builder/compare/v3.0.0-alpha.12...v3.0.0-beta.1
|
|
791
815
|
[v3.0.0-alpha.12]: https://github.com/SAP/ui5-builder/compare/v3.0.0-alpha.11...v3.0.0-alpha.12
|
|
792
816
|
[v3.0.0-alpha.11]: https://github.com/SAP/ui5-builder/compare/v3.0.0-alpha.10...v3.0.0-alpha.11
|
|
@@ -135,10 +135,10 @@ const EnrichedVisitorKeys = (function() {
|
|
|
135
135
|
* All properties in an object pattern are executed.
|
|
136
136
|
*/
|
|
137
137
|
ObjectPattern: [], // properties
|
|
138
|
-
|
|
138
|
+
PrivateIdentifier: [],
|
|
139
139
|
Program: [],
|
|
140
140
|
Property: [],
|
|
141
|
-
|
|
141
|
+
PropertyDefinition: [],
|
|
142
142
|
/*
|
|
143
143
|
* argument of the rest element is always executed under the same condition as the rest element itself
|
|
144
144
|
*/
|
|
@@ -146,7 +146,7 @@ const EnrichedVisitorKeys = (function() {
|
|
|
146
146
|
ReturnStatement: [],
|
|
147
147
|
SequenceExpression: [],
|
|
148
148
|
SpreadElement: [], // the argument of the spread operator always needs to be evaluated - argument
|
|
149
|
-
|
|
149
|
+
StaticBlock: [],
|
|
150
150
|
Super: [],
|
|
151
151
|
SwitchStatement: [],
|
|
152
152
|
SwitchCase: ["test", "consequent"], // test and consequent are executed only conditionally
|
|
@@ -196,15 +196,6 @@ const EnrichedVisitorKeys = (function() {
|
|
|
196
196
|
return;
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
-
// Ignore new ES2022 syntax as we currently use ES2021 (see parseUtils.js)
|
|
200
|
-
if (
|
|
201
|
-
type === "PrivateIdentifier" ||
|
|
202
|
-
type === "PropertyDefinition" ||
|
|
203
|
-
type === "StaticBlock"
|
|
204
|
-
) {
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
199
|
const visitorKeys = VisitorKeys[type];
|
|
209
200
|
const condKeys = TempKeys[type];
|
|
210
201
|
if ( condKeys === undefined ) {
|
|
@@ -535,6 +526,15 @@ class JSModuleAnalyzer {
|
|
|
535
526
|
}
|
|
536
527
|
break;
|
|
537
528
|
|
|
529
|
+
case Syntax.PropertyDefinition:
|
|
530
|
+
|
|
531
|
+
// Instance properties (static=false) are only initialized when an instance is created (conditional)
|
|
532
|
+
// but a computed key is always evaluated on class initialization (eager)
|
|
533
|
+
visit(node.key, conditional);
|
|
534
|
+
visit(node.value, !node.static || conditional);
|
|
535
|
+
|
|
536
|
+
break;
|
|
537
|
+
|
|
538
538
|
default:
|
|
539
539
|
if ( condKeys == null ) {
|
|
540
540
|
log.error("Unhandled AST node type " + node.type, node);
|
|
@@ -66,7 +66,7 @@ class ResourceCollector {
|
|
|
66
66
|
*
|
|
67
67
|
* If no component is given, orphans will only be reported but not added to any component (default).
|
|
68
68
|
*
|
|
69
|
-
* @param {
|
|
69
|
+
* @param {Object<string, string[]>} list component to list of components
|
|
70
70
|
*/
|
|
71
71
|
setExternalResources(list) {
|
|
72
72
|
this._externalResources = list;
|
|
@@ -56,6 +56,8 @@ export function isMethodCall(node, methodPath) {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
export function isNamedObject(node, objectPath, length) {
|
|
59
|
+
// TODO: Support PrivateIdentifier (foo.#bar)
|
|
60
|
+
|
|
59
61
|
// console.log("checking for named object ", node, objectPath, length);
|
|
60
62
|
while ( length > 1 &&
|
|
61
63
|
node.type === Syntax.MemberExpression &&
|
|
@@ -15,7 +15,7 @@ export default async function(resource) {
|
|
|
15
15
|
let propertiesFileSourceEncoding = project && project.getPropertiesFileSourceEncoding();
|
|
16
16
|
|
|
17
17
|
if (!propertiesFileSourceEncoding) {
|
|
18
|
-
if (project &&
|
|
18
|
+
if (project && project.getSpecVersion().lte("1.1")) {
|
|
19
19
|
// default encoding to "ISO-8859-1" for old specVersions
|
|
20
20
|
propertiesFileSourceEncoding = "ISO-8859-1";
|
|
21
21
|
} else {
|
|
@@ -7,7 +7,7 @@ export function parseJS(code, userOptions = {}) {
|
|
|
7
7
|
// allowed options and their defaults
|
|
8
8
|
const options = {
|
|
9
9
|
comment: false,
|
|
10
|
-
ecmaVersion:
|
|
10
|
+
ecmaVersion: 2022, // NOTE: Adopt JSModuleAnalyzer.js to allow new Syntax when upgrading to newer ECMA versions
|
|
11
11
|
range: false,
|
|
12
12
|
sourceType: "script",
|
|
13
13
|
};
|
|
@@ -170,18 +170,16 @@ async function buildJsdoc({sourcePath, configPath}) {
|
|
|
170
170
|
"--verbose",
|
|
171
171
|
sourcePath
|
|
172
172
|
];
|
|
173
|
-
|
|
173
|
+
const exitCode = await new Promise((resolve /* , reject */) => {
|
|
174
174
|
const child = spawn("node", args, {
|
|
175
175
|
stdio: ["ignore", "ignore", "inherit"]
|
|
176
176
|
});
|
|
177
|
-
child.on("close",
|
|
178
|
-
if (code === 0 || code === 1) {
|
|
179
|
-
resolve();
|
|
180
|
-
} else {
|
|
181
|
-
reject(new Error(`JSDoc child process closed with code ${code}`));
|
|
182
|
-
}
|
|
183
|
-
});
|
|
177
|
+
child.on("close", resolve);
|
|
184
178
|
});
|
|
179
|
+
|
|
180
|
+
if (exitCode !== 0) {
|
|
181
|
+
throw new Error(`JSDoc reported an error, check the log for issues (exit code: ${exitCode})`);
|
|
182
|
+
}
|
|
185
183
|
}
|
|
186
184
|
|
|
187
185
|
jsdocGenerator._generateJsdocConfig = generateJsdocConfig;
|
|
@@ -989,11 +989,12 @@ function transformer(sInputFile, sOutputFile, sLibraryFile, vDependencyAPIFiles,
|
|
|
989
989
|
const {sources} = options;
|
|
990
990
|
let {librarySrcDir, libraryTestDir} = options;
|
|
991
991
|
|
|
992
|
-
// Using path.join to normalize POSIX paths to Windows paths on Windows
|
|
993
|
-
librarySrcDir = path.join(librarySrcDir);
|
|
994
|
-
libraryTestDir = path.join(libraryTestDir);
|
|
995
|
-
|
|
996
992
|
if (Array.isArray(sources) && typeof librarySrcDir === "string" && typeof libraryTestDir === "string") {
|
|
993
|
+
|
|
994
|
+
// Using path.join to normalize POSIX paths to Windows paths on Windows
|
|
995
|
+
librarySrcDir = path.join(librarySrcDir);
|
|
996
|
+
libraryTestDir = path.join(libraryTestDir);
|
|
997
|
+
|
|
997
998
|
/**
|
|
998
999
|
* Calculate prefix to check
|
|
999
1000
|
*
|
|
@@ -66,6 +66,7 @@ const fs = require('jsdoc/fs');
|
|
|
66
66
|
const path = require('jsdoc/path');
|
|
67
67
|
const logger = require('jsdoc/util/logger');
|
|
68
68
|
const pluginConfig = (env.conf && env.conf.templates && env.conf.templates.ui5) || env.opts.sapui5 || {};
|
|
69
|
+
const escope = require("escope");
|
|
69
70
|
|
|
70
71
|
/* ---- logging ---- */
|
|
71
72
|
|
|
@@ -115,6 +116,9 @@ let docletUid = 0;
|
|
|
115
116
|
|
|
116
117
|
let currentProgram;
|
|
117
118
|
|
|
119
|
+
// Scope Manager
|
|
120
|
+
let scopeManager;
|
|
121
|
+
|
|
118
122
|
/**
|
|
119
123
|
* Information about the current module.
|
|
120
124
|
*
|
|
@@ -255,25 +259,33 @@ function analyzeModuleDefinition(node) {
|
|
|
255
259
|
currentModule.dependencies = convertValue(args[arg], "string[]");
|
|
256
260
|
arg++;
|
|
257
261
|
}
|
|
258
|
-
if ( arg < args.length &&
|
|
262
|
+
if ( arg < args.length &&
|
|
259
263
|
[Syntax.FunctionExpression, Syntax.ArrowFunctionExpression].includes(args[arg].type)) {
|
|
260
264
|
|
|
261
265
|
currentModule.factory = args[arg];
|
|
262
266
|
arg++;
|
|
263
267
|
}
|
|
268
|
+
|
|
264
269
|
if ( currentModule.dependencies && currentModule.factory ) {
|
|
265
270
|
for ( let i = 0; i < currentModule.dependencies.length && i < currentModule.factory.params.length; i++ ) {
|
|
266
|
-
|
|
267
|
-
(currentModule.factory.params[i].type === Syntax.ObjectPattern)
|
|
268
|
-
? currentModule.factory.params[i].properties[0].value.name // ObjectPattern means destructuring of the parameter
|
|
269
|
-
: currentModule.factory.params[i].name; // simple Identifier
|
|
271
|
+
let names = [];
|
|
270
272
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
273
|
+
if ( [Syntax.ObjectPattern, Syntax.ArrayPattern].includes(currentModule.factory.params[i].type) ) { // ObjectPattern/ArrayPattern means destructuring of the parameter of a function
|
|
274
|
+
names = resolveObjectPatternChain(currentModule.factory.params[i], null, []);
|
|
275
|
+
|
|
276
|
+
} else if (currentModule.factory.params[i].type === Syntax.Identifier) { // simple Identifier
|
|
277
|
+
names = [{original: currentModule.factory.params[i].name}];
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
names.forEach(name => {
|
|
281
|
+
const module = resolveModuleName(currentModule.module, currentModule.dependencies[i]);
|
|
282
|
+
debug(` import ${name.renamed || name.original} from '${module}'`);
|
|
283
|
+
|
|
284
|
+
currentModule.localNames[name.renamed || name.original] = {
|
|
285
|
+
module: module,
|
|
286
|
+
...(name.path ? {path: name.path} : {})
|
|
287
|
+
};
|
|
288
|
+
});
|
|
277
289
|
}
|
|
278
290
|
}
|
|
279
291
|
if ( currentModule.factory ) {
|
|
@@ -460,7 +472,7 @@ function createPropertyMap(node, defaultKey) {
|
|
|
460
472
|
|
|
461
473
|
/**
|
|
462
474
|
* Resolves potential wrapper expressions like: ChainExpression, AwaitExpression, etc.
|
|
463
|
-
* @param {Node} node
|
|
475
|
+
* @param {Node} node
|
|
464
476
|
* @returns {Node} the resolved node
|
|
465
477
|
*/
|
|
466
478
|
function resolvePotentialWrapperExpression(node) {
|
|
@@ -484,9 +496,9 @@ function resolvePotentialWrapperExpression(node) {
|
|
|
484
496
|
|
|
485
497
|
/**
|
|
486
498
|
* Strips the ChainExpression wrapper if such
|
|
487
|
-
*
|
|
488
|
-
* @param {Node} rootNode
|
|
489
|
-
* @param {String} path
|
|
499
|
+
*
|
|
500
|
+
* @param {Node} rootNode
|
|
501
|
+
* @param {String} path
|
|
490
502
|
* @returns {Node}
|
|
491
503
|
*/
|
|
492
504
|
function stripChainWrappers(rootNode, path) {
|
|
@@ -507,16 +519,17 @@ function stripChainWrappers(rootNode, path) {
|
|
|
507
519
|
|
|
508
520
|
function isTemplateLiteralWithoutExpression(node) {
|
|
509
521
|
return (
|
|
510
|
-
node
|
|
511
|
-
node
|
|
512
|
-
node
|
|
522
|
+
node &&
|
|
523
|
+
node.type === Syntax.TemplateLiteral &&
|
|
524
|
+
node.expressions && node.expressions.length === 0 &&
|
|
525
|
+
node.quasis && node.quasis.length === 1
|
|
513
526
|
);
|
|
514
527
|
}
|
|
515
528
|
|
|
516
529
|
/**
|
|
517
530
|
* Checks whether a node is Literal or TemplateLiteral without an expression
|
|
518
|
-
*
|
|
519
|
-
* @param {Node} node
|
|
531
|
+
*
|
|
532
|
+
* @param {Node} node
|
|
520
533
|
* @returns {String}
|
|
521
534
|
*/
|
|
522
535
|
function isStringLiteral(node) {
|
|
@@ -563,8 +576,8 @@ function isArrowFuncExpression(node) {
|
|
|
563
576
|
|
|
564
577
|
/**
|
|
565
578
|
* Checks whether the node is of a "returning" type
|
|
566
|
-
*
|
|
567
|
-
* @param {Node} node
|
|
579
|
+
*
|
|
580
|
+
* @param {Node} node
|
|
568
581
|
* @returns {Boolean}
|
|
569
582
|
*/
|
|
570
583
|
function isReturningNode(node) {
|
|
@@ -642,6 +655,254 @@ function isPotentialEnum(node) {
|
|
|
642
655
|
return node.properties.every((prop) => isCompileTimeConstant(prop.value));
|
|
643
656
|
}
|
|
644
657
|
|
|
658
|
+
// ---- ES6+ Destructuring ---------------------------------------------------------
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* Resolves (nested) Object/ArrayPattern nodes and builds a "path"
|
|
662
|
+
*
|
|
663
|
+
* @param {Node} valueNode
|
|
664
|
+
* @param {Node} keyNode
|
|
665
|
+
* @param {Array<String>} keyChain
|
|
666
|
+
* @returns Array<Object<Node, Node, Array<String>>>
|
|
667
|
+
*/
|
|
668
|
+
function resolveObjectPatternChain (valueNode, keyNode, keyChain) {
|
|
669
|
+
let chainSequence = [];
|
|
670
|
+
|
|
671
|
+
if (valueNode && valueNode.type === Syntax.ObjectPattern) {
|
|
672
|
+
for (let i = 0; i < valueNode.properties.length; i++) {
|
|
673
|
+
chainSequence = chainSequence.concat(
|
|
674
|
+
resolveObjectPatternChain(
|
|
675
|
+
valueNode.properties[i].value,
|
|
676
|
+
valueNode.properties[i].key,
|
|
677
|
+
[...keyChain, valueNode.properties[i].key.name] )
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
} else if (valueNode && valueNode.type === Syntax.ArrayPattern) {
|
|
681
|
+
for (let i = 0; i < valueNode.elements.length; i++) {
|
|
682
|
+
chainSequence = chainSequence.concat(
|
|
683
|
+
resolveObjectPatternChain(
|
|
684
|
+
valueNode.elements[i],
|
|
685
|
+
valueNode.elements[i],
|
|
686
|
+
[...keyChain, String(i)]
|
|
687
|
+
)
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
} else {
|
|
691
|
+
|
|
692
|
+
let result = { original: keyNode.name, path: keyChain.join(".") };
|
|
693
|
+
|
|
694
|
+
if (keyNode.name !== valueNode.name) {
|
|
695
|
+
// Renaming
|
|
696
|
+
result.renamed = valueNode.name;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
chainSequence.push(result);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
return chainSequence;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Tries to resolve an ENUM, regardless where it is defined and being destructured.
|
|
707
|
+
*
|
|
708
|
+
* @param {Node} node
|
|
709
|
+
* @param {String} type
|
|
710
|
+
* @returns {Object}
|
|
711
|
+
*/
|
|
712
|
+
function resolvePotentialEnum(node, type) {
|
|
713
|
+
let value = resolveFullyQuantifiedName(node);
|
|
714
|
+
|
|
715
|
+
if ( value.startsWith(type + ".") ) {
|
|
716
|
+
// starts with fully qualified enum name -> cut off name
|
|
717
|
+
value = value.slice(type.length + 1);
|
|
718
|
+
return {
|
|
719
|
+
value: value,
|
|
720
|
+
raw: value
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Returns the {Node} of the destructured argument of a (arrow) function.
|
|
727
|
+
*
|
|
728
|
+
* @param {Definition|ParameterDefinition} varDefinition
|
|
729
|
+
* @returns {Node}
|
|
730
|
+
*/
|
|
731
|
+
function getFuncArgumentDestructNode(varDefinition) {
|
|
732
|
+
if (
|
|
733
|
+
[
|
|
734
|
+
Syntax.ArrowFunctionExpression,
|
|
735
|
+
Syntax.FunctionDeclaration,
|
|
736
|
+
Syntax.FunctionExpression,
|
|
737
|
+
].includes(varDefinition.node.type)
|
|
738
|
+
) {
|
|
739
|
+
return varDefinition.node.params[varDefinition.index];
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// return undefined;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
* Checks whether a variable has been destructured.
|
|
747
|
+
*
|
|
748
|
+
* @param {Variable} variable
|
|
749
|
+
* @returns
|
|
750
|
+
*/
|
|
751
|
+
function isVarDestructuring(variable) {
|
|
752
|
+
const defNode =
|
|
753
|
+
variable &&
|
|
754
|
+
variable.defs &&
|
|
755
|
+
( getFuncArgumentDestructNode(variable.defs[0]) // (arrow) function argument
|
|
756
|
+
|| variable.defs[0].node.id ); // variable definition
|
|
757
|
+
|
|
758
|
+
return defNode && [Syntax.ObjectPattern, Syntax.ArrayPattern].includes( defNode.type );
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* Checks whether a var has been renamed while destructuring i.e. {A: b} = SomeObject
|
|
763
|
+
*
|
|
764
|
+
* @param {Variable} variable
|
|
765
|
+
* @returns {Object}
|
|
766
|
+
*/
|
|
767
|
+
function checkVarRenaming(variable) {
|
|
768
|
+
// variable.defs[0].node.id.type === Syntax.ObjectPattern -> Renaming
|
|
769
|
+
// variable.defs[0].node.id.properties[0].key.name === variable.name; // Original
|
|
770
|
+
// variable.defs[0].node.id.properties[0].value.name === variable.name; // Renamed
|
|
771
|
+
|
|
772
|
+
// If variable.defs (Variable definitions within the source code) are more 1, then we'd not be able to
|
|
773
|
+
// determine which defintion to use. For example:
|
|
774
|
+
// function doSomething({a}, b) {
|
|
775
|
+
// console.log(a);
|
|
776
|
+
// var { c : a } = { b };
|
|
777
|
+
// console.log(a);
|
|
778
|
+
// }
|
|
779
|
+
// doSomething({a:42}, 5);
|
|
780
|
+
//
|
|
781
|
+
// So, we'd not able to analyze which "a" to which console.log to map
|
|
782
|
+
if (
|
|
783
|
+
!variable
|
|
784
|
+
|| !variable.defs
|
|
785
|
+
|| variable.defs.length !== 1
|
|
786
|
+
) {
|
|
787
|
+
return null;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
const varDefinition = variable.defs[0];
|
|
791
|
+
const defNode = getFuncArgumentDestructNode(varDefinition) // (arrow) function argument
|
|
792
|
+
|| varDefinition.node.id; // variable definition
|
|
793
|
+
|
|
794
|
+
return resolveObjectPatternChain(defNode, null, []).find(
|
|
795
|
+
({ original, renamed }) =>
|
|
796
|
+
renamed === variable.name || original === variable.name
|
|
797
|
+
);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* Builds the fully quantified name when there's a destructuring of a variable
|
|
802
|
+
*
|
|
803
|
+
* @param {Node} node
|
|
804
|
+
* @returns {string}
|
|
805
|
+
*/
|
|
806
|
+
function resolveFullyQuantifiedName(node) {
|
|
807
|
+
// The missing part is on the left side. The right side is clear.
|
|
808
|
+
// We would eiter ways resolve to the same leftmost token.
|
|
809
|
+
let leftMostName = getLeftmostName(node);
|
|
810
|
+
let originalName = getObjectName(node) || "";
|
|
811
|
+
const currentScope = getEnclosingVariableScope(node);
|
|
812
|
+
|
|
813
|
+
if (!currentScope) {
|
|
814
|
+
return "";
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
while (leftMostName) {
|
|
818
|
+
const curVar = currentScope.set.get(leftMostName);
|
|
819
|
+
|
|
820
|
+
if (!curVar) {
|
|
821
|
+
break;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
if ( !isVarDestructuring(curVar) ) {
|
|
825
|
+
// Not a destructuring
|
|
826
|
+
return getResolvedName(originalName, leftMostName);
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
const potentialRenaming = checkVarRenaming(curVar);
|
|
830
|
+
if (potentialRenaming) {
|
|
831
|
+
let renamedChunks = originalName.split(".");
|
|
832
|
+
renamedChunks = getResolvedName( originalName, renamedChunks[0] ).split(".");
|
|
833
|
+
|
|
834
|
+
// when getResolvedName() was not able to resolve the renaming of a variable
|
|
835
|
+
// with currentModule.localNames[].path i.e. in "chained" destructuring, where
|
|
836
|
+
// the variable is not within localNames registry
|
|
837
|
+
if ( potentialRenaming.renamed === renamedChunks[0] ) { // Checks for direct renaming
|
|
838
|
+
renamedChunks[0] = potentialRenaming.original;
|
|
839
|
+
}
|
|
840
|
+
// Considers the 'path' if it differs from the original name i.e. there's some namespace before it
|
|
841
|
+
if ( potentialRenaming.original === renamedChunks[0] && potentialRenaming.path !== potentialRenaming.original ) {
|
|
842
|
+
renamedChunks[0] = potentialRenaming.path;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
originalName = renamedChunks.join(".");
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
const writeExpr = curVar.references.filter((ref) => ref.writeExpr);
|
|
849
|
+
|
|
850
|
+
// The same case as variable.defs- we're not able to determine the correct chain in case of multiple writeExpr
|
|
851
|
+
if (writeExpr.length !== 1) {
|
|
852
|
+
// writeExpr.length === 0 means an function argument and then we need
|
|
853
|
+
// just to return the already build originalName
|
|
854
|
+
return writeExpr.length === 0 ? originalName : "";
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
const writeExprNode = writeExpr[0].writeExpr;
|
|
858
|
+
|
|
859
|
+
if ( writeExprNode.type === Syntax.MemberExpression && !writeExprNode.computed && writeExprNode.object.type === Syntax.Identifier ) {
|
|
860
|
+
leftMostName = writeExprNode.object.name;
|
|
861
|
+
|
|
862
|
+
} else if (writeExprNode.type === Syntax.MemberExpression && writeExprNode.object.type === Syntax.MemberExpression) { // Standalone variable without leading dot notation namespace
|
|
863
|
+
leftMostName = getResolvedObjectName(writeExprNode);
|
|
864
|
+
|
|
865
|
+
} else if (writeExprNode.type === Syntax.Identifier) {
|
|
866
|
+
leftMostName = writeExprNode.name;
|
|
867
|
+
|
|
868
|
+
} else {
|
|
869
|
+
leftMostName = "";
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
if (leftMostName) {
|
|
873
|
+
originalName = leftMostName + "." + originalName;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
return originalName;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
/**
|
|
881
|
+
* Gets enclosing scope
|
|
882
|
+
*
|
|
883
|
+
* @param {Node} node
|
|
884
|
+
* @returns {Scope}
|
|
885
|
+
*/
|
|
886
|
+
function getEnclosingVariableScope (node) {
|
|
887
|
+
// Get to the nearest upper scope
|
|
888
|
+
let nearestScopeableNode = node;
|
|
889
|
+
let nearestScope = scopeManager.acquire(nearestScopeableNode);
|
|
890
|
+
while (
|
|
891
|
+
!nearestScope &&
|
|
892
|
+
nearestScopeableNode &&
|
|
893
|
+
nearestScopeableNode.parent
|
|
894
|
+
) {
|
|
895
|
+
nearestScopeableNode = nearestScopeableNode.parent;
|
|
896
|
+
nearestScope = scopeManager.acquire(nearestScopeableNode);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
// FunctionExpression with a name hold the value of the name in its scope.
|
|
900
|
+
// So, we need to unwrap to get to the real scope with var definitions
|
|
901
|
+
return nearestScope.functionExpressionScope
|
|
902
|
+
? nearestScope.childScopes[0]
|
|
903
|
+
: nearestScope;
|
|
904
|
+
}
|
|
905
|
+
|
|
645
906
|
function isCompileTimeConstant(node) {
|
|
646
907
|
return node && node.type === Syntax.Literal;
|
|
647
908
|
}
|
|
@@ -674,6 +935,11 @@ function getLeftmostName(node) {
|
|
|
674
935
|
function getResolvedObjectName(node) {
|
|
675
936
|
const name = getObjectName(node);
|
|
676
937
|
const _import = getLeftmostName(node);
|
|
938
|
+
|
|
939
|
+
return getResolvedName(name, _import);
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
function getResolvedName(name, _import) {
|
|
677
943
|
const local = _import && currentModule.localNames[_import];
|
|
678
944
|
if ( name && local && (local.class || local.module) ) {
|
|
679
945
|
let resolvedName;
|
|
@@ -733,18 +999,12 @@ function convertValueWithRaw(node, type, propertyName) {
|
|
|
733
999
|
} else if ( isMemberExpression(node) && type ) {
|
|
734
1000
|
|
|
735
1001
|
// enum value (a.b.c)
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
return {
|
|
741
|
-
value: value,
|
|
742
|
-
raw: value
|
|
743
|
-
};
|
|
744
|
-
// } else if ( value.indexOf(type.split(".").slice(-1)[0] + ".") === 0 ) {
|
|
745
|
-
// // unqualified name might be a local name (just a guess - would need static code analysis for proper solution)
|
|
746
|
-
// return value.slice(type.split(".").slice(-1)[0].length + 1);
|
|
1002
|
+
const potentialEnum = resolvePotentialEnum(node, type);
|
|
1003
|
+
|
|
1004
|
+
if ( potentialEnum ) {
|
|
1005
|
+
return potentialEnum;
|
|
747
1006
|
} else {
|
|
1007
|
+
value = getResolvedObjectName(node);
|
|
748
1008
|
warning(`did not understand default value '${value}'${propertyName ? " of property '" + propertyName + "'" : ""}, falling back to source`);
|
|
749
1009
|
let raw = value;
|
|
750
1010
|
if ( currentSource && node.range ) {
|
|
@@ -772,6 +1032,15 @@ function convertValueWithRaw(node, type, propertyName) {
|
|
|
772
1032
|
raw: local.raw
|
|
773
1033
|
};
|
|
774
1034
|
}
|
|
1035
|
+
|
|
1036
|
+
// This could be an ENUM which has been destructured up to the enum value part. In that case the node.type === Syntax.Identifier
|
|
1037
|
+
// For example, the `Solid` const in the following snippet:
|
|
1038
|
+
// sap.ui.define(["sap/m/library"], ( { BackgroundDesign } ) => {
|
|
1039
|
+
// const { Solid } = BackgroundDesign;
|
|
1040
|
+
const potentialEnum = resolvePotentialEnum(node, type);
|
|
1041
|
+
if ( potentialEnum ) {
|
|
1042
|
+
return potentialEnum;
|
|
1043
|
+
}
|
|
775
1044
|
} else if ( node.type === Syntax.ArrayExpression ) {
|
|
776
1045
|
|
|
777
1046
|
if ( node.elements.length === 0 ) {
|
|
@@ -801,9 +1070,11 @@ function convertValueWithRaw(node, type, propertyName) {
|
|
|
801
1070
|
}
|
|
802
1071
|
|
|
803
1072
|
} else if ( isTemplateLiteralWithoutExpression(node) ) {
|
|
1073
|
+
let value = node.quasis[0].value || {};
|
|
1074
|
+
|
|
804
1075
|
return {
|
|
805
|
-
value:
|
|
806
|
-
raw:
|
|
1076
|
+
value: value.cooked,
|
|
1077
|
+
raw: value.raw,
|
|
807
1078
|
};
|
|
808
1079
|
}
|
|
809
1080
|
|
|
@@ -1229,16 +1500,16 @@ function determineValueRange(expression, varname, inverse) {
|
|
|
1229
1500
|
&& expression.left.type === Syntax.BinaryExpression
|
|
1230
1501
|
&& expression.right.type === Syntax.BinaryExpression ) {
|
|
1231
1502
|
|
|
1232
|
-
if ( expression.operator === "&&"
|
|
1233
|
-
&& determineValueRangeBorder(range, expression.left, varname, inverse)
|
|
1503
|
+
if ( expression.operator === "&&"
|
|
1504
|
+
&& determineValueRangeBorder(range, expression.left, varname, inverse)
|
|
1234
1505
|
&& determineValueRangeBorder(range, expression.right, varname, inverse) ) {
|
|
1235
1506
|
return range;
|
|
1236
1507
|
} else if ( ["||", "??"].includes(expression.operator)
|
|
1237
|
-
&& ( determineValueRangeBorder(range, expression.left, varname, inverse)
|
|
1508
|
+
&& ( determineValueRangeBorder(range, expression.left, varname, inverse)
|
|
1238
1509
|
|| determineValueRangeBorder(range, expression.right, varname, inverse) )) {
|
|
1239
1510
|
return range;
|
|
1240
1511
|
}
|
|
1241
|
-
|
|
1512
|
+
|
|
1242
1513
|
} else if ( expression.type === Syntax.BinaryExpression
|
|
1243
1514
|
&& determineValueRangeBorder(range, expression, varname, inverse) ) {
|
|
1244
1515
|
return range;
|
|
@@ -2495,6 +2766,7 @@ exports.handlers = {
|
|
|
2495
2766
|
e.doclet.meta.__shortpath = getRelativePath(filepath);
|
|
2496
2767
|
_ui5data.resource = currentModule.resource;
|
|
2497
2768
|
_ui5data.module = currentModule.name || currentModule.module;
|
|
2769
|
+
_ui5data.initialLongname = e.doclet.longname;
|
|
2498
2770
|
|
|
2499
2771
|
const localDecl = findLocalDeclaration(e.doclet.meta.lineno, e.doclet.meta.columnno);
|
|
2500
2772
|
if ( localDecl ) {
|
|
@@ -2694,6 +2966,7 @@ exports.astNodeVisitor = {
|
|
|
2694
2966
|
|
|
2695
2967
|
if ( node.type === Syntax.Program ) {
|
|
2696
2968
|
currentProgram = node;
|
|
2969
|
+
scopeManager = escope.analyze(currentProgram);
|
|
2697
2970
|
}
|
|
2698
2971
|
|
|
2699
2972
|
function processExtendCall(extendCall, comment, commentAlreadyProcessed) {
|
|
@@ -2855,7 +3128,7 @@ exports.astNodeVisitor = {
|
|
|
2855
3128
|
* to retain the full record type structure.
|
|
2856
3129
|
*
|
|
2857
3130
|
* JSDoc is copyright (c) 2011-present Michael Mathews micmath@gmail.com and the contributors to JSDoc.
|
|
2858
|
-
*/
|
|
3131
|
+
*/
|
|
2859
3132
|
function getTypeStrings(parsedType, isOutermostType) {
|
|
2860
3133
|
let applications;
|
|
2861
3134
|
let typeString;
|
|
@@ -2960,11 +3233,11 @@ exports.astNodeVisitor = {
|
|
|
2960
3233
|
// #### BEGIN: MODIFIED BY SAP
|
|
2961
3234
|
if ( tagInfo && (/function/.test(tagInfo.typeExpression) || /\{.*\}/.test(tagInfo.typeExpression)) && tagInfo.parsedType ) {
|
|
2962
3235
|
// #### END: MODIFIED BY SAP
|
|
2963
|
-
// console.info("old typeExpression", tagInfo.typeExpression);
|
|
2964
|
-
// console.info("old parse tree", tagInfo.parsedType);
|
|
2965
|
-
// console.info("old parse result", tagInfo.type);
|
|
3236
|
+
// console.info("old typeExpression", tagInfo.typeExpression);
|
|
3237
|
+
// console.info("old parse tree", tagInfo.parsedType);
|
|
3238
|
+
// console.info("old parse result", tagInfo.type);
|
|
2966
3239
|
tagInfo.type = getTypeStrings(tagInfo.parsedType);
|
|
2967
|
-
// console.info("new parse result", tagInfo.type);
|
|
3240
|
+
// console.info("new parse result", tagInfo.type);
|
|
2968
3241
|
}
|
|
2969
3242
|
return tagInfo;
|
|
2970
3243
|
}
|
|
@@ -2877,7 +2877,11 @@ function createAPIJSON4Symbol(symbol, omitDefaults) {
|
|
|
2877
2877
|
}
|
|
2878
2878
|
tag("method");
|
|
2879
2879
|
attrib("name", name || member.name);
|
|
2880
|
-
|
|
2880
|
+
// write out module and export only when the module is different from the module of the parent entity
|
|
2881
|
+
// and when the member was not cloned (e.g. because it is borrowed)
|
|
2882
|
+
if ( member.__ui5.module
|
|
2883
|
+
&& member.__ui5.module !== symbol.__ui5.module
|
|
2884
|
+
&& member.__ui5.initialLongname === member.longname ) {
|
|
2881
2885
|
attrib("module", member.__ui5.module);
|
|
2882
2886
|
attrib("export", member.__ui5.globalOnly ? GLOBAL_ONLY : member.__ui5.export, '', true);
|
|
2883
2887
|
}
|
|
@@ -178,7 +178,7 @@ class LibraryLessGenerator {
|
|
|
178
178
|
* @param {@ui5/fs/Resource[]} parameters.resources List of <code>library.source.less</code>
|
|
179
179
|
* resources
|
|
180
180
|
* @param {fs|module:@ui5/fs/fsInterface} parameters.fs Node fs or custom
|
|
181
|
-
* [fs interface]{@link module
|
|
181
|
+
* [fs interface]{@link module:@ui5/fs/fsInterface}
|
|
182
182
|
* @returns {Promise<@ui5/fs/Resource[]>} Promise resolving with library.less resources
|
|
183
183
|
*/
|
|
184
184
|
async function createLibraryLess({resources, fs}) {
|
|
@@ -349,7 +349,7 @@ async function createManifest(
|
|
|
349
349
|
}
|
|
350
350
|
|
|
351
351
|
function collectThemes() {
|
|
352
|
-
const themes =
|
|
352
|
+
const themes = Object.create(null);
|
|
353
353
|
|
|
354
354
|
// find theme resources and determine theme names from their paths
|
|
355
355
|
libBundle.getResources(/(?:[^/]+\/)*themes\//).forEach((res) => {
|
|
@@ -14,7 +14,7 @@ import escapeUnicode from "escape-unicode";
|
|
|
14
14
|
const CHAR_CODE_OF_LAST_ASCII_CHARACTER = 127;
|
|
15
15
|
|
|
16
16
|
// use memoization for escapeUnicode function for performance
|
|
17
|
-
const memoizeEscapeUnicodeMap =
|
|
17
|
+
const memoizeEscapeUnicodeMap = Object.create(null);
|
|
18
18
|
const memoizeEscapeUnicode = function(sChar) {
|
|
19
19
|
if (memoizeEscapeUnicodeMap[sChar]) {
|
|
20
20
|
return memoizeEscapeUnicodeMap[sChar];
|
|
@@ -25,7 +25,7 @@ function getTimestamp() {
|
|
|
25
25
|
/**
|
|
26
26
|
* Manifest libraries as defined in the manifest.json file
|
|
27
27
|
*
|
|
28
|
-
* @typedef {
|
|
28
|
+
* @typedef {Object<string, {lazy: boolean}>} ManifestLibraries
|
|
29
29
|
*
|
|
30
30
|
* sample:
|
|
31
31
|
* <pre>
|
|
@@ -60,15 +60,15 @@ function getTimestamp() {
|
|
|
60
60
|
const processManifest = async (manifestResource) => {
|
|
61
61
|
const manifestContent = await manifestResource.getString();
|
|
62
62
|
const manifestObject = JSON.parse(manifestContent);
|
|
63
|
-
const manifestInfo =
|
|
63
|
+
const manifestInfo = Object.create(null);
|
|
64
64
|
|
|
65
65
|
// sap.ui5/dependencies is used for the "manifestHints/libs"
|
|
66
66
|
if (manifestObject["sap.ui5"]) {
|
|
67
67
|
const manifestDependencies = manifestObject["sap.ui5"]["dependencies"];
|
|
68
68
|
if (manifestDependencies && manifestDependencies.libs) {
|
|
69
|
-
const libs =
|
|
69
|
+
const libs = Object.create(null);
|
|
70
70
|
for (const [libKey, libValue] of Object.entries(manifestDependencies.libs)) {
|
|
71
|
-
libs[libKey] =
|
|
71
|
+
libs[libKey] = Object.create(null);
|
|
72
72
|
if (libValue.lazy) {
|
|
73
73
|
libs[libKey].lazy = true;
|
|
74
74
|
}
|
|
@@ -230,7 +230,7 @@ class DependencyInfo {
|
|
|
230
230
|
* @returns {object} the object with sorted keys
|
|
231
231
|
*/
|
|
232
232
|
const sortObjectKeys = (obj) => {
|
|
233
|
-
const sortedObject =
|
|
233
|
+
const sortedObject = Object.create(null);
|
|
234
234
|
const keys = Object.keys(obj);
|
|
235
235
|
keys.sort();
|
|
236
236
|
keys.forEach((key) => {
|
|
@@ -433,7 +433,7 @@ export default async function({options}) {
|
|
|
433
433
|
let components;
|
|
434
434
|
artifactInfos.forEach((artifactInfo) => {
|
|
435
435
|
artifactInfo.embeds.forEach((embeddedArtifactInfo) => {
|
|
436
|
-
const componentObject =
|
|
436
|
+
const componentObject = Object.create(null);
|
|
437
437
|
const bundledComponents = artifactInfo.bundledComponents;
|
|
438
438
|
const componentName = embeddedArtifactInfo.componentName;
|
|
439
439
|
if (!bundledComponents.has(componentName)) {
|
|
@@ -446,7 +446,7 @@ export default async function({options}) {
|
|
|
446
446
|
componentObject.manifestHints = manifestHints;
|
|
447
447
|
}
|
|
448
448
|
|
|
449
|
-
components = components ||
|
|
449
|
+
components = components || Object.create(null);
|
|
450
450
|
components[componentName] = componentObject;
|
|
451
451
|
});
|
|
452
452
|
});
|
|
@@ -87,8 +87,11 @@ export default async function({
|
|
|
87
87
|
// Omit -dbg files for optimize bundles and vice versa
|
|
88
88
|
const filterTag = optimize ?
|
|
89
89
|
taskUtil.STANDARD_TAGS.IsDebugVariant : taskUtil.STANDARD_TAGS.HasDebugVariant;
|
|
90
|
-
combo =
|
|
91
|
-
|
|
90
|
+
combo = taskUtil.resourceFactory.createFilterReader({
|
|
91
|
+
reader: combo,
|
|
92
|
+
callback: function(resource) {
|
|
93
|
+
return !taskUtil.getTag(resource, filterTag);
|
|
94
|
+
}
|
|
92
95
|
});
|
|
93
96
|
}
|
|
94
97
|
|
|
@@ -37,9 +37,12 @@ export default async function({
|
|
|
37
37
|
}) {
|
|
38
38
|
let nonDbgWorkspace = workspace;
|
|
39
39
|
if (taskUtil) {
|
|
40
|
-
nonDbgWorkspace =
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
nonDbgWorkspace = taskUtil.resourceFactory.createFilterReader({
|
|
41
|
+
reader: workspace,
|
|
42
|
+
callback: function(resource) {
|
|
43
|
+
// Remove any debug variants
|
|
44
|
+
return !taskUtil.getTag(resource, taskUtil.STANDARD_TAGS.IsDebugVariant);
|
|
45
|
+
}
|
|
43
46
|
});
|
|
44
47
|
}
|
|
45
48
|
|
|
@@ -246,9 +246,12 @@ function getSapUiCoreBunDef(name, filters, preload) {
|
|
|
246
246
|
export default async function({workspace, taskUtil, options: {skipBundles = [], excludes = [], projectName}}) {
|
|
247
247
|
let nonDbgWorkspace = workspace;
|
|
248
248
|
if (taskUtil) {
|
|
249
|
-
nonDbgWorkspace =
|
|
250
|
-
|
|
251
|
-
|
|
249
|
+
nonDbgWorkspace = taskUtil.resourceFactory.createFilterReader({
|
|
250
|
+
reader: workspace,
|
|
251
|
+
callback: function(resource) {
|
|
252
|
+
// Remove any debug variants
|
|
253
|
+
return !taskUtil.getTag(resource, taskUtil.STANDARD_TAGS.IsDebugVariant);
|
|
254
|
+
}
|
|
252
255
|
});
|
|
253
256
|
}
|
|
254
257
|
|
|
@@ -273,7 +276,7 @@ export default async function({workspace, taskUtil, options: {skipBundles = [],
|
|
|
273
276
|
// This is mainly to have an easier check without version parsing or using semver.
|
|
274
277
|
// If no project/specVersion is available, the bundles should also be created to not break potential
|
|
275
278
|
// existing use cases without a properly formed/formatted project tree.
|
|
276
|
-
if (!taskUtil ||
|
|
279
|
+
if (!taskUtil || taskUtil.getProject().getSpecVersion().lte("2.0")) {
|
|
277
280
|
const isEvo = resources.find((resource) => {
|
|
278
281
|
return resource.getPath() === "/resources/ui5loader.js";
|
|
279
282
|
});
|
|
@@ -281,9 +284,12 @@ export default async function({workspace, taskUtil, options: {skipBundles = [],
|
|
|
281
284
|
let unoptimizedModuleNameMapping;
|
|
282
285
|
let unoptimizedResources = resources;
|
|
283
286
|
if (taskUtil) {
|
|
284
|
-
const unoptimizedWorkspace =
|
|
285
|
-
|
|
286
|
-
|
|
287
|
+
const unoptimizedWorkspace = taskUtil.resourceFactory.createFilterReader({
|
|
288
|
+
reader: workspace,
|
|
289
|
+
callback: function(resource) {
|
|
290
|
+
// Remove any non-debug variants
|
|
291
|
+
return !taskUtil.getTag(resource, taskUtil.STANDARD_TAGS.HasDebugVariant);
|
|
292
|
+
}
|
|
287
293
|
});
|
|
288
294
|
unoptimizedResources =
|
|
289
295
|
await unoptimizedWorkspace.byGlob("/**/*.{js,json,xml,html,properties,library,js.map}");
|
|
@@ -15,7 +15,7 @@ import {getNonDebugName} from "../../../lbt/utils/ModuleName.js";
|
|
|
15
15
|
* @returns {object} Module name mapping
|
|
16
16
|
*/
|
|
17
17
|
export default function({resources, taskUtil}) {
|
|
18
|
-
const moduleNameMapping =
|
|
18
|
+
const moduleNameMapping = Object.create(null);
|
|
19
19
|
for (let i = resources.length - 1; i >= 0; i--) {
|
|
20
20
|
const resource = resources[i];
|
|
21
21
|
if (taskUtil.getTag(resource, taskUtil.STANDARD_TAGS.IsDebugVariant)) {
|
|
@@ -57,7 +57,7 @@ export default function({workspace, options}) {
|
|
|
57
57
|
const basePath = `/resources/${namespace}/`;
|
|
58
58
|
return workspace.byGlob(`/resources/${namespace}/**/*`)
|
|
59
59
|
.then(async (resources) => {
|
|
60
|
-
const cachebusterInfo =
|
|
60
|
+
const cachebusterInfo = Object.create(null);
|
|
61
61
|
const signer = getSigner(signatureType);
|
|
62
62
|
|
|
63
63
|
await Promise.all(resources.map(async (resource) => {
|
|
@@ -11,7 +11,6 @@ const taskInfos = {
|
|
|
11
11
|
transformBootstrapHtml: {path: "./transformBootstrapHtml.js"},
|
|
12
12
|
generateLibraryManifest: {path: "./generateLibraryManifest.js"},
|
|
13
13
|
generateVersionInfo: {path: "./generateVersionInfo.js"},
|
|
14
|
-
generateManifestBundle: {path: "./bundlers/generateManifestBundle.js"},
|
|
15
14
|
generateFlexChangesBundle: {path: "./bundlers/generateFlexChangesBundle.js"},
|
|
16
15
|
generateComponentPreload: {path: "./bundlers/generateComponentPreload.js"},
|
|
17
16
|
generateResourcesJson: {path: "./generateResourcesJson.js"},
|
|
@@ -26,7 +25,7 @@ export async function getTask(taskName) {
|
|
|
26
25
|
const taskInfo = taskInfos[taskName];
|
|
27
26
|
|
|
28
27
|
if (!taskInfo) {
|
|
29
|
-
if (["createDebugFiles", "uglify"].includes(taskName)) {
|
|
28
|
+
if (["createDebugFiles", "uglify", "generateManifestBundle"].includes(taskName)) {
|
|
30
29
|
throw new Error(
|
|
31
30
|
`Standard task ${taskName} has been removed in UI5 Tooling 3.0. ` +
|
|
32
31
|
`Please see the migration guide at https://sap.github.io/ui5-tooling/updates/migrate-v3/`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ui5/builder",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.3",
|
|
4
4
|
"description": "UI5 Tooling - Builder",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "SAP SE",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"./internal/jsdoc/template/publish": "./lib/processors/jsdoc/lib/ui5/template/publish.cjs"
|
|
29
29
|
},
|
|
30
30
|
"engines": {
|
|
31
|
-
"node": "
|
|
31
|
+
"node": "^16.18.0 || >=18.0.0",
|
|
32
32
|
"npm": ">= 8"
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
@@ -119,44 +119,42 @@
|
|
|
119
119
|
},
|
|
120
120
|
"dependencies": {
|
|
121
121
|
"@jridgewell/sourcemap-codec": "^1.4.14",
|
|
122
|
-
"@ui5/fs": "^3.0.0-beta.
|
|
123
|
-
"@ui5/logger": "^3.0.1-beta.
|
|
124
|
-
"cheerio": "1.0.0-rc.
|
|
122
|
+
"@ui5/fs": "^3.0.0-beta.3",
|
|
123
|
+
"@ui5/logger": "^3.0.1-beta.1",
|
|
124
|
+
"cheerio": "1.0.0-rc.12",
|
|
125
125
|
"escape-unicode": "^0.2.0",
|
|
126
126
|
"escope": "^4.0.0",
|
|
127
|
-
"espree": "^9.
|
|
128
|
-
"graceful-fs": "^4.2.
|
|
129
|
-
"jsdoc": "^3.6.
|
|
127
|
+
"espree": "^9.4.1",
|
|
128
|
+
"graceful-fs": "^4.2.10",
|
|
129
|
+
"jsdoc": "^3.6.11",
|
|
130
130
|
"less-openui5": "^0.11.2",
|
|
131
131
|
"make-dir": "^3.1.0",
|
|
132
132
|
"pretty-data": "^0.40.0",
|
|
133
133
|
"replacestream": "^4.0.3",
|
|
134
134
|
"rimraf": "^3.0.2",
|
|
135
|
-
"semver": "^7.3.
|
|
136
|
-
"terser": "^5.
|
|
137
|
-
"xml2js": "^0.4.23"
|
|
138
|
-
"yazl": "^2.5.1"
|
|
135
|
+
"semver": "^7.3.8",
|
|
136
|
+
"terser": "^5.16.0",
|
|
137
|
+
"xml2js": "^0.4.23"
|
|
139
138
|
},
|
|
140
139
|
"devDependencies": {
|
|
141
140
|
"@istanbuljs/esm-loader-hook": "^0.2.0",
|
|
142
|
-
"@ui5/project": "^3.0.0-
|
|
143
|
-
"ava": "^
|
|
144
|
-
"chai": "^4.3.
|
|
141
|
+
"@ui5/project": "^3.0.0-beta.3",
|
|
142
|
+
"ava": "^5.1.0",
|
|
143
|
+
"chai": "^4.3.7",
|
|
145
144
|
"chai-fs": "^2.0.0",
|
|
146
145
|
"chokidar-cli": "^3.0.0",
|
|
147
146
|
"cross-env": "^7.0.3",
|
|
148
147
|
"depcheck": "^1.4.3",
|
|
149
|
-
"docdash": "^
|
|
150
|
-
"eslint": "^8.
|
|
148
|
+
"docdash": "^2.0.0",
|
|
149
|
+
"eslint": "^8.28.0",
|
|
151
150
|
"eslint-config-google": "^0.14.0",
|
|
152
151
|
"eslint-plugin-ava": "^13.2.0",
|
|
153
|
-
"eslint-plugin-jsdoc": "^
|
|
154
|
-
"esmock": "^2.0.
|
|
155
|
-
"extract-zip": "^2.0.1",
|
|
152
|
+
"eslint-plugin-jsdoc": "^39.6.4",
|
|
153
|
+
"esmock": "^2.0.9",
|
|
156
154
|
"nyc": "^15.1.0",
|
|
157
155
|
"open-cli": "^7.1.0",
|
|
158
156
|
"recursive-readdir": "^2.2.3",
|
|
159
|
-
"sinon": "^14.0.
|
|
157
|
+
"sinon": "^14.0.2",
|
|
160
158
|
"tap-nyan": "^1.1.0",
|
|
161
159
|
"tap-xunit": "^2.4.1"
|
|
162
160
|
}
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import posixPath from "node:path/posix";
|
|
2
|
-
import yazl from "yazl";
|
|
3
|
-
import {createResource} from "@ui5/fs/resourceFactory";
|
|
4
|
-
import logger from "@ui5/logger";
|
|
5
|
-
const log = logger.getLogger("builder:processors:bundlers:manifestBundler");
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Repository to handle i18n resource files
|
|
9
|
-
*
|
|
10
|
-
* @private
|
|
11
|
-
*/
|
|
12
|
-
class I18nResourceList {
|
|
13
|
-
/**
|
|
14
|
-
* Constructor
|
|
15
|
-
*/
|
|
16
|
-
constructor() {
|
|
17
|
-
this.propertyFiles = new Map();
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Adds a i18n resource to the repository
|
|
22
|
-
*
|
|
23
|
-
* @param {string} directory Path to the i18n resource
|
|
24
|
-
* @param {@ui5/fs/Resource} resource i18n resource
|
|
25
|
-
*/
|
|
26
|
-
add(directory, resource) {
|
|
27
|
-
const normalizedDirectory = posixPath.normalize(directory);
|
|
28
|
-
if (!this.propertyFiles.has(normalizedDirectory)) {
|
|
29
|
-
this.propertyFiles.set(normalizedDirectory, [resource]);
|
|
30
|
-
} else {
|
|
31
|
-
this.propertyFiles.get(normalizedDirectory).push(resource);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Gets all registered i18n files within the provided path
|
|
37
|
-
*
|
|
38
|
-
* @param {string} directory Path to search for
|
|
39
|
-
* @returns {Array} Array of resources files
|
|
40
|
-
*/
|
|
41
|
-
get(directory) {
|
|
42
|
-
return this.propertyFiles.get(posixPath.normalize(directory)) || [];
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* @public
|
|
49
|
-
* @module @ui5/builder/processors/bundlers/manifestBundler
|
|
50
|
-
*/
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Creates a manifest bundle from the provided resources.
|
|
54
|
-
*
|
|
55
|
-
* @public
|
|
56
|
-
* @function default
|
|
57
|
-
* @static
|
|
58
|
-
*
|
|
59
|
-
* @param {object} parameters Parameters
|
|
60
|
-
* @param {@ui5/fs/Resource[]} parameters.resources List of resources to be processed
|
|
61
|
-
* @param {object} parameters.options Options
|
|
62
|
-
* @param {string} parameters.options.namespace Namespace of the project
|
|
63
|
-
* @param {string} parameters.options.bundleName Name of the bundled zip file
|
|
64
|
-
* @param {string} parameters.options.propertiesExtension Extension name of the properties files, e.g. ".properties"
|
|
65
|
-
* @param {string} parameters.options.descriptor Descriptor name
|
|
66
|
-
* @returns {Promise<@ui5/fs/Resource[]>} Promise resolving with manifest bundle resources
|
|
67
|
-
*/
|
|
68
|
-
export default ({resources, options: {namespace, bundleName, propertiesExtension, descriptor}}) => {
|
|
69
|
-
function bundleNameToUrl(bundleName, appId) {
|
|
70
|
-
if (!bundleName.startsWith(appId)) {
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
|
-
const relativeBundleName = bundleName.substring(appId.length + 1);
|
|
74
|
-
return relativeBundleName.replace(/\./g, "/") + propertiesExtension;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function addDescriptorI18nInfos(descriptorI18nInfos, manifest) {
|
|
78
|
-
function addI18nInfo(i18nPath) {
|
|
79
|
-
if (i18nPath.startsWith("ui5:")) {
|
|
80
|
-
log.warn(`Using the ui5:// protocol for i18n bundles is currently not supported ('${i18nPath}' in ${manifest.path})`);
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
descriptorI18nInfos.set(
|
|
84
|
-
posixPath.join(posixPath.dirname(manifest.path), posixPath.dirname(i18nPath)),
|
|
85
|
-
posixPath.basename(i18nPath, propertiesExtension)
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const content = JSON.parse(manifest.content);
|
|
90
|
-
const appI18n = content["sap.app"]["i18n"];
|
|
91
|
-
let bundleUrl;
|
|
92
|
-
// i18n section in sap.app can be either a string or an object with bundleUrl
|
|
93
|
-
if (typeof appI18n === "object") {
|
|
94
|
-
if (appI18n.bundleUrl) {
|
|
95
|
-
bundleUrl = appI18n.bundleUrl;
|
|
96
|
-
} else if (appI18n.bundleName) {
|
|
97
|
-
bundleUrl = bundleNameToUrl(appI18n.bundleName, content["sap.app"]["id"]);
|
|
98
|
-
}
|
|
99
|
-
} else if (typeof appI18n === "string") {
|
|
100
|
-
bundleUrl = appI18n;
|
|
101
|
-
} else {
|
|
102
|
-
bundleUrl = "i18n/i18n.properties";
|
|
103
|
-
}
|
|
104
|
-
if (bundleUrl) {
|
|
105
|
-
addI18nInfo(bundleUrl);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (typeof appI18n === "object" && Array.isArray(appI18n.enhanceWith)) {
|
|
109
|
-
appI18n.enhanceWith.forEach((enhanceWithEntry) => {
|
|
110
|
-
let bundleUrl;
|
|
111
|
-
if (enhanceWithEntry.bundleUrl) {
|
|
112
|
-
bundleUrl = enhanceWithEntry.bundleUrl;
|
|
113
|
-
} else if (enhanceWithEntry.bundleName) {
|
|
114
|
-
bundleUrl = bundleNameToUrl(enhanceWithEntry.bundleName, content["sap.app"]["id"]);
|
|
115
|
-
}
|
|
116
|
-
if (bundleUrl) {
|
|
117
|
-
addI18nInfo(bundleUrl);
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return Promise.all(resources.map((resource) =>
|
|
124
|
-
resource.getBuffer().then((content) => {
|
|
125
|
-
const basename = posixPath.basename(resource.getPath());
|
|
126
|
-
return {
|
|
127
|
-
name: basename,
|
|
128
|
-
isManifest: basename === descriptor,
|
|
129
|
-
path: resource.getPath(),
|
|
130
|
-
content: content
|
|
131
|
-
};
|
|
132
|
-
})
|
|
133
|
-
)).then((resources) => {
|
|
134
|
-
const archiveContent = new Map();
|
|
135
|
-
const descriptorI18nInfos = new Map();
|
|
136
|
-
const i18nResourceList = new I18nResourceList();
|
|
137
|
-
|
|
138
|
-
resources.forEach((resource) => {
|
|
139
|
-
if (resource.isManifest) {
|
|
140
|
-
addDescriptorI18nInfos(descriptorI18nInfos, resource);
|
|
141
|
-
archiveContent.set(resource.path, resource.content);
|
|
142
|
-
} else {
|
|
143
|
-
const directory = posixPath.dirname(resource.path);
|
|
144
|
-
i18nResourceList.add(directory, resource);
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
descriptorI18nInfos.forEach((rootName, directory) => {
|
|
149
|
-
const i18nResources = i18nResourceList.get(directory)
|
|
150
|
-
.filter((resource) => resource.name.startsWith(rootName));
|
|
151
|
-
|
|
152
|
-
if (i18nResources.length) {
|
|
153
|
-
i18nResources.forEach((resource) => archiveContent.set(resource.path, resource.content));
|
|
154
|
-
} else {
|
|
155
|
-
log.warn(`Could not find any resources for i18n bundle '${directory}'`);
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
return archiveContent;
|
|
160
|
-
}).then((archiveContent) => new Promise((resolve) => {
|
|
161
|
-
const zip = new yazl.ZipFile();
|
|
162
|
-
const basePath = `/resources/${namespace}/`;
|
|
163
|
-
archiveContent.forEach((content, path) => {
|
|
164
|
-
if (!path.startsWith(basePath)) {
|
|
165
|
-
log.verbose(`Not bundling resource with path ${path} since it is not based on path ${basePath}`);
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
// Remove base path. Absolute paths are not allowed in ZIP files
|
|
169
|
-
const normalizedPath = path.replace(basePath, "");
|
|
170
|
-
zip.addBuffer(content, normalizedPath);
|
|
171
|
-
});
|
|
172
|
-
zip.end();
|
|
173
|
-
|
|
174
|
-
const pathPrefix = "/resources/" + namespace + "/";
|
|
175
|
-
const res = createResource({
|
|
176
|
-
path: pathPrefix + bundleName,
|
|
177
|
-
stream: zip.outputStream
|
|
178
|
-
});
|
|
179
|
-
resolve([res]);
|
|
180
|
-
}));
|
|
181
|
-
};
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import logger from "@ui5/logger";
|
|
2
|
-
const log = logger.getLogger("builder:tasks:bundlers:generateManifestBundle");
|
|
3
|
-
import manifestBundler from "../../processors/bundlers/manifestBundler.js";
|
|
4
|
-
|
|
5
|
-
const DESCRIPTOR = "manifest.json";
|
|
6
|
-
const PROPERTIES_EXT = ".properties";
|
|
7
|
-
const BUNDLE_NAME = "manifest-bundle.zip";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @public
|
|
11
|
-
* @module @ui5/builder/tasks/bundlers/generateManifestBundle
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/* eslint "jsdoc/check-param-names": ["error", {"disableExtraPropertyReporting":true}] */
|
|
15
|
-
/**
|
|
16
|
-
* Task for manifestBundler.
|
|
17
|
-
*
|
|
18
|
-
* @public
|
|
19
|
-
* @function default
|
|
20
|
-
* @static
|
|
21
|
-
*
|
|
22
|
-
* @param {object} parameters Parameters
|
|
23
|
-
* @param {@ui5/fs/DuplexCollection} parameters.workspace DuplexCollection to read and write files
|
|
24
|
-
* @param {object} parameters.options Options
|
|
25
|
-
* @param {string} parameters.options.projectName Project name
|
|
26
|
-
* @param {string} parameters.options.projectNamespace Project namespace
|
|
27
|
-
* @returns {Promise<undefined>} Promise resolving with <code>undefined</code> once data has been written
|
|
28
|
-
*/
|
|
29
|
-
export default async function({workspace, options = {}}) {
|
|
30
|
-
const {projectName} = options;
|
|
31
|
-
// Backward compatibility: "namespace" option got renamed to "projectNamespace"
|
|
32
|
-
const namespace = options.projectNamespace || options.namespace;
|
|
33
|
-
|
|
34
|
-
if (!projectName || !namespace) {
|
|
35
|
-
throw new Error("[generateManifestBundle]: One or more mandatory options not provided");
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const allResources = await workspace.byGlob(`/resources/${namespace}/**/{${DESCRIPTOR},*${PROPERTIES_EXT}}`);
|
|
39
|
-
if (allResources.length === 0) {
|
|
40
|
-
log.verbose(`Could not find a "${DESCRIPTOR}" file for project ${projectName}, ` +
|
|
41
|
-
`creation of "${BUNDLE_NAME}" is skipped!`);
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const processedResources = await manifestBundler({
|
|
46
|
-
resources: allResources,
|
|
47
|
-
options: {
|
|
48
|
-
descriptor: DESCRIPTOR,
|
|
49
|
-
propertiesExtension: PROPERTIES_EXT,
|
|
50
|
-
bundleName: BUNDLE_NAME,
|
|
51
|
-
namespace
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
await Promise.all(processedResources.map((resource) => {
|
|
56
|
-
return workspace.write(resource);
|
|
57
|
-
}));
|
|
58
|
-
}
|