@sap/cds-compiler 4.0.2 → 4.2.2

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 (101) hide show
  1. package/CHANGELOG.md +200 -5
  2. package/bin/cdsc.js +18 -15
  3. package/doc/CHANGELOG_BETA.md +16 -0
  4. package/doc/CHANGELOG_DEPRECATED.md +15 -0
  5. package/lib/api/main.js +33 -13
  6. package/lib/api/options.js +2 -2
  7. package/lib/api/validate.js +25 -25
  8. package/lib/base/location.js +6 -7
  9. package/lib/base/message-registry.js +123 -42
  10. package/lib/base/messages.js +18 -10
  11. package/lib/base/model.js +43 -10
  12. package/lib/checks/defaultValues.js +6 -6
  13. package/lib/checks/elements.js +11 -10
  14. package/lib/checks/foreignKeys.js +0 -5
  15. package/lib/checks/manyNavigations.js +33 -0
  16. package/lib/checks/onConditions.js +22 -14
  17. package/lib/checks/queryNoDbArtifacts.js +132 -73
  18. package/lib/checks/selectItems.js +4 -55
  19. package/lib/checks/sql-snippets.js +15 -4
  20. package/lib/checks/types.js +3 -3
  21. package/lib/checks/utils.js +4 -3
  22. package/lib/checks/validator.js +3 -1
  23. package/lib/compiler/.eslintrc.json +2 -1
  24. package/lib/compiler/assert-consistency.js +71 -40
  25. package/lib/compiler/base.js +7 -2
  26. package/lib/compiler/builtins.js +40 -41
  27. package/lib/compiler/checks.js +415 -367
  28. package/lib/compiler/classes.js +62 -0
  29. package/lib/compiler/cycle-detector.js +9 -9
  30. package/lib/compiler/define.js +124 -90
  31. package/lib/compiler/extend.js +115 -88
  32. package/lib/compiler/finalize-parse-cdl.js +26 -25
  33. package/lib/compiler/generate.js +57 -49
  34. package/lib/compiler/index.js +56 -56
  35. package/lib/compiler/kick-start.js +10 -7
  36. package/lib/compiler/moduleLayers.js +1 -1
  37. package/lib/compiler/populate.js +180 -144
  38. package/lib/compiler/propagator.js +10 -9
  39. package/lib/compiler/resolve.js +321 -246
  40. package/lib/compiler/shared.js +812 -433
  41. package/lib/compiler/tweak-assocs.js +114 -50
  42. package/lib/compiler/utils.js +241 -46
  43. package/lib/edm/.eslintrc.json +40 -1
  44. package/lib/edm/annotations/genericTranslation.js +721 -707
  45. package/lib/edm/annotations/preprocessAnnotations.js +88 -77
  46. package/lib/edm/csn2edm.js +389 -378
  47. package/lib/edm/edm.js +679 -770
  48. package/lib/edm/edmAnnoPreprocessor.js +132 -146
  49. package/lib/edm/edmInboundChecks.js +29 -27
  50. package/lib/edm/edmPreprocessor.js +689 -648
  51. package/lib/edm/edmUtils.js +279 -300
  52. package/lib/gen/Dictionary.json +34 -10
  53. package/lib/gen/language.checksum +1 -1
  54. package/lib/gen/language.interp +1 -1
  55. package/lib/gen/languageParser.js +2857 -2856
  56. package/lib/json/from-csn.js +77 -51
  57. package/lib/json/to-csn.js +15 -15
  58. package/lib/language/antlrParser.js +2 -1
  59. package/lib/language/genericAntlrParser.js +52 -43
  60. package/lib/language/language.g4 +61 -64
  61. package/lib/language/multiLineStringParser.js +2 -0
  62. package/lib/main.d.ts +65 -0
  63. package/lib/model/csnRefs.js +37 -19
  64. package/lib/model/csnUtils.js +51 -18
  65. package/lib/model/revealInternalProperties.js +30 -22
  66. package/lib/modelCompare/compare.js +149 -41
  67. package/lib/modelCompare/utils/filter.js +55 -25
  68. package/lib/optionProcessor.js +21 -9
  69. package/lib/render/manageConstraints.js +20 -17
  70. package/lib/render/toCdl.js +63 -23
  71. package/lib/render/toHdbcds.js +2 -2
  72. package/lib/render/toRename.js +4 -9
  73. package/lib/render/toSql.js +82 -35
  74. package/lib/render/utils/common.js +11 -9
  75. package/lib/render/utils/unique.js +52 -0
  76. package/lib/transform/db/applyTransformations.js +62 -21
  77. package/lib/transform/db/assertUnique.js +7 -8
  78. package/lib/transform/db/associations.js +2 -2
  79. package/lib/transform/db/cdsPersistence.js +9 -9
  80. package/lib/transform/db/constraints.js +47 -17
  81. package/lib/transform/db/expansion.js +138 -68
  82. package/lib/transform/db/flattening.js +98 -30
  83. package/lib/transform/db/rewriteCalculatedElements.js +20 -14
  84. package/lib/transform/db/temporal.js +1 -1
  85. package/lib/transform/db/transformExists.js +8 -7
  86. package/lib/transform/db/views.js +73 -33
  87. package/lib/transform/draft/db.js +11 -9
  88. package/lib/transform/draft/odata.js +1 -1
  89. package/lib/transform/{forOdataNew.js → forOdata.js} +10 -7
  90. package/lib/transform/forRelationalDB.js +148 -136
  91. package/lib/transform/localized.js +92 -54
  92. package/lib/transform/odata/toFinalBaseType.js +3 -3
  93. package/lib/transform/{transformUtilsNew.js → transformUtils.js} +13 -111
  94. package/lib/transform/translateAssocsToJoins.js +14 -28
  95. package/lib/utils/file.js +7 -7
  96. package/lib/utils/moduleResolve.js +210 -121
  97. package/lib/utils/objectUtils.js +1 -1
  98. package/package.json +5 -5
  99. package/share/messages/check-proper-type-of.md +1 -1
  100. package/share/messages/{check-proper-type.md → def-missing-type.md} +3 -5
  101. package/share/messages/message-explanations.json +1 -1
