@sap/cds-compiler 3.4.2 → 3.5.0

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 (143) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +1 -0
  3. package/bin/cds_update_identifiers.js +5 -5
  4. package/bin/cdsc.js +15 -16
  5. package/bin/cdshi.js +19 -6
  6. package/doc/CHANGELOG_ARCHIVE.md +2 -2
  7. package/doc/CHANGELOG_BETA.md +9 -1
  8. package/doc/CHANGELOG_DEPRECATED.md +2 -0
  9. package/lib/api/main.js +61 -59
  10. package/lib/api/options.js +4 -2
  11. package/lib/api/validate.js +2 -2
  12. package/lib/base/cleanSymbols.js +2 -3
  13. package/lib/base/dictionaries.js +6 -6
  14. package/lib/base/error.js +2 -2
  15. package/lib/base/keywords.js +6 -6
  16. package/lib/base/location.js +11 -12
  17. package/lib/base/message-registry.js +177 -58
  18. package/lib/base/messages.js +252 -180
  19. package/lib/base/model.js +14 -11
  20. package/lib/base/node-helpers.js +9 -10
  21. package/lib/base/optionProcessorHelper.js +138 -129
  22. package/lib/checks/.eslintrc.json +2 -0
  23. package/lib/checks/actionsFunctions.js +5 -5
  24. package/lib/checks/annotationsOData.js +4 -4
  25. package/lib/checks/arrayOfs.js +1 -1
  26. package/lib/checks/cdsPersistence.js +1 -1
  27. package/lib/checks/checkForTypes.js +3 -3
  28. package/lib/checks/defaultValues.js +3 -3
  29. package/lib/checks/elements.js +7 -7
  30. package/lib/checks/emptyOrOnlyVirtual.js +2 -2
  31. package/lib/checks/foreignKeys.js +1 -1
  32. package/lib/checks/invalidTarget.js +4 -4
  33. package/lib/checks/managedInType.js +1 -1
  34. package/lib/checks/managedWithoutKeys.js +1 -1
  35. package/lib/checks/nonexpandableStructured.js +5 -3
  36. package/lib/checks/nullableKeys.js +1 -1
  37. package/lib/checks/onConditions.js +5 -6
  38. package/lib/checks/parameters.js +1 -1
  39. package/lib/checks/queryNoDbArtifacts.js +2 -2
  40. package/lib/checks/selectItems.js +4 -4
  41. package/lib/checks/sql-snippets.js +4 -4
  42. package/lib/checks/types.js +7 -7
  43. package/lib/checks/utils.js +4 -4
  44. package/lib/checks/validator.js +16 -13
  45. package/lib/compiler/.eslintrc.json +4 -1
  46. package/lib/compiler/assert-consistency.js +8 -7
  47. package/lib/compiler/builtins.js +14 -14
  48. package/lib/compiler/checks.js +123 -48
  49. package/lib/compiler/define.js +12 -13
  50. package/lib/compiler/extend.js +266 -60
  51. package/lib/compiler/finalize-parse-cdl.js +10 -5
  52. package/lib/compiler/index.js +17 -14
  53. package/lib/compiler/populate.js +14 -6
  54. package/lib/compiler/propagator.js +2 -0
  55. package/lib/compiler/resolve.js +2 -15
  56. package/lib/compiler/shared.js +27 -16
  57. package/lib/compiler/tweak-assocs.js +5 -6
  58. package/lib/compiler/utils.js +20 -0
  59. package/lib/edm/annotations/genericTranslation.js +604 -358
  60. package/lib/edm/annotations/preprocessAnnotations.js +39 -35
  61. package/lib/edm/csn2edm.js +275 -222
  62. package/lib/edm/edm.js +17 -3
  63. package/lib/edm/edmAnnoPreprocessor.js +6 -6
  64. package/lib/edm/edmInboundChecks.js +2 -2
  65. package/lib/edm/edmPreprocessor.js +107 -77
  66. package/lib/edm/edmUtils.js +44 -5
  67. package/lib/gen/Dictionary.json +210 -8
  68. package/lib/gen/language.checksum +1 -1
  69. package/lib/gen/language.interp +67 -63
  70. package/lib/gen/language.tokens +81 -81
  71. package/lib/gen/languageLexer.interp +4 -10
  72. package/lib/gen/languageLexer.js +854 -869
  73. package/lib/gen/languageLexer.tokens +79 -81
  74. package/lib/gen/languageParser.js +14309 -13832
  75. package/lib/inspect/inspectModelStatistics.js +2 -2
  76. package/lib/inspect/inspectPropagation.js +6 -6
  77. package/lib/inspect/inspectUtils.js +2 -2
  78. package/lib/json/from-csn.js +102 -55
  79. package/lib/json/to-csn.js +119 -198
  80. package/lib/language/antlrParser.js +5 -2
  81. package/lib/language/docCommentParser.js +6 -6
  82. package/lib/language/errorStrategy.js +43 -23
  83. package/lib/language/genericAntlrParser.js +113 -133
  84. package/lib/language/language.g4 +1550 -1506
  85. package/lib/language/multiLineStringParser.js +3 -3
  86. package/lib/language/textUtils.js +2 -2
  87. package/lib/main.js +3 -3
  88. package/lib/model/csnRefs.js +5 -0
  89. package/lib/model/csnUtils.js +130 -122
  90. package/lib/model/revealInternalProperties.js +1 -1
  91. package/lib/model/sortViews.js +4 -6
  92. package/lib/modelCompare/compare.js +2 -2
  93. package/lib/modelCompare/utils/.eslintrc.json +22 -0
  94. package/lib/modelCompare/utils/filter.js +100 -0
  95. package/lib/optionProcessor.js +5 -0
  96. package/lib/render/.eslintrc.json +1 -0
  97. package/lib/render/DuplicateChecker.js +1 -1
  98. package/lib/render/manageConstraints.js +12 -12
  99. package/lib/render/toCdl.js +311 -276
  100. package/lib/render/toHdbcds.js +97 -94
  101. package/lib/render/toRename.js +5 -5
  102. package/lib/render/toSql.js +127 -223
  103. package/lib/render/utils/common.js +141 -108
  104. package/lib/render/utils/delta.js +227 -0
  105. package/lib/render/utils/sql.js +22 -6
  106. package/lib/render/utils/stringEscapes.js +3 -3
  107. package/lib/transform/db/.eslintrc.json +2 -0
  108. package/lib/transform/db/applyTransformations.js +3 -3
  109. package/lib/transform/db/assertUnique.js +13 -12
  110. package/lib/transform/db/associations.js +5 -5
  111. package/lib/transform/db/cdsPersistence.js +10 -8
  112. package/lib/transform/db/constraints.js +14 -14
  113. package/lib/transform/db/expansion.js +20 -22
  114. package/lib/transform/db/flattening.js +24 -42
  115. package/lib/transform/db/groupByOrderBy.js +3 -3
  116. package/lib/transform/db/temporal.js +6 -6
  117. package/lib/transform/db/transformExists.js +23 -23
  118. package/lib/transform/db/views.js +16 -16
  119. package/lib/transform/draft/.eslintrc.json +1 -35
  120. package/lib/transform/draft/db.js +10 -10
  121. package/lib/transform/draft/odata.js +2 -2
  122. package/lib/transform/forOdataNew.js +8 -29
  123. package/lib/transform/forRelationalDB.js +16 -6
  124. package/lib/transform/localized.js +11 -10
  125. package/lib/transform/odata/toFinalBaseType.js +41 -27
  126. package/lib/transform/odata/typesExposure.js +113 -47
  127. package/lib/transform/parseExpr.js +209 -106
  128. package/lib/transform/transformUtilsNew.js +17 -10
  129. package/lib/transform/translateAssocsToJoins.js +24 -19
  130. package/lib/transform/universalCsn/coreComputed.js +10 -10
  131. package/lib/transform/universalCsn/universalCsnEnricher.js +26 -26
  132. package/lib/transform/universalCsn/utils.js +3 -3
  133. package/lib/utils/file.js +5 -5
  134. package/lib/utils/moduleResolve.js +13 -13
  135. package/lib/utils/objectUtils.js +6 -6
  136. package/lib/utils/term.js +5 -2
  137. package/lib/utils/timetrace.js +51 -24
  138. package/package.json +5 -8
  139. package/share/messages/check-proper-type-of.md +1 -1
  140. package/share/messages/message-explanations.json +1 -1
  141. package/share/messages/redirected-to-complex.md +4 -4
  142. package/share/messages/{syntax-expecting-integer.md → syntax-expecting-unsigned-int.md} +7 -4
  143. package/lib/modelCompare/filter.js +0 -83
