@ui5/builder 3.0.0-alpha.10 → 3.0.0-alpha.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +35 -2
  2. package/jsdoc.json +2 -2
  3. package/lib/lbt/UI5ClientConstants.js +7 -8
  4. package/lib/lbt/analyzer/ComponentAnalyzer.js +10 -10
  5. package/lib/lbt/analyzer/FioriElementsAnalyzer.js +31 -20
  6. package/lib/lbt/analyzer/JSModuleAnalyzer.js +107 -65
  7. package/lib/lbt/analyzer/SmartTemplateAnalyzer.js +31 -20
  8. package/lib/lbt/analyzer/XMLCompositeAnalyzer.js +35 -25
  9. package/lib/lbt/analyzer/XMLTemplateAnalyzer.js +19 -17
  10. package/lib/lbt/analyzer/analyzeLibraryJS.js +22 -6
  11. package/lib/lbt/bundle/AutoSplitter.js +10 -11
  12. package/lib/lbt/bundle/Builder.js +30 -33
  13. package/lib/lbt/bundle/BundleDefinition.js +1 -5
  14. package/lib/lbt/bundle/BundleWriter.js +1 -2
  15. package/lib/lbt/bundle/ResolvedBundleDefinition.js +6 -7
  16. package/lib/lbt/bundle/Resolver.js +9 -10
  17. package/lib/lbt/calls/SapUiDefine.js +16 -11
  18. package/lib/lbt/graph/dependencyGraph.js +3 -4
  19. package/lib/lbt/graph/dominatorTree.js +3 -3
  20. package/lib/lbt/graph/topologicalSort.js +3 -3
  21. package/lib/lbt/resources/LibraryFileAnalyzer.js +5 -8
  22. package/lib/lbt/resources/LocatorResource.js +2 -2
  23. package/lib/lbt/resources/LocatorResourcePool.js +3 -3
  24. package/lib/lbt/resources/ModuleInfo.js +1 -2
  25. package/lib/lbt/resources/Resource.js +3 -4
  26. package/lib/lbt/resources/ResourceCollector.js +7 -8
  27. package/lib/lbt/resources/ResourceFilterList.js +38 -40
  28. package/lib/lbt/resources/ResourceInfo.js +1 -1
  29. package/lib/lbt/resources/ResourceInfoList.js +2 -2
  30. package/lib/lbt/resources/ResourcePool.js +15 -21
  31. package/lib/lbt/utils/ASTUtils.js +58 -44
  32. package/lib/lbt/utils/JSTokenizer.js +4 -4
  33. package/lib/lbt/utils/ModuleName.js +10 -20
  34. package/lib/lbt/utils/escapePropertiesFile.js +3 -3
  35. package/lib/lbt/utils/parseUtils.js +4 -10
  36. package/lib/processors/bootstrapHtmlTransformer.js +15 -7
  37. package/lib/processors/bundlers/flexChangesBundler.js +16 -8
  38. package/lib/processors/bundlers/manifestBundler.js +19 -10
  39. package/lib/processors/bundlers/moduleBundler.js +26 -15
  40. package/lib/processors/jsdoc/apiIndexGenerator.js +16 -9
  41. package/lib/processors/jsdoc/jsdocGenerator.js +31 -17
  42. package/lib/processors/jsdoc/lib/{createIndexFiles.js → createIndexFiles.cjs} +0 -0
  43. package/lib/processors/jsdoc/lib/{transformApiJson.js → transformApiJson.cjs} +58 -2
  44. package/lib/processors/jsdoc/lib/ui5/{plugin.js → plugin.cjs} +306 -119
  45. package/lib/processors/jsdoc/lib/ui5/template/{publish.js → publish.cjs} +1 -1
  46. package/lib/processors/jsdoc/lib/ui5/template/utils/{versionUtil.js → versionUtil.cjs} +0 -0
  47. package/lib/processors/jsdoc/sdkTransformer.js +18 -11
  48. package/lib/processors/libraryLessGenerator.js +28 -16
  49. package/lib/processors/manifestCreator.js +14 -13
  50. package/lib/processors/minifier.js +21 -15
  51. package/lib/processors/nonAsciiEscaper.js +16 -6
  52. package/lib/processors/resourceListCreator.js +13 -13
  53. package/lib/processors/stringReplacer.js +13 -6
  54. package/lib/processors/themeBuilder.js +30 -22
  55. package/lib/processors/versionInfoGenerator.js +33 -23
  56. package/lib/tasks/buildThemes.js +17 -10
  57. package/lib/tasks/bundlers/generateBundle.js +23 -12
  58. package/lib/tasks/bundlers/generateComponentPreload.js +18 -10
  59. package/lib/tasks/bundlers/generateFlexChangesBundle.js +16 -8
  60. package/lib/tasks/bundlers/generateLibraryPreload.js +22 -12
  61. package/lib/tasks/bundlers/generateManifestBundle.js +15 -6
  62. package/lib/tasks/bundlers/generateStandaloneAppBundle.js +21 -13
  63. package/lib/tasks/bundlers/utils/createModuleNameMapping.js +6 -6
  64. package/lib/tasks/escapeNonAsciiCharacters.js +12 -5
  65. package/lib/tasks/generateCachebusterInfo.js +16 -8
  66. package/lib/tasks/generateLibraryManifest.js +14 -8
  67. package/lib/tasks/generateResourcesJson.js +15 -9
  68. package/lib/tasks/generateThemeDesignerResources.js +19 -9
  69. package/lib/tasks/generateVersionInfo.js +12 -5
  70. package/lib/tasks/jsdoc/executeJsdocSdkTransformation.js +17 -9
  71. package/lib/tasks/jsdoc/generateApiIndex.js +16 -10
  72. package/lib/tasks/jsdoc/generateJsdoc.js +131 -119
  73. package/lib/tasks/minify.js +13 -6
  74. package/lib/tasks/replaceBuildtime.js +12 -5
  75. package/lib/tasks/replaceCopyright.js +12 -5
  76. package/lib/tasks/replaceVersion.js +12 -5
  77. package/lib/tasks/taskRepository.js +24 -29
  78. package/lib/tasks/transformBootstrapHtml.js +6 -5
  79. package/package.json +30 -15
  80. package/index.js +0 -173