@@ -216,7 +216,7 @@ usingProxy[ outer, proxy ]
216
216
  )
217
217
  ;
218
218
 
219
- artifactDefOrExtend[ outer, defOnly = false ] locals[ art = {} ] // cannot use `parent` as parameter name!
219
+ artifactDefOrExtend[ outer, defOnly = false ] locals[ art = new parser.XsnArtifact() ] // cannot use `parent` as parameter name!
220
220
  @after{ /* #ATN 1 */ }
221
221
  :
222
222
  { $art.location = this.startLocation(); this.docComment( $art ); }
@@ -285,13 +285,13 @@ optionalSemi
285
285
 
286
286
  // Annotation def and main definitions ------------------------------------------
287
287
 
288
- annotationDef[ art, outer ] locals[ name = {} ]
288
+ annotationDef[ art, outer ] locals[ name = new parser.XsnName() ]
289
289
  @after { this.attachLocation( $art ); }
290
290
  :
291
291
  annotation=ANNOTATION simplePath[ $name, 'AnnoDef' ]
292
292
  { if ($outer.kind !== 'source') { // this is a syntax restriction to avoid confusion
293
293
  this.error( 'syntax-unexpected-vocabulary', $annotation, { '#': $outer.kind } );
294
- $art = {}; }
294
+ $art = new this.XsnArtifact(); }
295
295
  else {
296
296
  if (!$outer.vocabularies) $outer.vocabularies = Object.create(null);
297
297
  this.addDef( $art, $outer, 'vocabularies', 'annotation', $name );
@@ -301,7 +301,7 @@ annotationDef[ art, outer ] locals[ name = {} ]
301
301
  typeSpecSemi[ $art ] // also 'includes'...
302
302
  ;
303
303
 
304
- serviceDef[ art, outer, defOnly = false ] locals[ name = {} ]
304
+ serviceDef[ art, outer, defOnly = false ] locals[ name = new parser.XsnName(); ]
305
305
  @after { this.attachLocation( $art ); }
306
306
  :
307
307
  SERVICE simplePath[ $name, 'Service' ]
@@ -309,7 +309,7 @@ serviceDef[ art, outer, defOnly = false ] locals[ name = {} ]
309
309
  optArtifactsBlock[ $art, defOnly ]
310
310
  ;
311
311
 
312
- contextDef[ art, outer, defOnly = false ] locals[ name = {} ]
312
+ contextDef[ art, outer, defOnly = false ] locals[ name = new parser.XsnName(); ]
313
313
  @after { this.attachLocation( $art ); }
314
314
  :
315
315
  CONTEXT simplePath[ $name, 'Context' ]
@@ -317,7 +317,7 @@ contextDef[ art, outer, defOnly = false ] locals[ name = {} ]
317
317
  optArtifactsBlock[ $art, defOnly ]
318
318
  ;
319
319
 
320
- eventDef[ art, outer ] locals[ name = {} ]
320
+ eventDef[ art, outer ] locals[ name = new parser.XsnName(); ]
321
321
  @after { /* #ATN 1 */ this.attachLocation( $art ); }
322
322
  :
323
323
  EVENT simplePath[ $name, 'Event' ]
@@ -353,7 +353,7 @@ eventDef[ art, outer ] locals[ name = {} ]
353
353
  )
354
354
  ;
355
355
 
356
- viewDef[ art, outer ] locals[ name = {} ]
356
+ viewDef[ art, outer ] locals[ name = new parser.XsnName(); ]
357
357
  @after { this.attachLocation( $art ); }
358
358
  :
359
359
  v=VIEW simplePath[ $name, 'Entity' ]
@@ -376,7 +376,7 @@ viewDef[ art, outer ] locals[ name = {} ]
376
376
  requiredSemi
377
377
  ;
378
378
 
379
- entityDef[ art, outer ] locals[ name = {} ]
379
+ entityDef[ art, outer ] locals[ name = new parser.XsnName() ]
380
380
  @after { this.attachLocation( $art ); }
381
381
  :
382
382
  ENTITY simplePath[ $name, 'Entity' ]
@@ -424,7 +424,7 @@ entityDef[ art, outer ] locals[ name = {} ]
424
424
  )
425
425
  ;
426
426
 
427
- aspectDef[ art, outer ] locals[ name = {} ]
427
+ aspectDef[ art, outer ] locals[ name = new parser.XsnName() ]
428
428
  @after { this.attachLocation( $art ); }
429
429
  :