@@ -528,7 +528,7 @@ function fns( model ) {
528
528
  * @param {object} typeArtifact
529
529
  * @param {CSN.Artifact} user
530
530
  */
531
- function resolveTypeArgumentsUnchecked(artifact, typeArtifact, user) {
531
+ function resolveTypeArgumentsUnchecked( artifact, typeArtifact, user ) {
532
532
  let args = artifact.$typeArgs || [];
533
533
  const parameters = typeArtifact.parameters || [];
534
534
 
@@ -572,10 +572,12 @@ function fns( model ) {
572
572
  artifact.$typeArgs = undefined;
573
573
  }
574
574
 
575
- // Return artifact or element referred by name `head`. The first environment
576
- // we search in is `env`. If `unchecked` is equal to `true`, do not report an error
577
- // if the artifact does not exist. Return a "fresh" artifact for
578
- // non-existing external using references if `unchecked` is truthy.
575
+ /**
576
+ * Return artifact or element referred by name `head`. The first environment
577
+ * we search in is `env`. If `unchecked` is equal to `true`, do not report an error
578
+ * if the artifact does not exist. Return a "fresh" artifact for
579
+ * non-existing external using references if `unchecked` is truthy.
580
+ */
579
581
  function getPathRoot( path, spec, user, env, extDict, msgArt ) {
580
582
  const head = path[0];
581
583
  if (!head || !head.id || !env)
@@ -689,14 +691,13 @@ function fns( model ) {
689
691
  // navigation elements (for which you should use a table alias)
690
692
  if (extDict !== model.definitions) {
691
693
  for (const name in extDict) {
692
- const def = extDict[name];
693
- if (!(Array.isArray(def) && def[0].kind === '$navElement'))
694
- e[name] = def;
694
+ if (!spec.dollar || name[0] !== '$')
695
+ e[name] = extDict[name];
695
696
  }
696
697
  }
697
698
  else {
698
699
  for (const name in extDict) {
699
- if (!name.includes('.') && (spec.nodollar || name[0] !== '$'))
700
+ if (!name.includes('.') && (!spec.dollar || name[0] !== '$'))
700
701
  e[name] = extDict[name];
701
702
  }
702
703
  }
@@ -712,8 +713,18 @@ function fns( model ) {
712
713
  signalNotFound( 'ref-undefined-element', [ head.location, user ], valid,
713
714
  { art: searchName( msgArt, head.id, 'element' ) } );
714
715
  }
716
+ else if (head.id[0] === '$') {
717
+ const tableAlias = extDict[head.id]?._parent;
718
+ const alias = tableAlias?.kind === '$tableAlias' ? tableAlias.name?.alias : null;
719
+ signalNotFound( 'ref-undefined-var', [ head.location, user ], valid, {
720
+ '#': alias ? 'alias' : 'std',
721
+ alias,
722
+ id: head.id,
723
+ } );
724
+ }
715
725
  else {
716
- signalNotFound( 'ref-undefined-var', [ head.location, user ], valid, { id: head.id } );
726
+ signalNotFound( 'ref-undefined-element', [ head.location, user ], valid,
727
+ { art: head.id, '#': 'std' } );
717
728
  }
718
729
  }
719
730
  else if (env.$frontend && env.$frontend !== 'cdl' || spec.global) {
@@ -764,7 +775,7 @@ function fns( model ) {
764
775
  return 0;
765
776
  if (art.$uncheckedElements) { // magic variable / replacement variable
766
777
  signalNotFound( 'ref-unknown-var', [ item.location, user ], [ env ],
767
- { id: path.map(n => n.id).join('.') } );
778
+ { id: pathName( path ) } );
768
779
  }
769
780
  else {
770
781
  errorNotFound( item, env );
@@ -873,7 +884,7 @@ function fns( model ) {
873
884
  * @param {object[]} valid
874
885
  * @param {object} [textParams]
875
886
  */
876
- function signalNotFound(msgId, location, valid, textParams ) {
887
+ function signalNotFound( msgId, location, valid, textParams ) {
877
888
  if (location.$notFound)
878
889
  return;
879
890
  location.$notFound = true;
@@ -891,7 +902,7 @@ function fns( model ) {
891
902
  * @param {object} art
892
903
  * @param {any} location
893
904
  */
894
- function signalMissingElementAccess(art, location) {
905
+ function signalMissingElementAccess( art, location ) {
895
906
  const err = message( 'ref-expected-element', location,
896
907
  { '#': 'magicVar', id: art.name.id } );
897
908
  // Mapping for better valid names: from -> $at.from
@@ -909,7 +920,7 @@ function fns( model ) {
909
920
  * @param {CompileMessage} msg CDS Compiler message
910
921
  * @param {...object} validDicts One ore more artifact dictionaries such as in `_block`.
911
922
  */
912
- function attachAndEmitValidNames(msg, ...validDicts) {
923
+ function attachAndEmitValidNames( msg, ...validDicts ) {
913
924
  if (!options.testMode && !options.attachValidNames)
914
925
  return;
915
926
 
@@ -922,7 +933,7 @@ function fns( model ) {
922
933
  msg.validNames[name] = valid[name];
923
934
  }
924
935
 
925
- if (options.testMode) {
936
+ if (options.testMode && !options.$recompile) {
926
937
  // no semantic location => either first of [loc, semantic loc] pair or just location.
927
938
  const loc = msg.location[0] || msg.location;
928
939
  const names = Object.keys(msg.validNames);
@@ -959,7 +970,7 @@ function fns( model ) {
959
970
  // for non-actions. We can't only check for !art.returns, because `action A();` is valid.
960
971
  // `art._block` ensures that `art` is a defined def.
961
972
  warning('anno-unexpected-returns', [ construct.name.location, construct ],
962
- { keyword: 'returns', kind: art.kind }, 'Unexpected $(KEYWORD) for $(KIND)');
973
+ { keyword: 'returns', meta: art.kind }, 'Unexpected $(KEYWORD) for $(META)');
963
974
  }
964
975
  }
965
976
 
@@ -21,7 +21,7 @@ const {
21
21
  } = require('./utils');
22
22
 
23
23
  const $location = Symbol.for('cds.$location');
24
-
24
+ const $inferred = Symbol.for('cds.$inferred');
25
25
 
26
26
  // Export function of this file.
27
27
  function tweakAssocs( model ) {
@@ -242,10 +242,7 @@ function tweakAssocs( model ) {
242
242
  }
243
243
 
244
244
  function inferredForeignKeys( foreignKeys, ignore ) {
245
- // TODO: better use a symbol $inferred for dictionaries later
246
- for (const name in foreignKeys)
247
- return foreignKeys[name].$inferred && foreignKeys[name].$inferred !== ignore;
248
- return false;
245
+ return foreignKeys[$inferred] && foreignKeys[$inferred] !== ignore;
249
246
  }
250
247
 
251
248
  function rewriteKeys( elem, assoc ) {
@@ -255,7 +252,7 @@ function tweakAssocs( model ) {
255
252
  // 'Info','FK').toString())
256
253
  forEachInOrder( assoc, 'foreignKeys', ( orig, name ) => {
257
254
  const fk = linkToOrigin( orig, name, elem, 'foreignKeys', elem.location );
258
- fk.$inferred = 'rewrite'; // TODO: other $inferred value?
255
+ fk.$inferred = 'rewrite'; // Override existing value; TODO: other $inferred value?
259
256
  // TODO: re-check for case that foreign key is managed association
260
257
  if ('_effectiveType' in orig)
261
258
  setLink( fk, '_effectiveType', orig._effectiveType);
@@ -268,6 +265,8 @@ function tweakAssocs( model ) {
268
265
  }
269
266
  fk.targetElement = te;
270
267
  });
268
+ if (elem.foreignKeys) // Possibly no fk was set
269
+ elem.foreignKeys[$inferred] = 'rewrite';
271
270
  }
272
271
 
273
272
  // TODO: there is no need to rewrite the on condition of non-leading queries,
@@ -400,6 +400,24 @@ function setExpandStatus( elem, status ) {
400
400
  }
401
401
  }
402
402
 
403
+ function setExpandStatusAnnotate( elem, status ) {
404
+ for (;;) {
405
+ if (elem.$expand === status)
406
+ return; // already set
407
+ elem.$expand = status; // meaning: expanded, containing annos
408
+ for (let line = elem.items; line; line = line.items)
409
+ line.$expand = status; // to-csn just uses the innermost $expand
410
+ if (!elem._main)
411
+ return;
412
+ elem = elem._parent;
413
+ }
414
+ }
415
+
416
+ function isDirectComposition( art ) {
417
+ const type = art.type && art.type.path;
418
+ return type && type[0] && type[0].id === 'cds.Composition';
419
+ }
420
+
403
421
  module.exports = {
404
422
  pushLink,
405
423
  annotationVal,
@@ -424,4 +442,6 @@ module.exports = {
424
442
  traverseQueryPost,
425
443
  traverseQueryExtra,
426
444
  setExpandStatus,
445
+ setExpandStatusAnnotate,
446
+ isDirectComposition,
427
447
  };