@@ -53,7 +53,14 @@
53
53
  */
54
54
 
55
55
  /* imports */
56
- const Syntax = require('jsdoc/src/syntax').Syntax;
56
+ const Syntax = {
57
+ // Those are currently not in the syntax.js file.
58
+ ChainExpression: "ChainExpression",
59
+ OptionalMemberExpression: "OptionalMemberExpression",
60
+ OptionalCallExpression: "OptionalCallExpression",
61
+
62
+ ...require("jsdoc/src/syntax").Syntax,
63
+ };
57
64
  const Doclet = require('jsdoc/doclet').Doclet;
58
65
  const fs = require('jsdoc/fs');
59
66
  const path = require('jsdoc/path');
@@ -234,9 +241,8 @@ function resolveModuleName(base, name) {
234
241
  function analyzeModuleDefinition(node) {
235
242
  const args = node.arguments;
236
243
  let arg = 0;
237
- if ( arg < args.length
238
- && args[arg].type === Syntax.Literal && typeof args[arg].value === 'string' ) {
239
- currentModule.name = args[arg].value;
244
+ if ( arg < args.length && isStringLiteral(args[arg]) ) {
245
+ currentModule.name = convertValue(args[arg]);
240
246
  warning(`module explicitly defined a module name '${currentModule.name}'`);
241
247
  const resourceModuleName = getModuleName(currentModule.resource);
242
248
  if (currentModule.name !== resourceModuleName) {
@@ -249,13 +255,19 @@ function analyzeModuleDefinition(node) {
249
255
  currentModule.dependencies = convertValue(args[arg], "string[]");
250
256
  arg++;
251
257
  }
252
- if ( arg < args.length && args[arg].type === Syntax.FunctionExpression ) {
258
+ if ( arg < args.length &&
259
+ [Syntax.FunctionExpression, Syntax.ArrowFunctionExpression].includes(args[arg].type)) {
260
+
253
261
  currentModule.factory = args[arg];
254
262
  arg++;
255
263
  }
256
264
  if ( currentModule.dependencies && currentModule.factory ) {
257
265
  for ( let i = 0; i < currentModule.dependencies.length && i < currentModule.factory.params.length; i++ ) {
258
- const name = currentModule.factory.params[i].name;
266
+ const name =
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
270
+
259
271
  const module = resolveModuleName(currentModule.module, currentModule.dependencies[i]);
260
272
  debug(` import ${name} from '${module}'`);
261
273
  currentModule.localNames[name] = {
@@ -265,7 +277,7 @@ function analyzeModuleDefinition(node) {
265
277
  }
266
278
  }
267
279
  if ( currentModule.factory ) {
268
- collectShortcuts(currentModule.factory.body);
280
+ collectShortcuts(currentModule.factory);
269
281
  }
270
282
  }
271
283
 
@@ -276,16 +288,19 @@ function analyzeModuleDefinition(node) {
276
288
  *
277
289
  * @param {ASTNode} body AST node of a function body that shall be searched for shortcuts
278
290
  */
279
- function collectShortcuts(body) {
291
+ function collectShortcuts(factory) {
292
+ const body = factory.body;
280
293
 
281
294
  function checkAssignment(name, valueNode) {
295
+ valueNode = resolvePotentialWrapperExpression(valueNode);
296
+
282
297
  if ( valueNode.type === Syntax.Literal ) {
283
298
  currentModule.localNames[name] = {
284
299
  value: valueNode.value,
285
300
  raw: valueNode.raw
286
301
  };
287
302
  debug("compile time constant found ", name, valueNode.value);
288
- } else if ( valueNode.type === Syntax.MemberExpression ) {
303
+ } else if ( isMemberExpression(valueNode) ) {
289
304
  const _import = getLeftmostName(valueNode);
290
305
  const local = _import && currentModule.localNames[_import];
291
306
  const objectName = getObjectName(valueNode);
@@ -297,11 +312,9 @@ function collectShortcuts(body) {
297
312
  debug(` found local shortcut: ${name} ${currentModule.localNames[name]}`);
298
313
  }
299
314
  } else if ( isRequireSyncCall(valueNode) || isProbingRequireCall(valueNode) ) {
300
- if ( valueNode.arguments[0]
301
- && valueNode.arguments[0].type === Syntax.Literal
302
- && typeof valueNode.arguments[0].value === 'string' ) {
315
+ if ( valueNode.arguments[0] && isStringLiteral(valueNode.arguments[0]) ) {
303
316
  currentModule.localNames[name] = {
304
- module: valueNode.arguments[0].value
317
+ module: convertValue(valueNode.arguments[0])
305
318
  // no (or empty) path
306
319
  };
307
320
  debug(` found local import: ${name} = ${valueNode.callee.property.name}('${valueNode.arguments[0].value}')`);
@@ -315,8 +328,8 @@ function collectShortcuts(body) {
315
328
  }
316
329
  }
317
330
 
318
- if ( body.type === Syntax.BlockStatement ) {
319
- body.body.forEach(function ( stmt ) {
331
+ if ( body.type === Syntax.BlockStatement || isArrowFuncExpression(factory) ) {
332
+ const itemsResolver = function ( stmt ) {
320
333
  // console.log(stmt);
321
334
  if ( stmt.type === Syntax.FunctionDeclaration ) {
322
335
  if ( stmt.id && stmt.id.type === Syntax.Identifier && stmt.loc && stmt.loc.start ) {
@@ -336,15 +349,28 @@ function collectShortcuts(body) {
336
349
  && stmt.expression.type === Syntax.AssignmentExpression
337
350
  && stmt.expression.left.type === Syntax.Identifier ) {
338
351
  checkAssignment(stmt.expression.left.name, stmt.expression.right);
339
- } else if ( stmt.type === Syntax.ReturnStatement ) {
340
- if ( stmt.argument && stmt.argument.type === Syntax.Identifier ) {
341
- currentModule.defaultExport = stmt.argument.name;
342
- } else if ( stmt.argument && isExtendCall(stmt.argument) ) {
343
- debug(` found default export class definition: return .extend('${stmt.argument.arguments[0].value}', ...)`);
344
- currentModule.defaultExportClass = stmt.argument.arguments[0].value;
352
+ } else if ( isReturningNode(stmt) ) {
353
+ const stmtArgument = isArrowFuncExpression(stmt)
354
+ ? stmt.body
355
+ : resolvePotentialWrapperExpression(stmt).argument;
356
+
357
+ if ( stmtArgument && stmtArgument.type === Syntax.Identifier ) {
358
+ currentModule.defaultExport = stmtArgument.name;
359
+ } else if ( stmtArgument && stmtArgument.type === Syntax.ClassExpression && stmtArgument.id && stmtArgument.id.type === Syntax.Identifier ) {
360
+ debug(` found default export class definition: return class '${stmtArgument.id.name}'`);
361
+ currentModule.defaultExportClass = stmtArgument.id.name;
362
+ } else if ( stmtArgument && isExtendCall(stmtArgument) ) {
363
+ debug(` found default export class definition: return .extend('${stmtArgument.arguments[0].value}', ...)`);
364
+ currentModule.defaultExportClass = convertValue(stmtArgument.arguments[0]);
345
365
  }
346
366
  }
347
- });
367
+ };
368
+
369
+ if (isArrowFuncExpression(factory)) {
370
+ itemsResolver(factory);
371
+ } else {
372
+ body.body.forEach(itemsResolver);
373
+ }
348
374
  }
349
375
 
350
376
  if ( currentModule.defaultExport && currentModule.localNames[currentModule.defaultExport] ) {
@@ -369,12 +395,12 @@ function guessSingularName(sPluralName) {
369
395
  }
370
396
 
371
397
  function getPropertyKey(prop) {
372
- if ( prop.key.type === Syntax.Identifier ) {
398
+ if ( prop.type === Syntax.SpreadElement ) {
399
+ return;
400
+ } else if ( prop.key.type === Syntax.Identifier && prop.computed !== true ) {
373
401
  return prop.key.name;
374
402
  } else if ( prop.key.type === Syntax.Literal ) {
375
403
  return String(prop.key.value);
376
- } else {
377
- return prop.key.toSource();
378
404
  }
379
405
  }
380
406
 
@@ -432,80 +458,180 @@ function createPropertyMap(node, defaultKey) {
432
458
  return result;
433
459
  }
434
460
 
461
+ /**
462
+ * Resolves potential wrapper expressions like: ChainExpression, AwaitExpression, etc.
463
+ * @param {Node} node
464
+ * @returns {Node} the resolved node
465
+ */
466
+ function resolvePotentialWrapperExpression(node) {
467
+ switch (node && node.type) {
468
+ case Syntax.ChainExpression:
469
+ return node.expression;
470
+
471
+ case Syntax.AwaitExpression:
472
+ return node.argument;
473
+
474
+ case Syntax.ExpressionStatement:
475
+ if ( node.expression.type === Syntax.YieldExpression ) {
476
+ return node.expression.argument.type === Syntax.UpdateExpression
477
+ ? node.expression.argument
478
+ : node.expression;
479
+ }
480
+ default:
481
+ return node;
482
+ }
483
+ }
484
+
485
+ /**
486
+ * Strips the ChainExpression wrapper if such
487
+ *
488
+ * @param {Node} rootNode
489
+ * @param {String} path
490
+ * @returns {Node}
491
+ */
492
+ function stripChainWrappers(rootNode, path) {
493
+ const strip = (node) =>
494
+ node && node.type === Syntax.ChainExpression ? node.expression : node;
495
+
496
+ let curNode = strip(rootNode);
497
+ let chunks = path && path.split(".");
498
+ let name;
499
+
500
+ while (chunks && chunks.length) {
501
+ name = chunks.shift();
502
+ curNode = curNode && strip(curNode[name]);
503
+ }
504
+
505
+ return curNode;
506
+ }
507
+
508
+ function isTemplateLiteralWithoutExpression(node) {
509
+ return (
510
+ node?.type === Syntax.TemplateLiteral &&
511
+ node?.expressions?.length === 0 &&
512
+ node?.quasis?.length === 1
513
+ );
514
+ }
515
+
516
+ /**
517
+ * Checks whether a node is Literal or TemplateLiteral without an expression
518
+ *
519
+ * @param {Node} node
520
+ * @returns {String}
521
+ */
522
+ function isStringLiteral(node) {
523
+ return (
524
+ (node && node.type === Syntax.Literal && typeof node.value === "string")
525
+ || isTemplateLiteralWithoutExpression(node)
526
+ );
527
+ }
528
+
529
+ function isMemberExpression(node) {
530
+ return node && [Syntax.MemberExpression, Syntax.OptionalMemberExpression].includes(node.type);
531
+ }
532
+
533
+ function isCaleeMemberExpression(node) {
534
+ return (
535
+ node &&
536
+ [Syntax.CallExpression, Syntax.OptionalCallExpression].includes(node.type) &&
537
+ isMemberExpression(node.callee)
538
+ );
539
+ }
540
+
435
541
  function isExtendCall(node) {
542
+ node = stripChainWrappers(node);
436
543
 
437
544
  return (
438
545
  node
439
- && node.type === Syntax.CallExpression
440
- && node.callee.type === Syntax.MemberExpression
441
- && node.callee.property.type === Syntax.Identifier
442
- && node.callee.property.name === 'extend'
546
+ && isCaleeMemberExpression(node)
547
+ && stripChainWrappers(node, "callee.property").type === Syntax.Identifier
548
+ && stripChainWrappers(node, "callee.property").name === 'extend'
443
549
  && node.arguments.length >= 2
444
- && node.arguments[0].type === Syntax.Literal
445
- && typeof node.arguments[0].value === "string"
550
+ && isStringLiteral(node.arguments[0])
446
551
  && node.arguments[1].type === Syntax.ObjectExpression
447
552
  );
448
553
 
449
554
  }
450
555
 
556
+ function isArrowFuncExpression(node) {
557
+ return (
558
+ node &&
559
+ node.type === Syntax.ArrowFunctionExpression &&
560
+ node.expression === true
561
+ );
562
+ }
563
+
564
+ /**
565
+ * Checks whether the node is of a "returning" type
566
+ *
567
+ * @param {Node} node
568
+ * @returns {Boolean}
569
+ */
570
+ function isReturningNode(node) {
571
+ return (node && node.type === Syntax.ReturnStatement)
572
+ || (node && node.type === Syntax.ExpressionStatement && node.expression.type === Syntax.YieldExpression)
573
+ || isArrowFuncExpression(node);
574
+ }
575
+
451
576
  function isSapUiDefineCall(node) {
452
577
 
453
578
  return (
454
- node
455
- && node.type === Syntax.CallExpression
456
- && node.callee.type === Syntax.MemberExpression
457
- && node.callee.object.type === Syntax.MemberExpression
458
- && node.callee.object.object.type === Syntax.Identifier
459
- && node.callee.object.object.name === 'sap'
460
- && node.callee.object.property.type === Syntax.Identifier
461
- && node.callee.object.property.name === 'ui'
462
- && node.callee.property.type === Syntax.Identifier
463
- && node.callee.property.name === 'define'
579
+ stripChainWrappers(node)
580
+ && isCaleeMemberExpression(stripChainWrappers(node))
581
+ && isMemberExpression(stripChainWrappers(node, "callee.object"))
582
+ && stripChainWrappers(node, "callee.property").type === Syntax.Identifier
583
+ && stripChainWrappers(node, "callee.property").name === 'define'
584
+ && stripChainWrappers(node, "callee.object.object").type === Syntax.Identifier
585
+ && stripChainWrappers(node, "callee.object.object").name === 'sap'
586
+ && stripChainWrappers(node, "callee.object.property").type === Syntax.Identifier
587
+ && stripChainWrappers(node, "callee.object.property").name === 'ui'
464
588
  );
465
589
 
466
590
  }
467
591
 
468
592
  function isCreateDataTypeCall(node) {
593
+ node = stripChainWrappers(node);
594
+
469
595
  return (
470
596
  node
471
- && node.type === Syntax.CallExpression
472
- && node.callee.type === Syntax.MemberExpression
473
- && getResolvedObjectName(node.callee.object) === "sap.ui.base.DataType"
474
- && node.callee.property.type === Syntax.Identifier
475
- && node.callee.property.name === 'createType'
597
+ && isCaleeMemberExpression(node)
598
+ && getResolvedObjectName(stripChainWrappers(node, "callee.object")) === "sap.ui.base.DataType"
599
+ && stripChainWrappers(node, "callee.property").type === Syntax.Identifier
600
+ && stripChainWrappers(node, "callee.property").name === 'createType'
476
601
  );
477
602
  }
478
603
 
479
604
  function isRequireSyncCall(node) {
605
+ node = stripChainWrappers(node);
606
+
480
607
  return (
481
608
  node
482
- && node.type === Syntax.CallExpression
483
- && node.callee.type === Syntax.MemberExpression
484
- && node.callee.object.type === Syntax.MemberExpression
485
- && node.callee.object.object.type === Syntax.Identifier
486
- && node.callee.object.object.name === 'sap'
487
- && node.callee.object.property.type === Syntax.Identifier
488
- && node.callee.object.property.name === 'ui'
489
- && node.callee.property.type === Syntax.Identifier
490
- && node.callee.property.name === 'requireSync'
609
+ && isCaleeMemberExpression(node)
610
+ && isMemberExpression( stripChainWrappers(node, "callee.object") )
611
+ && stripChainWrappers(node, "callee.object.object").type === Syntax.Identifier
612
+ && stripChainWrappers(node, "callee.object.object").name === 'sap'
613
+ && stripChainWrappers(node, "callee.object.property").type === Syntax.Identifier
614
+ && stripChainWrappers(node, "callee.object.property").name === 'ui'
615
+ && stripChainWrappers(node, "callee.property").type === Syntax.Identifier
616
+ && stripChainWrappers(node, "callee.property").name === 'requireSync'
491
617
  );
492
618
  }
493
619
 
494
620
  function isProbingRequireCall(node) {
621
+ node = stripChainWrappers(node);
622
+
495
623
  return (
496
624
  node
497
- && node.type === Syntax.CallExpression
498
- && node.callee.type === Syntax.MemberExpression
499
- && node.callee.object.type === Syntax.MemberExpression
500
- && node.callee.object.object.type === Syntax.Identifier
501
- && node.callee.object.object.name === 'sap'
502
- && node.callee.object.property.type === Syntax.Identifier
503
- && node.callee.object.property.name === 'ui'
504
- && node.callee.property.type === Syntax.Identifier
505
- && node.callee.property.name === 'require'
625
+ && isCaleeMemberExpression(node)
626
+ && isMemberExpression( stripChainWrappers(node, "callee.object") )
627
+ && stripChainWrappers(node, "callee.object.object").type === Syntax.Identifier
628
+ && stripChainWrappers(node, "callee.object.object").name === 'sap'
629
+ && stripChainWrappers(node, "callee.object.property").type === Syntax.Identifier
630
+ && stripChainWrappers(node, "callee.object.property").name === 'ui'
631
+ && stripChainWrappers(node, "callee.property").type === Syntax.Identifier
632
+ && stripChainWrappers(node, "callee.property").name === 'require'
506
633
  && node.arguments.length === 1
507
- && node.arguments[0].type === Syntax.Literal
508
- && typeof node.arguments[0].value === 'string' // TODO generalize to statically analyzable constants
634
+ && isStringLiteral(node.arguments[0])
509
635
  );
510
636
  }
511
637
 
@@ -521,7 +647,7 @@ function isCompileTimeConstant(node) {
521
647
  }
522
648
 
523
649
  function getObjectName(node) {
524
- if ( node.type === Syntax.MemberExpression && !node.computed && node.property.type === Syntax.Identifier ) {
650
+ if ( isMemberExpression(node) && !node.computed && node.property.type === Syntax.Identifier ) {
525
651
  const prefix = getObjectName(node.object);
526
652
  return prefix ? prefix + "." + node.property.name : null;
527
653
  } else if ( node.type === Syntax.Identifier ) {
@@ -536,7 +662,7 @@ function getObjectName(node) {
536
662
  * returns the leftmost identifier a
537
663
  */
538
664
  function getLeftmostName(node) {
539
- while ( node.type === Syntax.MemberExpression ) {
665
+ while ( isMemberExpression(node) ) {
540
666
  node = node.object;
541
667
  }
542
668
  if ( node.type === Syntax.Identifier ) {
@@ -604,7 +730,7 @@ function convertValueWithRaw(node, type, propertyName) {
604
730
  raw: node.operator + node.argument.raw
605
731
  };
606
732
 
607
- } else if ( node.type === Syntax.MemberExpression && type ) {
733
+ } else if ( isMemberExpression(node) && type ) {
608
734
 
609
735
  // enum value (a.b.c)
610
736
  value = getResolvedObjectName(node);
@@ -674,6 +800,11 @@ function convertValueWithRaw(node, type, propertyName) {
674
800
  };
675
801
  }
676
802
 
803
+ } else if ( isTemplateLiteralWithoutExpression(node) ) {
804
+ return {
805
+ value: node?.quasis?.[0]?.value?.cooked,
806
+ raw: node?.quasis?.[0]?.value?.raw,
807
+ };
677
808
  }
678
809
 
679
810
  value = "...see text or source";
@@ -697,10 +828,10 @@ function convertStringArray(node) {
697
828
  }
698
829
  const result = [];
699
830
  for ( let i = 0; i < node.elements.length; i++ ) {
700
- if ( node.elements[i].type !== Syntax.Literal || typeof node.elements[i].value !== 'string' ) {
831
+ if ( !isStringLiteral(node.elements[i]) ) {
701
832
  throw new Error("not a string literal");
702
833
  }
703
- result.push(node.elements[i].value);
834
+ result.push( convertValue(node.elements[i]) );
704
835
  }
705
836
  // console.log(result);
706
837
  return result;
@@ -736,7 +867,7 @@ function collectClassInfo(extendCall, classDoclet) {
736
867
  if ( classDoclet && classDoclet.augments && classDoclet.augments.length === 1 ) {
737
868
  baseType = classDoclet.augments[0];
738
869
  }
739
- if ( extendCall.callee.type === Syntax.MemberExpression ) {
870
+ if ( isMemberExpression(extendCall.callee) ) {
740
871
  const baseCandidate = getResolvedObjectName(extendCall.callee.object);
741
872
  if ( baseCandidate && baseType == null ) {
742
873
  baseType = baseCandidate;
@@ -746,7 +877,7 @@ function collectClassInfo(extendCall, classDoclet) {
746
877
  }
747
878
 
748
879
  const oClassInfo = {
749
- name : extendCall.arguments[0].value,
880
+ name : convertValue(extendCall.arguments[0]),
750
881
  baseType : baseType,
751
882
  interfaces : [],
752
883
  doc : classDoclet && classDoclet.description,
@@ -988,7 +1119,7 @@ function collectClassInfo(extendCall, classDoclet) {
988
1119
  return oClassInfo;
989
1120
  }
990
1121
 
991
- function collectDesigntimeInfo(dtNode) {
1122
+ function collectDesigntimeInfo(dtNodeArgument) {
992
1123
 
993
1124
  function each(node, defaultKey, callback) {
994
1125
  const map = node && createPropertyMap(node.value);
@@ -1010,7 +1141,7 @@ function collectDesigntimeInfo(dtNode) {
1010
1141
 
1011
1142
  let oDesigntimeInfo;
1012
1143
 
1013
- const map = createPropertyMap(dtNode.argument);
1144
+ const map = createPropertyMap(dtNodeArgument);
1014
1145
 
1015
1146
  if (map.annotations) {
1016
1147
 
@@ -1095,12 +1226,19 @@ function determineValueRangeBorder(range, expression, varname, inverse) {
1095
1226
  function determineValueRange(expression, varname, inverse) {
1096
1227
  const range = {};
1097
1228
  if ( expression.type === Syntax.LogicalExpression
1098
- && expression.operator === '&&'
1099
1229
  && expression.left.type === Syntax.BinaryExpression
1100
- && expression.right.type === Syntax.BinaryExpression
1101
- && determineValueRangeBorder(range, expression.left, varname, inverse)
1102
- && determineValueRangeBorder(range, expression.right, varname, inverse) ) {
1103
- return range;
1230
+ && expression.right.type === Syntax.BinaryExpression ) {
1231
+
1232
+ if ( expression.operator === "&&"
1233
+ && determineValueRangeBorder(range, expression.left, varname, inverse)
1234
+ && determineValueRangeBorder(range, expression.right, varname, inverse) ) {
1235
+ return range;
1236
+ } else if ( ["||", "??"].includes(expression.operator)
1237
+ && ( determineValueRangeBorder(range, expression.left, varname, inverse)
1238
+ || determineValueRangeBorder(range, expression.right, varname, inverse) )) {
1239
+ return range;
1240
+ }
1241
+
1104
1242
  } else if ( expression.type === Syntax.BinaryExpression
1105
1243
  && determineValueRangeBorder(range, expression, varname, inverse) ) {
1106
1244
  return range;
@@ -1113,24 +1251,24 @@ function collectDataTypeInfo(extendCall, classDoclet) {
1113
1251
  let i = 0,
1114
1252
  name, def, base, pattern, range;
1115
1253
 
1116
- if ( i < args.length && args[i].type === Syntax.Literal && typeof args[i].value === 'string' ) {
1117
- name = args[i++].value;
1254
+ if ( i < args.length && isStringLiteral(args[i]) ) {
1255
+ name = convertValue(args[i++]);
1118
1256
  }
1119
1257
  if ( i < args.length && args[i].type === Syntax.ObjectExpression ) {
1120
1258
  def = createPropertyMap(args[i++]);
1121
1259
  }
1122
1260
  if ( i < args.length ) {
1123
- if ( args[i].type === Syntax.Literal && typeof args[i].value === 'string' ) {
1124
- base = args[i++].value;
1125
- } else if ( args[i].type === Syntax.CallExpression
1126
- && args[i].callee.type === Syntax.MemberExpression
1127
- && getResolvedObjectName(args[i].callee.object) === "sap.ui.base.DataType"
1128
- && args[i].callee.property.type === Syntax.Identifier
1129
- && args[i].callee.property.name === 'getType'
1130
- && args[i].arguments.length === 1
1131
- && args[i].arguments[0].type === Syntax.Literal
1132
- && typeof args[i].arguments[0].value === 'string' ) {
1133
- base = args[i++].arguments[0].value;
1261
+ const node = resolvePotentialWrapperExpression(args[i]);
1262
+
1263
+ if ( isStringLiteral(args[i]) ) {
1264
+ base = convertValue(args[i++]);
1265
+ } else if ( isCaleeMemberExpression(node)
1266
+ && getResolvedObjectName(node.callee.object) === "sap.ui.base.DataType"
1267
+ && node.callee.property.type === Syntax.Identifier
1268
+ && node.callee.property.name === 'getType'
1269
+ && node.arguments.length === 1
1270
+ && isStringLiteral(node.arguments[0]) ) {
1271
+ base = convertValue(args[i++].arguments[0]);
1134
1272
  } else {
1135
1273
  future(`could not identify base type of data type '${name}'`);
1136
1274
  }
@@ -1138,25 +1276,31 @@ function collectDataTypeInfo(extendCall, classDoclet) {
1138
1276
  base = "any";
1139
1277
  }
1140
1278
 
1279
+ const isArrowExpression = isArrowFuncExpression(def && def.isValid && def.isValid.value);
1280
+
1141
1281
  if ( def
1142
1282
  && def.isValid
1143
- && def.isValid.value.type === Syntax.FunctionExpression
1283
+ && [Syntax.FunctionExpression, Syntax.ArrowFunctionExpression].includes(def.isValid.value.type)
1144
1284
  && def.isValid.value.params.length === 1
1145
1285
  && def.isValid.value.params[0].type === Syntax.Identifier
1146
- && def.isValid.value.body.body.length === 1 ) {
1286
+ && (isArrowExpression || def.isValid.value.body.body.length === 1) ) {
1287
+
1147
1288
  const varname = def.isValid.value.params[0].name;
1148
- const stmt = def.isValid.value.body.body[0];
1149
- if ( stmt.type === Syntax.ReturnStatement && stmt.argument ) {
1150
- if ( stmt.argument.type === Syntax.CallExpression
1151
- && stmt.argument.callee.type === Syntax.MemberExpression
1152
- && stmt.argument.callee.object.type === Syntax.Literal
1153
- && stmt.argument.callee.object.regex
1154
- && stmt.argument.callee.property.type === Syntax.Identifier
1155
- && stmt.argument.callee.property.name === 'test' ) {
1156
- pattern = stmt.argument.callee.object.regex.pattern;
1289
+ const stmt = isArrowExpression ? def.isValid.value.body : def.isValid.value.body.body[0];
1290
+
1291
+ if ( isReturningNode(stmt) || isArrowExpression ) {
1292
+ const stmtArgument = resolvePotentialWrapperExpression(
1293
+ isArrowExpression ? stmt : stmt.argument
1294
+ );
1295
+ if ( isCaleeMemberExpression(stmtArgument)
1296
+ && stmtArgument.callee.object.type === Syntax.Literal
1297
+ && stmtArgument.callee.object.regex
1298
+ && stmtArgument.callee.property.type === Syntax.Identifier
1299
+ && stmtArgument.callee.property.name === 'test' ) {
1300
+ pattern = stmtArgument.callee.object.regex.pattern;
1157
1301
  // console.log(pattern);
1158
1302
  } else {
1159
- range = determineValueRange(stmt.argument, varname, false);
1303
+ range = determineValueRange(stmtArgument, varname, false);
1160
1304
  }
1161
1305
  } else if ( stmt.type === Syntax.IfStatement
1162
1306
  && stmt.consequent.type === Syntax.BlockStatement
@@ -1741,7 +1885,7 @@ function createAutoDoc(oClassInfo, classComment, doclet, node, parser, filename,
1741
1885
  newJSDoc([
1742
1886
  "Removes an " + n1 + " from the association named " + link + ".",
1743
1887
  "@param {int | sap.ui.core.ID | " + info.type + "} " + varname(n1, "variant") + " The " + n1 + " to be removed or its index or ID",
1744
- "@returns {sap.ui.core.ID} The removed " + n1 + " or <code>null</code>",
1888
+ "@returns {sap.ui.core.ID|null} The removed " + n1 + " or <code>null</code>",
1745
1889
  info.since ? "@since " + info.since : "",
1746
1890
  info.deprecation ? "@deprecated " + info.deprecation : "",
1747
1891
  info.experimental ? "@experimental " + info.experimental : "",
@@ -2583,24 +2727,37 @@ exports.astNodeVisitor = {
2583
2727
  }
2584
2728
  }
2585
2729
 
2586
- if ( node.type === Syntax.ExpressionStatement ) {
2587
- if ( isSapUiDefineCall(node.expression) ) {
2588
- analyzeModuleDefinition(node.expression);
2589
- /*
2730
+ if ( [Syntax.ExpressionStatement, Syntax.LogicalExpression].includes(node.type) ) {
2731
+ let nodeToAnalyze;
2732
+ if (isSapUiDefineCall(node.expression)) {
2733
+ nodeToAnalyze = node.expression;
2734
+
2735
+ /*
2590
2736
  } else if ( isJQuerySapDeclareCall(node.expression)
2591
2737
  && node.expression.arguments.length > 0
2592
2738
  && node.expression.arguments[0].type === Syntax.Literal
2593
2739
  && typeof node.expression.arguments[0].value === "string" ) {
2594
2740
  warning(`module has explicit module name ${node.expression.arguments[0].value}`);
2595
2741
  */
2742
+ } else if (isSapUiDefineCall(node.left)) {
2743
+ nodeToAnalyze = node.left;
2744
+ } else if (isSapUiDefineCall(node.right)) {
2745
+ nodeToAnalyze = node.right;
2596
2746
  }
2597
2747
 
2748
+ nodeToAnalyze && analyzeModuleDefinition(
2749
+ resolvePotentialWrapperExpression(nodeToAnalyze)
2750
+ );
2598
2751
  }
2599
2752
 
2600
- if (node.type === Syntax.ReturnStatement && node.argument && node.argument.type === Syntax.ObjectExpression && /\.designtime\.js$/.test(currentSourceName) ) {
2753
+ const isArrowExpression = isArrowFuncExpression(node) && node.body.type === Syntax.ObjectExpression;
2754
+ const nodeArgument = isArrowExpression
2755
+ ? node.body
2756
+ : resolvePotentialWrapperExpression(node).argument;
2757
+ if (isArrowExpression || (isReturningNode(node) && nodeArgument && nodeArgument.type === Syntax.ObjectExpression) && /\.designtime\.js$/.test(currentSourceName) ) {
2601
2758
 
2602
2759
  // assume this node to return designtime metadata. Collect it and remember it by its module name
2603
- const oDesigntimeInfo = collectDesigntimeInfo(node);
2760
+ const oDesigntimeInfo = collectDesigntimeInfo(nodeArgument);
2604
2761
  if ( oDesigntimeInfo ) {
2605
2762
  designtimeInfos[currentModule.module] = oDesigntimeInfo;
2606
2763
  info(`collected designtime info ${currentModule.module}`);
@@ -2630,14 +2787,19 @@ exports.astNodeVisitor = {
2630
2787
  }
2631
2788
  });
2632
2789
 
2633
- } else if ( node.type === Syntax.ReturnStatement && isExtendCall(node.argument) ) {
2790
+ } else if ( isReturningNode(node)
2791
+ && isExtendCall(resolvePotentialWrapperExpression(node).argument || node.body) ) {
2792
+
2793
+ const nodeArgument = isArrowFuncExpression(node)
2794
+ ? node.body
2795
+ : resolvePotentialWrapperExpression(node).argument;
2634
2796
 
2635
2797
  // return Something.extend(...)
2636
2798
 
2637
- const className = node.argument.arguments[0].value;
2638
- const comment = getLeadingCommentNode(node, className) || getLeadingCommentNode(node.argument, className);
2799
+ const className = convertValue(nodeArgument.arguments[0]);
2800
+ const comment = getLeadingCommentNode(node, className) || getLeadingCommentNode(nodeArgument, className);
2639
2801
  // console.log(`ast node with comment ${comment}`);
2640
- processExtendCall(node.argument, comment, true);
2802
+ processExtendCall(nodeArgument, comment, true);
2641
2803
  } else if ( node.type === Syntax.ExpressionStatement && node.expression.type === Syntax.AssignmentExpression ) {
2642
2804
 
2643
2805
  if ( isCreateDataTypeCall(node.expression.right) ) {
@@ -2689,7 +2851,8 @@ exports.astNodeVisitor = {
2689
2851
  /*
2690
2852
  * This function has been copied from jsdoc/lib/jsdoc/tag/type (version 3.6.7)
2691
2853
  * The copy has been enhanced with the changes from https://github.com/jsdoc/jsdoc/pull/1735
2692
- * to retain the full function signature for function types.
2854
+ * to retain the full function signature for function types and with a further change
2855
+ * to retain the full record type structure.
2693
2856
  *
2694
2857
  * JSDoc is copyright (c) 2011-present Michael Mathews micmath@gmail.com and the contributors to JSDoc.
2695
2858
  */
@@ -2731,7 +2894,29 @@ exports.astNodeVisitor = {
2731
2894
  // types.push('Object');
2732
2895
  if (Array.isArray(parsedType.fields)) {
2733
2896
  typeString = `{${parsedType.fields.map(
2734
- ({key,value}) => `${catharsis.stringify(key)}: ${toTypeString(value)}`
2897
+ ({key,value}) => {
2898
+ const keyString = catharsis.stringify(key);
2899
+ if (value) {
2900
+ var propertyPlusType = `${keyString}: ${toTypeString(value)}`;
2901
+ return propertyPlusType;
2902
+ } else {
2903
+ let pos;
2904
+ if (keyString && (pos = keyString.indexOf(":")) > -1) {
2905
+ // When no space is present between colon and type (e.g. the structure looks like "{x:number}" with no space after
2906
+ // the colon), then Catharsis parses this as property name "x:number" with no type given.
2907
+ // In this case give a clear hint that this space is needed and throw an error to prevent such issues from being merged
2908
+ const realName = keyString.substring(0, pos);
2909
+ const realValue = keyString.substring(pos + 1, keyString.length);
2910
+ let message = `Cannot parse the "${keyString}" part of "${parsedType.typeExpression}" in RecordType (log output above may give a hint in which file).\n`;
2911
+ message += `Did you mean to specify a property "${realName}" of type "${realValue}"? Then insert a space after the colon and write "${realName}: ${realValue}".`
2912
+ error(message);
2913
+ return "x: any"; // unparseable property set to "any" - but the JSDoc run will fail now, anyway
2914
+ } else {
2915
+ // only property given without type; this will be turned into type "any" further downstream
2916
+ return keyString;
2917
+ }
2918
+ }
2919
+ }
2735
2920
  ).join(', ')}}`;
2736
2921
  types.push(typeString);
2737
2922
  } else {
@@ -2772,7 +2957,9 @@ exports.astNodeVisitor = {
2772
2957
  const origParse = jsdocType.parse;
2773
2958
  jsdocType.parse = function() {
2774
2959
  const tagInfo = origParse.apply(this, arguments);
2775
- if ( tagInfo && /function/.test(tagInfo.typeExpression) && tagInfo.parsedType ) {
2960
+ // #### BEGIN: MODIFIED BY SAP
2961
+ if ( tagInfo && (/function/.test(tagInfo.typeExpression) || /\{.*\}/.test(tagInfo.typeExpression)) && tagInfo.parsedType ) {
2962
+ // #### END: MODIFIED BY SAP
2776
2963
  // console.info("old typeExpression", tagInfo.typeExpression);
2777
2964
  // console.info("old parse tree", tagInfo.parsedType);
2778
2965
  // console.info("old parse result", tagInfo.type);