430
430
  ( ASPECT | ( abs=ABSTRACT | HideAlternatives ) ent=ENTITY )
@@ -453,12 +453,11 @@ aspectDef[ art, outer ] locals[ name = {} ]
453
453
  )?
454
454
  optionalSemi
455
455
  | // `aspect MyAspect;`, e.g. for annotation aspects.
456
- { this.aspectWithoutElements( $art ); }
457
456
  requiredSemi
458
457
  )
459
458
  ;
460
459
 
461
- typeDef[ art, outer ] locals[ name = {} ]
460
+ typeDef[ art, outer ] locals[ name = new parser.XsnName() ]
462
461
  @after { this.attachLocation( $art ); }
463
462
  :
464
463
  TYPE simplePath[ $name, 'Type' ]
@@ -468,7 +467,7 @@ typeDef[ art, outer ] locals[ name = {} ]
468
467
  typeSpecSemi[ $art ]
469
468
  ;
470
469
 
471
- actionFunctionMainDef[ art, outer ] locals[ name = {} ]
470
+ actionFunctionMainDef[ art, outer ] locals[ name = new parser.XsnName() ]
472
471
  @after { this.attachLocation( $art ); }
473
472
  :
474
473
  ACTION simplePath[ $name, 'Action' ]
@@ -488,7 +487,7 @@ actionFunctionMainDef[ art, outer ] locals[ name = {} ]
488
487
 
489
488
  // Member definitions: actions, elements, enums, parameters: --------------------
490
489
 
491
- actionFunctionDef[ outer ] locals[ art = {} ]
490
+ actionFunctionDef[ outer ] locals[ art = new parser.XsnArtifact() ]
492
491
  @after { this.attachLocation( $art ); }
493
492
  :
494
493
  { $art.location = this.startLocation();; this.docComment( $art ); }
@@ -510,7 +509,7 @@ actionFunctionDef[ outer ] locals[ art = {} ]
510
509
  )
511
510
  ;
512
511
 
513
- parameterDef[ outer ] locals[ art = {} ]
512
+ parameterDef[ outer ] locals[ art = new parser.XsnArtifact() ]
514
513
  @after { this.attachLocation( $art ); }
515
514
  :
516
515
  { this.meltKeywordToIdentifier();; this.docComment( $art ); }
@@ -546,7 +545,7 @@ parameterListDef[ art ]
546
545
  ')' { this.finalizeDictOrArray( $art.params ); }
547
546
  ;
548
547
 
549
- enumSymbolDef[ outer ] locals[ art = {} ]
548
+ enumSymbolDef[ outer ] locals[ art = new parser.XsnArtifact() ]
550
549
  @after { this.attachLocation( $art ); }
551
550
  :
552
551
  { $art.location = this.startLocation();; this.docComment( $art ); }
@@ -570,14 +569,14 @@ enumSymbolDef[ outer ] locals[ art = {} ]
570
569
  requiredSemi
571
570
  ;
572
571
 
573
- elementDef[ outer ] locals[ $art = {} ]
572
+ elementDef[ outer ] locals[ $art = new parser.XsnArtifact() ]
574
573
  :
575
574
  { $art.location = this.startLocation();; this.docComment( $art ); }
576
575
  annotationAssignment_ll1[ $art ]*
577
- elementDefInner[ $art, $outer, false ]
576
+ elementDefInner[ $art, $outer ]
578
577
  ;
579
578
 
580
- elementDefInner[ art, outer, mightBeEnum ]
579
+ elementDefInner[ art, outer, explicitElement = false ]
581
580
  @after{ this.attachLocation( $art ); }
582
581
  :
583
582
  // VIRTUAL is keyword, except if before the following tokens texts:
@@ -592,7 +591,7 @@ elementDefInner[ art, outer, mightBeEnum ]
592
591
  }
593
592
  )?
594
593
  { this.setLocalToken( 'ELEMENT', 'ELEMENT', /^[;:{@=}]$/ ); }
595
- ( ELEMENT { $mightBeEnum = false; } )? // auto-recognizable at other places
594
+ ( ELEMENT { $explicitElement = true; } )? // auto-recognizable at other places
596
595
  name=ident['Element']
597
596
  { this.addDef( $art, $outer, 'elements', 'element', $name.id );
598
597
  this.docComment( $art ); }
@@ -605,7 +604,7 @@ elementDefInner[ art, outer, mightBeEnum ]
605
604
  )
606
605
  |
607
606
  ':'
608
- elementType[ $art, $mightBeEnum ]
607
+ elementType[ $art ]
609
608
  |
610
609
  eq='=' e=expression // SQL has syntax variant using AS - we DO NOT
611
610
  stored=STORED?
@@ -613,10 +612,8 @@ elementDefInner[ art, outer, mightBeEnum ]
613
612
  // this.setIntroLocation( eq ); -- future
614
613
  if ($stored)
615
614
  $art.value.stored = this.valueWithTokenLocation( true, $stored );
616
- if ($mightBeEnum && !$stored &&
617
- ($e.expr?.val !== undefined || $e.expr?.sym !== undefined) &&
618
- !$virtual && !$key && !$masked && !$art.elements && !$art.type)
619
- $art['$'+'syntax'] = 'enum';
615
+ if ($explicitElement)
616
+ $art['$'+'syntax'] = 'element';
620
617
  }
621
618
  { this.docComment( $art ); }
622
619
  annotationAssignment_ll1[ $art ]* // for enum symbol def via EXTEND
@@ -750,7 +747,7 @@ defaultValue[ art ] locals[ elem, elements = {} ]
750
747
 
751
748
  // Extend and annotate ----------------------------------------------------------
752
749
 
753
- extendArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
750
+ extendArtifact[ art, outer ] locals[ name = new parser.XsnName(), elemName = new parser.XsnName() ]
754
751
  @after{ /* #ATN 1 */ this.attachLocation( $art ); }
755
752
  :
756
753
  simplePath[ $name, 'Extend' ]
@@ -771,7 +768,7 @@ extendArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
771
768
  (
772
769
  // all the alternatives from `extendWithOptElementsOrType` --------------
773
770
  '{' { $art.elements = this.createDict(); }
774
- elementDefOrExtend[ $art, true ]*
771
+ elementDefOrExtend[ $art ]*
775
772
  '}' { this.finalizeDictOrArray( $art.elements ); }
776
773
  { this.checkExtensionDict( $art.elements ); }
777
774
  optionalSemi
@@ -779,7 +776,7 @@ extendArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
779
776
  requiredSemi
780
777
  |
781
778
  ELEMENTS { $art.elements = this.createDict(); } '{'
782
- elementDefOrExtend[ $art ]*
779
+ elementDefOrExtend[ $art, true ]*
783
780
  '}' { this.finalizeDictOrArray( $art.elements ); }
784
781
  { this.checkExtensionDict( $art.elements ); }
785
782
  optionalSemi
@@ -823,7 +820,7 @@ extendArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
823
820
  )
824
821
  ;
825
822
 
826
- extendService[ art, outer ] locals[ name = {} ]
823
+ extendService[ art, outer ] locals[ name = new parser.XsnName() ]
827
824
  @after { this.attachLocation( $art ); }
828
825
  :
829
826
  SERVICE { $art.expectedKind = this.valueWithTokenLocation(); }
@@ -833,7 +830,7 @@ extendService[ art, outer ] locals[ name = {} ]
833
830
  optArtifactsBlock[ art, 'service' ]
834
831
  ;
835
832
 
836
- extendContext[ art, outer ] locals[ name = {} ]
833
+ extendContext[ art, outer ] locals[ name = new parser.XsnName() ]
837
834
  @after { this.attachLocation( $art ); }
838
835
  :
839
836
  CONTEXT { $art.expectedKind = this.valueWithTokenLocation(); }
@@ -843,7 +840,7 @@ extendContext[ art, outer ] locals[ name = {} ]
843
840
  optArtifactsBlock[ art, 'context' ]
844
841
  ;
845
842
 
846
- extendEntityOrAspect[ art, outer ] locals[ name = {} ]
843
+ extendEntityOrAspect[ art, outer ] locals[ name = new parser.XsnName() ]
847
844
  @after { /* #ATN 1 */ this.attachLocation( $art ); }
848
845
  :
849
846
  (ASPECT | ENTITY) { $art.expectedKind = this.valueWithTokenLocation(); }
@@ -888,7 +885,7 @@ extendForEntity[ art ]
888
885
  requiredSemi
889
886
  ;
890
887
 
891
- extendProjection[ art, outer ] locals[ name = {} ]
888
+ extendProjection[ art, outer ] locals[ name = new parser.XsnName() ]
892
889
  @after { this.attachLocation( $art ); }
893
890
  :
894
891
  PROJECTION { $art.expectedKind = this.valueWithTokenLocation( 'entity' ); }
@@ -924,7 +921,7 @@ extendProjection[ art, outer ] locals[ name = {} ]
924
921
  )
925
922
  ;
926
923
 
927
- extendType[ art, outer ] locals[ name = {} ]
924
+ extendType[ art, outer ] locals[ name = new parser.XsnName() ]
928
925
  @after { this.attachLocation( $art ); }
929
926
  :
930
927
  TYPE { $art.expectedKind = this.valueWithTokenLocation(); }
@@ -940,7 +937,7 @@ extendType[ art, outer ] locals[ name = {} ]
940
937
  annotationAssignment_ll1[ $art ]*
941
938
  (
942
939
  '{' { $art.elements = this.createDict(); }
943
- elementDefOrExtend[ $art, true ]*
940
+ elementDefOrExtend[ $art ]*
944
941
  '}' { this.finalizeDictOrArray( $art.elements ); }
945
942
  { this.checkExtensionDict( $art.elements ); }
946
943
  optionalSemi
@@ -965,13 +962,13 @@ extendWithOptElementsOrType[ art ]
965
962
  annotationAssignment_ll1[ $art ]*
966
963
  (
967
964
  '{' { $art.elements = this.createDict(); }
968
- elementDefOrExtend[ $art, true ]*
965
+ elementDefOrExtend[ $art ]*
969
966
  '}' { this.finalizeDictOrArray( $art.elements ); }
970
967
  { this.checkExtensionDict( $art.elements ); }
971
968
  optionalSemi
972
969
  |
973
970
  ELEMENTS { $art.elements = this.createDict(); } '{'
974
- elementDefOrExtend[ $art ]*
971
+ elementDefOrExtend[ $art, true ]*
975
972
  '}' { this.finalizeDictOrArray( $art.elements ); }
976
973
  { this.checkExtensionDict( $art.elements ); }
977
974
  optionalSemi
@@ -995,7 +992,7 @@ extendWithOptElementsNoWith[ art ]
995
992
  annotationAssignment_ll1[ $art ]*
996
993
  (
997
994
  '{' { $art.elements = this.createDict(); }
998
- elementDefOrExtend[ $art, true ]*
995
+ elementDefOrExtend[ $art ]*
999
996
  '}' { this.finalizeDictOrArray( $art.elements ); }
1000
997
  { this.checkExtensionDict( $art.elements ); }
1001
998
  optionalSemi
@@ -1006,7 +1003,7 @@ extendWithOptElementsNoWith[ art ]
1006
1003
 
1007
1004
  // For `extend … with elements` or `extend entity … with`, `extend aspect … with`,
1008
1005
  // i.e. definitions in { … } are never enums
1009
- elementDefOrExtend[ outer, mightBeEnum = false ] locals[ art = {} ]
1006
+ elementDefOrExtend[ outer, explicitElement = false ] locals[ art = new parser.XsnArtifact() ]
1010
1007
  @after { /* #ATN 1 */ } // if ($art) this.attachLocation( $art ); }
1011
1008
  :
1012
1009
  { $art.location = this.startLocation();; this.docComment( $art ); }
@@ -1016,7 +1013,7 @@ elementDefOrExtend[ outer, mightBeEnum = false ] locals[ art = {} ]
1016
1013
  EXTEND
1017
1014
  extendElement[ $art, $outer ]
1018
1015
  |
1019
- elementDefInner[ $art, $outer, $mightBeEnum ]
1016
+ elementDefInner[ $art, $outer, $explicitElement ]
1020
1017
  )
1021
1018
  ;
1022
1019
 
@@ -1030,7 +1027,7 @@ extendElement[ art, outer ]
1030
1027
  extendWithOptElementsOrType[ $art, $art ]
1031
1028
  ;
1032
1029
 
1033
- annotateArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
1030
+ annotateArtifact[ art, outer ] locals[ name = new parser.XsnName(), elemName = new parser.XsnName() ]
1034
1031
  @after { this.attachLocation( $art ); }
1035
1032
  :
1036
1033
  simplePath[ $name, 'Annotate' ]
@@ -1090,7 +1087,7 @@ annotateArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
1090
1087
  )
1091
1088
  ;
1092
1089
 
1093
- annotateElement[ outer ] locals[ art = {} ]
1090
+ annotateElement[ outer ] locals[ art = new parser.XsnArtifact() ]
1094
1091
  @after{ this.attachLocation( $art ); }
1095
1092
  :
1096
1093
  { $art.location = this.startLocation();; this.docComment( $art ); }
@@ -1110,7 +1107,7 @@ annotateElement[ outer ] locals[ art = {} ]
1110
1107
  )
1111
1108
  ;
1112
1109
 
1113
- annotateAction [ outer ] locals [ art = {} ]
1110
+ annotateAction [ outer ] locals [ art = new parser.XsnArtifact() ]
1114
1111
  @after{ this.attachLocation( $art ); }
1115
1112
  :
1116
1113
  { $art.location = this.startLocation();; this.docComment( $art ); }
@@ -1138,7 +1135,7 @@ annotateAction [ outer ] locals [ art = {} ]
1138
1135
  annotateReturns[ art ]
1139
1136
  @after{ this.attachLocation( $art.returns ); }
1140
1137
  :
1141
- ret=RETURNS { $art.returns = { kind: 'annotate' }; }
1138
+ ret=RETURNS { $art.returns = new this.XsnArtifact();; $art.returns.kind = 'annotate'; }
1142
1139
  { this.docComment( $art.returns ); }
1143
1140
  annotationAssignment_ll1[ $art.returns ]*
1144
1141
  ( '{' { $art.returns.elements = this.createDict(); }
@@ -1150,7 +1147,7 @@ annotateReturns[ art ]
1150
1147
  )
1151
1148
  ;
1152
1149
 
1153
- annotateParam [ outer ] locals [ art = {} ]
1150
+ annotateParam [ outer ] locals [ art = new parser.XsnArtifact() ]
1154
1151
  @after{ this.attachLocation( $art ); }
1155
1152
  :
1156
1153
  { $art.location = this.startLocation();; this.docComment( $art ); }
@@ -1424,9 +1421,12 @@ typeAssociationCont[ art ]
1424
1421
  )*
1425
1422
  )?
1426
1423
  '}' { this.finalizeDictOrArray( $art.foreignKeys ); }
1424
+ defaultAndNullability[ $art ]?
1427
1425
  |
1428
1426
  ON cond=condition
1429
1427
  { $art.on=$cond.cond; }
1428
+ |
1429
+ defaultAndNullability[ $art ]
1430
1430
  )
1431
1431
  ;
1432
1432
 
@@ -1442,12 +1442,12 @@ typeAssociationElementCont[ art ] // including Composition
1442
1442
  )*
1443
1443
  )?
1444
1444
  '}' { this.finalizeDictOrArray( $art.foreignKeys ); }
1445
- nullability[ $art ]?
1445
+ defaultAndNullability[ $art ]?
1446
1446
  |
1447
1447
  ON cond=condition
1448
1448
  { $art.on=$cond.cond; }
1449
1449
  |
1450
- nullability[ $art ]
1450
+ defaultAndNullability[ $art ]
1451
1451
  )?
1452
1452
  { this.docComment( $art ); }
1453
1453
  annotationAssignment_ll1[ $art ]*
@@ -1515,7 +1515,7 @@ nullability[ art ]
1515
1515
  | n1=NULL
1516
1516
  ;
1517
1517
 
1518
- foreignKey[ outer ] locals[ art = {}, elem = {} ]
1518
+ foreignKey[ outer ] locals[ art = new parser.XsnArtifact(), elem = {} ]
1519
1519
  @after { this.attachLocation($art); }
1520
1520
  :
1521
1521
  simplePath[ $elem, 'ref' ] { $art.targetElement = $elem; }
@@ -1784,7 +1784,7 @@ tableTerm returns [ table ]
1784
1784
  }
1785
1785
  ':' fromPath[ $table, 'ref']
1786
1786
  )?
1787
- ( AS n1=ident['FromAlias'] { $table.name = $n1.id }
1787
+ ( AS n1=ident['FromAlias'] { $table.name = $n1.id; }
1788
1788
  | n2=identNoKeyword['FromAlias'] { $table.name = this.fragileAlias( $n2.id ); }
1789
1789
  // if we would use rule `ident`, we would either had to make all JOIN
1790
1790
  // kinds reserved or introduce ATN
@@ -1823,7 +1823,7 @@ fromPath[ qp, idkind ] returns[ dotAfterFilter = null ]
1823
1823
  if (!$qp.scope) $qp.scope = $qp.path.length;
1824
1824
  } }
1825
1825
  '.' id=ident[$idkind] { this.pushIdent( $qp.path, $id.id ); }
1826
- ( fromArguments[ $id.id ] cardinalityAndFilter[ $id.id ]?
1826
+ ( fromArguments[ $id.id ] cardinalityAndFilter[ $id.id ]?
1827
1827
  { if (!$dotAfterFilter) $dotAfterFilter = false; }
1828
1828
  | cardinalityAndFilter[ $id.id ]
1829
1829
  { if (!$dotAfterFilter) $dotAfterFilter = false; }
@@ -1887,7 +1887,7 @@ selectItemDef[ outer ] locals[ art ]
1887
1887
  star='*'
1888
1888
  { $outer.push( this.valueWithTokenLocation( '*', $star ) ); }
1889
1889
  |
1890
- { $art = {};; this.docComment( $art ); }
1890
+ { $art = new this.XsnArtifact();; this.docComment( $art ); }
1891
1891
  annotationAssignment_atn[ $art ]*
1892
1892
  // VIRTUAL is keyword, except if before the following tokens texts:
1893
1893
  { this.setLocalToken( 'VIRTUAL', 'VIRTUAL', /^([,.:\[@]|as)$/i ) ; } // not '{'
@@ -1904,7 +1904,7 @@ selectItemDefBody[ art, outer ] locals[ assoc ]
1904
1904
  e=expression { $art.value = $e.expr; }
1905
1905
  // we cannot use 'condition' instead, as long as we allow aliases without
1906
1906
  // AS (using rule 'ident' instead of 'identNoKeyword') -> ambiguities
1907
- ( as=AS n1=ident['Item'] { $art.name = $n1.id }
1907
+ ( as=AS n1=ident['Item'] { $art.name = $n1.id; }
1908
1908
  | n2=ident['Item'] { $art.name = this.fragileAlias( $n2.id, true ); }
1909
1909
  | { this.classifyImplicitName( 'Item', $e.expr ); }
1910
1910
  )
@@ -1929,7 +1929,7 @@ selectItemDefBody[ art, outer ] locals[ assoc ]
1929
1929
  |
1930
1930
  selectItemInlineList[ $art, 'expand' ]
1931
1931
  excludingClause[ $art ]?
1932
- AS n1=ident['Item'] { $art.name = $n1.id }
1932
+ AS n1=ident['Item'] { $art.name = $n1.id; }
1933
1933
  )
1934
1934
  { this.docComment( $art ); }
1935
1935
  annotationAssignment_fix[ $art ]*
@@ -1995,7 +1995,7 @@ selectItemInlineDef[ outer ] locals[ art ]
1995
1995
  star='*'
1996
1996
  { $outer.push( this.valueWithTokenLocation( '*', $star ) ); }
1997
1997
  |
1998
- { $art = {};; this.docComment( $art ); }
1998
+ { $art = new this.XsnArtifact();; this.docComment( $art ); }
1999
1999
  annotationAssignment_atn[ $art ]*
2000
2000
  selectItemDefBody[ $art, $outer ]
2001
2001
  ;
@@ -2010,11 +2010,8 @@ orderByClause[ inQuery ] returns [ query ]
2010
2010
  limitClause[ inQuery ] returns [ query ]
2011
2011
  :
2012
2012
  limkw=LIMIT { $query = this.unaryOpForParens( $inQuery, '$'+'query' ); }
2013
- ( lim=Number { $query.limit = { rows: this.numberLiteral( $lim, '' ) }; }
2014
- | limnull=NULL { $query.limit = { rows: {
2015
- literal: 'null', val: null, location: this.tokenLocation($limnull) } }; }
2016
- )
2017
- ( OFFSET off=Number { $query.limit.offset = this.numberLiteral( $off ); } )? // unsigned integer
2013
+ lim=expression { $query.limit = { rows: $lim.expr }; }
2014
+ ( OFFSET off=expression { $query.limit.offset = $off.expr; } )? // unsigned integer
2018
2015
  ;
2019
2016
 
2020
2017
  orderBySpec returns[ ob ]
@@ -2312,7 +2309,7 @@ expressionTerm returns [ expr ] locals [ args = [] ]
2312
2309
  )
2313
2310
  ;
2314
2311
 
2315
- specialFunction returns [ ret = {} ] locals[ art = {} ]
2312
+ specialFunction returns [ ret = {} ] locals[ art = new parser.XsnArtifact() ]
2316
2313
  :
2317
2314
  ca=CAST '(' // see createArray() in action
2318
2315
  {
@@ -2663,7 +2660,7 @@ annotationAssignment_fix[ art ] locals[ assignment ]
2663
2660
  (
2664
2661
  annotationAssignment_paren[ $art ]
2665
2662
  |
2666
- { $assignment = { name: {} }; }
2663
+ { $assignment = { name: new this.XsnName() }; }
2667
2664
  annotationPath[ $assignment.name, 'anno' ]
2668
2665
  ( '#' annotationPathVariant[ $assignment.name ] )?
2669
2666
  { this.warnIfColonFollows( $assignment ); }
@@ -2681,7 +2678,7 @@ annotationAssignment_ll1[ art ] locals[ assignment ]
2681
2678
  (
2682
2679
  annotationAssignment_paren[ $art ]
2683
2680
  |
2684
- { $assignment = { name: {} }; }
2681
+ { $assignment = { name: new this.XsnName() }; }
2685
2682
  annotationPath[ $assignment.name, 'anno' ]
2686
2683
  ( '#' annotationPathVariant[ $assignment.name ] )?
2687
2684
  (
@@ -2703,7 +2700,7 @@ annotationAssignment_atn[ art ] locals[ assignment ]
2703
2700
  (
2704
2701
  annotationAssignment_paren[ $art ]
2705
2702
  |
2706
- { $assignment = { name: {} }; }
2703
+ { $assignment = { name: new this.XsnName() }; }
2707
2704
  annotationPath[ $assignment.name, 'anno' ]
2708
2705
  // '#' is in the follow set of this rule, as it is used in rule "selectItemDef"
2709
2706
  // before an "expression" which can start with a '#' for an enum value
@@ -2749,7 +2746,7 @@ annotationAssignment_paren[ art ]
2749
2746
  ')'
2750
2747
  ;
2751
2748
 
2752
- annotationAssignment_1[ art ] locals[ assignment = { name: {} } ]
2749
+ annotationAssignment_1[ art ] locals[ assignment = { name: new parser.XsnName() } ]
2753
2750
  @after { this.assignAnnotation( $art, $assignment ); }
2754
2751
  :
2755
2752
  annotationPath[ $assignment.name, 'anno' ]
@@ -2865,7 +2862,7 @@ annoValueBase[ assignment ] locals [ seenEllipsis = false ]
2865
2862
  ')'
2866
2863
  ;
2867
2864
 
2868
- flattenedValue[ assignment ] locals[ val = { name: {} } ]
2865
+ flattenedValue[ assignment ] locals[ val = { name: new parser.XsnName() } ]
2869
2866
  :
2870
2867
  at='@'? annotationPath[ $val.name, 'name', $at ]
2871
2868
  ( '#' annotationPathVariant[ $val.name ] )?
@@ -2876,7 +2873,7 @@ flattenedValue[ assignment ] locals[ val = { name: {} } ]
2876
2873
  { $assignment['$'+'flatten'].push( $val ); }
2877
2874
  ;
2878
2875
 
2879
- namedValue[ struct ] locals[ val = { name: {} } ]
2876
+ namedValue[ struct ] locals[ val = { name: new parser.XsnName() } ]
2880
2877
  :
2881
2878
  at='@'? annotationPath[ $val.name, 'name', $at ]
2882
2879
  ( ':' { this.meltKeywordToIdentifier(true); }
@@ -6,6 +6,7 @@ const {
6
6
  cdlNewLineRegEx,
7
7
  } = require('./textUtils');
8
8
  const { CompilerAssertion } = require('../base/error');
9
+ const { CsnLocation } = require('../compiler/classes');
9
10
 
10
11
  /**
11
12
  * Strips and counts the indentation from the given string.
@@ -462,6 +463,7 @@ class MultiLineStringParser {
462
463
  */
463
464
  _locationForCharacters(i, width) {
464
465
  return {
466
+ __proto__: CsnLocation.prototype,
465
467
  file: this.parser.filename,
466
468
  line: this.token.line + this._lineInString,
467
469
  endLine: this.token.line + this._lineInString,
package/lib/main.d.ts CHANGED
@@ -70,6 +70,18 @@ declare namespace compiler {
70
70
  * - universal : In development (BETA)
71
71
  */
72
72
  csnFlavor?: string | 'client' | 'gensrc' | 'universal'
73
+ /**
74
+ * If set, backends will not create localized convenience views for those views,
75
+ * that only have an association to a localized entity/view. Views will only get
76
+ * a convenience view, if they themselves contain localized elements (i.e. either
77
+ * have simple projection on localized elements and CDL-casts to a localized element).
78
+ *
79
+ * The OData backend will not set `$localized: true` markers for such cases.
80
+ *
81
+ * Does not work for backends to.hdi(), to.hdbcds() or to.sql() with `sqlDialect: 'hana'`,
82
+ * since in all those dialects, associations still exist in generated artifacts.
83
+ */
84
+ fewerLocalizedViews?: boolean
73
85
  }
74
86
 
75
87
  /**
@@ -86,6 +98,30 @@ declare namespace compiler {
86
98
  * the prefix for SAP CDS packages / CDS files.
87
99
  */
88
100
  cdsHome?: string
101
+ /**
102
+ * "Doc comments" (documentation comments) are those comments starting with `/**` in CDL
103
+ * or the `doc` property in CSN. This option is an _output_ option, which can have three
104
+ * values:
105
+ *
106
+ * - `true`:
107
+ * Doc comments will appear in the compiled CSN. Basic sanity checks are performed:
108
+ * In CDL, if a doc comment appears at a not-defined position, where it has no impact,
109
+ * an info message is emitted. For CSN input, it is checked that the `doc` property
110
+ * is a string or `null`.
111
+ *
112
+ * - `false`:
113
+ * Doc comments will not be parsed for CDL, and will be stripped from input CSN,
114
+ * i.e. the compiled CSN (output) does not contain `doc` properties. No checks
115
+ * are performed on doc comments.
116
+ *
117
+ * - `undefined`:
118
+ * Doc comments are checked (see value `true`). For CDL, doc comments are not parsed,
119
+ * i.e. will not appear in the compiled CSN (output).
120
+ * For CSN input, all `doc` properties remain in the CSN.
121
+ *
122
+ * The CDL equivalent of the CSN value `doc: null`, is an empty doc comment.
123
+ */
124
+ docComment?: boolean
89
125
  /**
90
126
  * When set to `true`, and the model contains an entity `sap.common.Languages`
91
127
  * with an element `code`, all generated texts entities additionally contain
@@ -95,6 +131,17 @@ declare namespace compiler {
95
131
  * @since v2.8.0
96
132
  */
97
133
  addTextsLanguageAssoc?: boolean
134
+ /**
135
+ * An array of directory names that are used for CDS module lookups.
136
+ * Lookup directory `node_modules/` is appended if not set explicitly.
137
+ *
138
+ * All directories in this array follow the same lookup-pattern as `node_modules/`.
139
+ *
140
+ * See <https://cap.cloud.sap/docs/cds/cdl#model-resolution>
141
+ *
142
+ * @since v4.2.0
143
+ */
144
+ moduleLookupDirectories?: string[]
98
145
  /**
99
146
  * Option for {@link compileSources}. If set, all objects inside the
100
147
  * provided sources dictionary are interpreted as XSN structures instead
@@ -466,6 +513,12 @@ declare namespace compiler {
466
513
  */
467
514
  export class CompilationError extends Error {
468
515
  constructor(messages: CompileMessage[], model?: any, text?: string, ...args: any[]);
516
+ /**
517
+ * String to identify this class. Can be used instead of relying on `instanceof`.
518
+ * Always `ERR_CDS_COMPILATION_FAILURE`.
519
+ * @since v4.0.0
520
+ */
521
+ code: string;
469
522
  messages: CompileMessage[];
470
523
  toString(): string;
471
524
  /**
@@ -798,6 +851,9 @@ declare namespace compiler {
798
851
  * identifier in brackets.
799
852
  * Otherwise, return the name without brackets.
800
853
  *
854
+ * NOTE: If `name` contains newline characters, the resulting delimited identifier
855
+ * will not be parsable by the compiler!
856
+ *
801
857
  * Example:
802
858
  * ```js
803
859
  * to.cdl.smartId('with ![brackets]')
@@ -812,6 +868,9 @@ declare namespace compiler {
812
868
  *
813
869
  * @param name
814
870
  * @param [insideFunction=null]
871
+ * Inside special functions such as SAP HANA's `OCCURRENCES_REGEXPR`, there are more
872
+ * keywords than in other places. Set this value to a function name, if you want to
873
+ * handle those additional keywords as well.
815
874
  */
816
875
  function smartId(name: string, insideFunction?: string|null) : string;
817
876
  /**
@@ -819,6 +878,9 @@ declare namespace compiler {
819
878
  * function identifier in brackets for CDL.
820
879
  * Otherwise, return the function name without brackets.
821
880
  *
881
+ * NOTE: If `name` contains newline characters, the resulting delimited identifier
882
+ * will not be parsable by the compiler!
883
+ *
822
884
  * Example:
823
885
  * ```js
824
886
  * to.cdl.smartFunctionId('with ![brackets]')
@@ -834,6 +896,9 @@ declare namespace compiler {
834
896
  * Escapes the given name according to the CDL language and puts it
835
897
  * into `![` and `]`, properly escaping all `]` in the identifier.
836
898
  *
899
+ * NOTE: If `name` contains newline characters, the resulting delimited identifier
900
+ * will not be parsable by the compiler!
901
+ *
837
902
  * Example:
838
903
  * ```js
839
904
  * to.cdl.delimitedId('with ![brackets]')