@sap/cds-compiler 4.4.4 → 4.6.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 (82) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/bin/cdsc.js +18 -11
  3. package/bin/cdsv2m.js +7 -5
  4. package/doc/CHANGELOG_BETA.md +22 -0
  5. package/lib/api/main.js +306 -144
  6. package/lib/api/options.js +18 -6
  7. package/lib/api/validate.js +1 -1
  8. package/lib/base/message-registry.js +45 -10
  9. package/lib/base/messages.js +33 -16
  10. package/lib/base/model.js +4 -0
  11. package/lib/base/optionProcessorHelper.js +45 -176
  12. package/lib/checks/annotationsOData.js +49 -0
  13. package/lib/checks/elements.js +32 -34
  14. package/lib/checks/enricher.js +39 -3
  15. package/lib/checks/validator.js +8 -7
  16. package/lib/compiler/assert-consistency.js +40 -17
  17. package/lib/compiler/builtins.js +30 -53
  18. package/lib/compiler/checks.js +46 -14
  19. package/lib/compiler/cycle-detector.js +1 -4
  20. package/lib/compiler/define.js +35 -10
  21. package/lib/compiler/extend.js +21 -7
  22. package/lib/compiler/generate.js +3 -0
  23. package/lib/compiler/populate.js +5 -1
  24. package/lib/compiler/propagator.js +46 -9
  25. package/lib/compiler/resolve.js +94 -35
  26. package/lib/compiler/shared.js +60 -33
  27. package/lib/compiler/tweak-assocs.js +188 -92
  28. package/lib/compiler/utils.js +11 -1
  29. package/lib/edm/annotations/edmJson.js +41 -66
  30. package/lib/edm/annotations/genericTranslation.js +27 -9
  31. package/lib/edm/annotations/preprocessAnnotations.js +2 -3
  32. package/lib/edm/csn2edm.js +28 -11
  33. package/lib/edm/edmInboundChecks.js +58 -15
  34. package/lib/edm/edmPreprocessor.js +12 -16
  35. package/lib/edm/edmUtils.js +5 -2
  36. package/lib/gen/Dictionary.json +10 -0
  37. package/lib/gen/language.checksum +1 -1
  38. package/lib/gen/language.interp +15 -2
  39. package/lib/gen/language.tokens +1 -0
  40. package/lib/gen/languageParser.js +6557 -5618
  41. package/lib/json/from-csn.js +4 -5
  42. package/lib/json/to-csn.js +29 -4
  43. package/lib/language/antlrParser.js +19 -1
  44. package/lib/language/errorStrategy.js +28 -7
  45. package/lib/language/genericAntlrParser.js +118 -24
  46. package/lib/language/textUtils.js +16 -0
  47. package/lib/main.d.ts +28 -3
  48. package/lib/main.js +3 -0
  49. package/lib/model/csnRefs.js +4 -1
  50. package/lib/model/csnUtils.js +20 -14
  51. package/lib/model/revealInternalProperties.js +5 -2
  52. package/lib/optionProcessor.js +23 -22
  53. package/lib/render/manageConstraints.js +13 -29
  54. package/lib/render/toCdl.js +47 -26
  55. package/lib/render/toHdbcds.js +63 -42
  56. package/lib/render/toRename.js +6 -10
  57. package/lib/render/toSql.js +71 -117
  58. package/lib/render/utils/common.js +41 -6
  59. package/lib/transform/.eslintrc.json +9 -1
  60. package/lib/transform/addTenantFields.js +228 -0
  61. package/lib/transform/db/applyTransformations.js +57 -4
  62. package/lib/transform/db/assertUnique.js +4 -4
  63. package/lib/transform/db/backlinks.js +13 -1
  64. package/lib/transform/db/cdsPersistence.js +1 -1
  65. package/lib/transform/db/expansion.js +24 -3
  66. package/lib/transform/db/flattening.js +70 -71
  67. package/lib/transform/db/killAnnotations.js +37 -0
  68. package/lib/transform/db/rewriteCalculatedElements.js +46 -6
  69. package/lib/transform/db/temporal.js +1 -1
  70. package/lib/transform/draft/db.js +2 -16
  71. package/lib/transform/draft/odata.js +3 -3
  72. package/lib/transform/effective/associations.js +3 -5
  73. package/lib/transform/effective/main.js +6 -9
  74. package/lib/transform/forOdata.js +26 -55
  75. package/lib/transform/forRelationalDB.js +38 -18
  76. package/lib/transform/odata/toFinalBaseType.js +3 -3
  77. package/lib/transform/odata/typesExposure.js +14 -5
  78. package/lib/transform/transformUtils.js +47 -34
  79. package/lib/transform/translateAssocsToJoins.js +45 -11
  80. package/lib/transform/universalCsn/coreComputed.js +1 -1
  81. package/lib/transform/universalCsn/universalCsnEnricher.js +4 -4
  82. package/package.json +7 -6
@@ -31,6 +31,7 @@ const publicOptionsNewAPI = [
31
31
  'generatedByComment',
32
32
  'betterSqliteSessionVariables',
33
33
  'fewerLocalizedViews',
34
+ 'withHanaAssociations',
34
35
  // ODATA
35
36
  'odataOpenapiHints',
36
37
  'odataVersion',
@@ -42,7 +43,6 @@ const publicOptionsNewAPI = [
42
43
  'odataXServiceRefs',
43
44
  'odataV2PartialConstr',
44
45
  'odataVocabularies',
45
- 'odataOpenType',
46
46
  'service',
47
47
  'serviceNames',
48
48
  //
@@ -67,6 +67,7 @@ const privateOptions = [
67
67
  'noRecompile',
68
68
  'internalMsg',
69
69
  'disableHanaComments', // in case of issues with hana comment rendering
70
+ 'tenantAsColumn', // not published yet
70
71
  'localizedWithoutCoalesce', // deprecated version of 'localizedLanguageFallback', TODO(v5): Remove option
71
72
  ];
72
73
 
@@ -77,9 +78,9 @@ const overallOptions = publicOptionsNewAPI.concat(privateOptions);
77
78
  * Apply defaults and make sure that the "hard requirements" are met,
78
79
  * i.e. src: sql if to.sql() was called.
79
80
  *
80
- * @param {FlatOptions} [input={}] Input options
81
- * @param {FlatOptions} [defaults={}] Default options to apply
82
- * @param {FlatOptions} [hardRequire={}] Hard requirements to enforce
81
+ * @param {FlatOptions} [input] Input options
82
+ * @param {FlatOptions} [defaults] Default options to apply
83
+ * @param {FlatOptions} [hardRequire] Hard requirements to enforce
83
84
  * @param {object} [customValidators] Custom validations to run instead of defaults
84
85
  * @param {string[]} [combinationValidators] Option combinations to validate
85
86
  * @param {string} moduleName The called module, e.g. 'for.odata', 'to.hdi'. Needed to initialize the message functions
@@ -127,14 +128,18 @@ module.exports = {
127
128
  cdl: options => translateOptions(options, undefined, undefined, undefined, undefined, 'to.cdl'),
128
129
  sql: (options) => {
129
130
  const hardOptions = { src: 'sql', toSql: true, forHana: true };
130
- const defaultOptions = { sqlMapping: 'plain', sqlDialect: 'plain', generatedByComment: true };
131
+ const defaultOptions = {
132
+ sqlMapping: 'plain', sqlDialect: 'plain', generatedByComment: true, withHanaAssociations: true,
133
+ };
131
134
  const processed = translateOptions(options, defaultOptions, hardOptions, undefined, [ 'sql-dialect-and-naming' ], 'to.sql');
132
135
 
133
136
  return Object.assign({}, processed);
134
137
  },
135
138
  hdi: (options) => {
136
139
  const hardOptions = { src: 'hdi', toSql: true, forHana: true };
137
- const defaultOptions = { sqlMapping: 'plain', sqlDialect: 'hana', generatedByComment: false };
140
+ const defaultOptions = {
141
+ sqlMapping: 'plain', sqlDialect: 'hana', generatedByComment: false, withHanaAssociations: true,
142
+ };
138
143
  return translateOptions(options, defaultOptions, hardOptions, { sqlDialect: generateStringValidator([ 'hana' ]) }, undefined, 'to.hdi');
139
144
  },
140
145
  hdbcds: (options) => {
@@ -154,6 +159,13 @@ module.exports = {
154
159
  };
155
160
  return translateOptions(options, defaultOptions, hardOptions, undefined, [ 'valid-structured' ], 'to.edmx');
156
161
  },
162
+ odata: (options) => {
163
+ const hardOptions = { combined: true, toOdata: true };
164
+ const defaultOptions = {
165
+ odataVersion: 'v4', odataFormat: 'flat',
166
+ };
167
+ return translateOptions(options, defaultOptions, hardOptions, undefined, [ 'valid-structured' ], 'to.odata');
168
+ },
157
169
  },
158
170
  for: { // TODO: Rename version to oDataVersion
159
171
  odata: (options) => {
@@ -141,7 +141,7 @@ const allCombinationValidators = {
141
141
  message.error('api-invalid-combination', null, { '#': 'sql-dialect-and-naming', name: options.sqlDialect, prop: options.sqlMapping });
142
142
  },
143
143
  'sql-dialect-and-localized': (options, message) => {
144
- if (options.fewerLocalizedViews && options.sqlDialect === 'hana')
144
+ if (options.fewerLocalizedViews && options.sqlDialect === 'hana' && (options.withHanaAssociations || options.withHanaAssociations === undefined))
145
145
  message.error('api-invalid-combination', null, { '#': 'sql-dialect-and-localized', option: 'fewerLocalizedViews', value: 'hana' });
146
146
  },
147
147
  'beta-no-test': (options, message) => {
@@ -121,12 +121,12 @@ const centralMessages = {
121
121
  'ref-undefined-def': { severity: 'Error' },
122
122
  'ref-undefined-var': { severity: 'Error' },
123
123
  'ref-undefined-element': { severity: 'Error' },
124
- 'anno-undefined-element': { severity: 'Warning' },
125
- 'ref-unknown-var': { severity: 'Info', errorFor: [ 'to.hdbcds', 'to.sql', 'to.hdi', 'to.rename' ] },
124
+ 'anno-undefined-element': { severity: 'Error' },
125
+ 'ref-unknown-var': { severity: 'Info' },
126
126
  'ref-obsolete-parameters': { severity: 'Error', configurableFor: 'v4' },
127
127
  // does not hurt us, but makes it tedious to detect parameter refs
128
128
  'ref-undefined-param': { severity: 'Error' },
129
- 'anno-undefined-param': { severity: 'Warning' },
129
+ 'anno-undefined-param': { severity: 'Error' },
130
130
  'ref-rejected-on': { severity: 'Error' },
131
131
  'ref-expected-element': { severity: 'Error' },
132
132
 
@@ -254,11 +254,16 @@ const centralMessageTexts = {
254
254
  std: 'Unexpected option combination: $(OPTION) and $(PROP)', // unused
255
255
  'beta-no-test':'Option $(OPTION) was used. This option should not be used in productive scenarios!',
256
256
  },
257
+ 'api-unexpected-option': 'Option $(OPTION) can\'t be used in backend $(MODULE)',
257
258
  'api-invalid-lookup-dir': {
258
259
  std: '',
259
260
  slash: 'Expected directory $(VALUE) in option $(OPTION) to end with $(OTHERVALUE)',
260
261
  relative: 'Expected directory $(VALUE) in option $(OPTION) to not start with $(OTHERVALUE)',
261
262
  },
263
+ 'api-unsupported-csn-flavor': {
264
+ std: 'Module $(NAME) expects a client/inferred CSN, not $(OPTION)',
265
+ 'parsed-requires': 'Module $(NAME) expects a client/inferred CSN, or a parsed CSN without dependencies, but found $(PROP) property',
266
+ },
262
267
 
263
268
  'anno-duplicate': {
264
269
  std: 'Duplicate assignment with $(ANNO)',
@@ -281,6 +286,11 @@ const centralMessageTexts = {
281
286
  view: 'Compiler generated view $(NAME) must not be annotated with $(ANNO) if $(ART) is not skipped',
282
287
  },
283
288
 
289
+ 'anno-missing-rewrite': {
290
+ std: 'Assign a value for $(ANNO), the value inherited from $(ART) would contain invalid references like $(ELEMREF)',
291
+ unrelated: 'Assign a value for $(ANNO), the value inherited from $(ART) would contain references like $(ELEMREF) to unrelated elements',
292
+ },
293
+
284
294
  'chained-array-of': '"Array of"/"many" must not be chained with another "array of"/"many" inside a service',
285
295
 
286
296
  'check-proper-type-of': {
@@ -326,6 +336,9 @@ const centralMessageTexts = {
326
336
  csn: 'Expecting a non-negative integer for property $(PROP)',
327
337
  'or-asterisk': 'Expecting a non-negative integer or string $(OP) for property $(PROP)',
328
338
  },
339
+ 'syntax-ignoring-decimal': {
340
+ std: 'Ignoring decimal places, because an integer was expected'
341
+ },
329
342
  'syntax-ignoring-anno': {
330
343
  std: 'Annotations can\'t be used in a column with $(CODE)',
331
344
  doc: 'Doc comments can\'t be used in a column with $(CODE)',
@@ -573,6 +586,7 @@ const centralMessageTexts = {
573
586
  std: 'Variable $(ID) has not been found',
574
587
  alias: 'Variable $(ID) has not been found. Use table alias $(ALIAS) to refer an element with the same name',
575
588
  self: 'Variable $(ID) has not been found. Use $(ALIAS) to refer an element with the same name',
589
+ value: 'No value found for variable $(ID). Use option $(OPTION) to specify a value for $(ID)',
576
590
  },
577
591
  'ref-unknown-var': {
578
592
  std: 'No replacement found for special variable $(ID)'
@@ -614,6 +628,7 @@ const centralMessageTexts = {
614
628
  self: 'A reference to an unmanaged association is only valid when compared via $(CODE)',
615
629
  expr: 'Associations can\'t be used as values in expressions',
616
630
  'expr-comp': 'Compositions can\'t be used as values in expressions',
631
+ 'assoc-stored': 'Associations and compositions can\'t be used as values in stored calculated elements',
617
632
  cast: 'Casting to an association is not supported',
618
633
 
619
634
  'managed-filter': 'Unexpected managed association $(NAME) in filter expression of $(ID)',
@@ -646,9 +661,19 @@ const centralMessageTexts = {
646
661
  'on-condition': 'ON-conditions must not contain parameters, step $(ID) of path $(ELEMREF)',
647
662
  calc: 'Unexpected arguments in path $(ELEMREF) of stored calculated element; only simple paths can be used here'
648
663
  },
664
+ 'ref-unsupported-type': {
665
+ std: 'Type $(TYPE) is not supported',
666
+ hana: 'Type $(TYPE) is only supported for SQL dialect $(VALUE), not $(OTHERVALUE)',
667
+ hdbcds:'Type $(TYPE) is not supported in HDBCDS',
668
+ odata: 'Type $(TYPE) is not supported for OData'
669
+ },
649
670
 
650
671
  // TODO: Better text ?
651
672
  'rewrite-not-supported': 'The ON-condition is not rewritten here - provide an explicit ON-condition',
673
+ 'type-unsupported-rewrite': {
674
+ std: 'Rewriting the ON-condition not supported here', // unused: merge with 'rewrite-not-supported'
675
+ 'sub-element': 'Rewriting the ON-condition of unmanaged association in sub element is not supported'
676
+ },
652
677
 
653
678
  'type-unexpected-typeof': {
654
679
  std: 'Unexpected $(KEYWORD) for the type reference here',
@@ -835,9 +860,15 @@ const centralMessageTexts = {
835
860
  param: 'A type, an element, or a service entity is expected here',
836
861
  event: 'A type, an element, an event, or a service entity is expected here',
837
862
  },
838
- // TODO: text variant if the association does not start an entity
839
- 'ref-invalid-source': 'A query source must be an entity or an association',
840
- 'extend-columns': 'Artifact $(ART) can\'t be extended with columns, only projections can',
863
+ 'ref-invalid-source': {
864
+ std: 'A query source must be an entity or an association',
865
+ event: 'An event\'s projection source must be an entity, structured type, event or an association',
866
+ },
867
+ 'extend-columns': {
868
+ std: 'Artifact $(ART) can\'t be extended with columns, only simple views/projections without JOINs and UNIONs can',
869
+ join: 'Artifact $(ART) can\'t be extended with columns, because it contains a JOIN',
870
+ union: 'Artifact $(ART) can\'t be extended with columns, because it contains a UNION',
871
+ },
841
872
  'extend-repeated-intralayer': 'Unstable element order due to repeated extensions in same layer',
842
873
  'extend-unexpected-include': 'Can\'t extend $(META) with includes',
843
874
 
@@ -889,6 +920,7 @@ const centralMessageTexts = {
889
920
  std: 'Specified element $(NAME) differs from inferred element in property $(PROP)',
890
921
  type: 'Expected type of specified element $(NAME) to be the same as the inferred element\'s type',
891
922
  typeName: 'Expected type $(TYPE) of specified element $(NAME) to be the same as the inferred element\'s type $(OTHERTYPE)',
923
+ typeExtra: 'Element $(NAME) does not have an inferred type property, but an unexpected type $(TYPE) was specified',
892
924
  missing: 'Specified element $(NAME) differs from inferred element: it is missing property $(PROP)',
893
925
  extra: 'Specified element $(NAME) differs from inferred element: it has an additional property $(PROP)',
894
926
  target: 'Expected target $(TARGET) of specified element $(NAME) to be the same as the inferred element\'s target $(ART)',
@@ -937,7 +969,8 @@ const centralMessageTexts = {
937
969
  'to-structure': 'Can\'t cast to a structured type',
938
970
  'from-structure': 'Structured elements can\'t be cast to a different type',
939
971
  'expr-to-structure': 'Can\'t cast an expression to a structured type',
940
- 'val-to-structure': 'Can\'t cast $(VALUE) to a structured type'
972
+ 'val-to-structure': 'Can\'t cast $(VALUE) to a structured type',
973
+ 'from-assoc': 'Invalid type cast on an association'
941
974
  },
942
975
 
943
976
  // -----------------------------------------------------------------------------------
@@ -1018,6 +1051,7 @@ const centralMessageTexts = {
1018
1051
  },
1019
1052
  'odata-parameter-order': 'Unexpected mandatory after optional parameter',
1020
1053
  'odata-key-recursive': 'Unexpected recursive key $(NAME)',
1054
+ 'odata-key-uuid-default-anno': 'Expected element of type $(TYPE) to be annotated with $(ANNO) when used as primary key in $(ID)',
1021
1055
  // -----------------------------------------------------------------------------------
1022
1056
  // All odata-anno MUST have a '$(ANNO)' parameter to indicate error location
1023
1057
  // -----------------------------------------------------------------------------------
@@ -1026,7 +1060,7 @@ const centralMessageTexts = {
1026
1060
  'odata-anno-preproc': {
1027
1061
  'std': 'unused message text',
1028
1062
  'nokey': 'Expected target $(NAME) to have a key element for $(ANNO)',
1029
- 'multkeys': 'Expected target $(NAME) to have only one key element',
1063
+ 'multkeys': 'Expected target $(NAME) to have only one key element for $(ANNO)',
1030
1064
  'vhlnokey': 'Expected value help list entity $(NAME) to have a key element for $(ANNO)',
1031
1065
  'vhlmultkeys': 'Expected value help list entity $(NAME) to have only one key element for $(ANNO)',
1032
1066
  'notforentity': 'Unexpected usage of $(ANNO) for an entity',
@@ -1034,8 +1068,8 @@ const centralMessageTexts = {
1034
1068
  'noassoc': 'Expected association $(ID) to exist for $(ANNO)',
1035
1069
  'vallistignored': '$(NAME) is ignored for $(ANNO) as $(CODE) is present',
1036
1070
  'notastring': 'Expected value to be a string for $(ANNO)',
1037
- 'notexist': 'Expect entity $(ID) to exist for $(ANNO)',
1038
- 'txtarr': 'Expect $(ANNO) shortcut to have a $(NAME) annotation'
1071
+ 'notexist': 'Expected entity $(ID) to exist for $(ANNO)',
1072
+ 'txtarr': 'Expected $(ANNO) shortcut to have a $(NAME) annotation'
1039
1073
  },
1040
1074
  // -----------------------------------------------------------------------------------
1041
1075
  // GenericTranslation:
@@ -1074,6 +1108,7 @@ const centralMessageTexts = {
1074
1108
  'unknown': '$(TYPE) is not a known vocabulary type for $(ANNO)',
1075
1109
  'abstract': 'Unexpected abstract type $(TYPE) for $(ANNO), use $(CODE) to specify a concrete type',
1076
1110
  'derived': 'Expected specified $(TYPE) to be derived from $(NAME) for $(ANNO)',
1111
+ 'literal': 'Expected value $(RAWVALUE) of specified $(CODE) to be a string literal for $(ANNO)'
1077
1112
  },
1078
1113
  'odata-anno-def': {
1079
1114
  // All $(ANNO) w/o sub elements, term qualifiers and context stack
@@ -305,14 +305,14 @@ function makeMessageFunction( model, options, moduleName = null ) {
305
305
  throw new CompilerAssertion('makeMessageFunction() expects options.messages to exist in testMode!');
306
306
  }
307
307
 
308
- const hasMessageArray = !!options.messages;
308
+ const hasMessageArray = Array.isArray(options.messages);
309
309
  /**
310
310
  * Array of collected compiler messages. Only use it for debugging. Will not
311
311
  * contain the messages created during a `callTransparently` call.
312
312
  *
313
313
  * @type {CompileMessage[]}
314
314
  */
315
- let messages = options.messages || [];
315
+ let messages = hasMessageArray ? options.messages : [];
316
316
  /**
317
317
  * Whether an error was emitted in the module. Also includes reclassified errors.
318
318
  * @type {boolean}
@@ -332,6 +332,7 @@ function makeMessageFunction( model, options, moduleName = null ) {
332
332
  throwWithAnyError,
333
333
  callTransparently,
334
334
  moduleName,
335
+ setModel,
335
336
  };
336
337
 
337
338
  function _message( id, location, textOrArguments, severity, texts = null ) {
@@ -550,6 +551,16 @@ function makeMessageFunction( model, options, moduleName = null ) {
550
551
  messages = backup;
551
552
  return collected;
552
553
  }
554
+
555
+ /**
556
+ * Change the model used to calculate CSN locations.
557
+ * This is necessary if you change the model heavily and rely on $paths relative to the new model.
558
+ *
559
+ * @param {CSN.Model} _model
560
+ */
561
+ function setModel( _model ) {
562
+ model = _model;
563
+ }
553
564
  }
554
565
 
555
566
  /**
@@ -679,6 +690,7 @@ const paramsTransform = {
679
690
  meta: quote.angle,
680
691
  othermeta: quote.angle,
681
692
  keyword,
693
+ module: quote.single,
682
694
  // more complex convenience:
683
695
  names: transformManyWith( quoted ),
684
696
  number: quote.single, // number cited from source or expected in source
@@ -797,15 +809,16 @@ function tokenSymbol( token ) {
797
809
  * Transform an element reference (/path), e.g. on-condition path.
798
810
  */
799
811
  function transformElementRef( arg ) {
800
- if (arg.ref) {
801
- // Can be used by CSN backends to create a simple path such as E:elem
802
- return quoted(arg.ref.map((ref) => {
803
- if (ref.id)
804
- return `${ ref.id }${ref.args ? '(…)' : ''}${ref.where ? '[…]' : ''}`;
805
- return ref;
806
- }).join('.'));
807
- }
808
- return quoted(arg);
812
+ const ref = arg.ref || arg.path;
813
+ if (!ref)
814
+ return quoted( arg );
815
+ // Can be used by CSN backends or compiler to create a simple path such as E:elem
816
+ return quoted(
817
+ ref.map(
818
+ item => (typeof item !== 'string'
819
+ ? `${ item.id }${item.args ? '(…)' : ''}${item.where ? '[…]' : ''}`
820
+ : item) )
821
+ .join('.') );
809
822
  }
810
823
 
811
824
  function transformArg( arg, r, args, texts ) {
@@ -1299,7 +1312,7 @@ function deduplicateMessages( messages ) {
1299
1312
  }
1300
1313
 
1301
1314
  function shortArtName( art ) {
1302
- if (!art.name)
1315
+ if (!art.name || art.kind === '$annotation')
1303
1316
  return artName( art );
1304
1317
  const name = getArtifactName( art );
1305
1318
  if ([ 'select', 'action', 'alias', 'param' ].every( n => name[n] == null || name[n] === 1 ) &&
@@ -1310,7 +1323,7 @@ function shortArtName( art ) {
1310
1323
 
1311
1324
  function artName( art, omit ) {
1312
1325
  let suffix = 0;
1313
- while (!art.name && art._outer) {
1326
+ while (!art.name && art._outer && art.kind !== '$annotation') {
1314
1327
  ++suffix;
1315
1328
  art = art._outer;
1316
1329
  }
@@ -1367,8 +1380,12 @@ function homeName( art, absoluteOnly ) {
1367
1380
  return art;
1368
1381
  if (art._user) // when providing a path item with filter as “user”
1369
1382
  return homeName( art._user, absoluteOnly );
1370
- if (art._outer) // in items property
1371
- return homeName( art._outer, absoluteOnly );
1383
+ if (art._outer) { // in items property, or annotation with path
1384
+ const outer = homeName( art._outer, absoluteOnly );
1385
+ return (art.kind === '$annotation')
1386
+ ? `${ outer }/${ quoted( '@' + art.name.id ) }`
1387
+ : outer;
1388
+ }
1372
1389
  else if (art.kind === 'source' || !art.name) // error reported in parser or on source level
1373
1390
  return null;
1374
1391
  else if (art.kind === 'using')
@@ -1578,7 +1595,7 @@ function constructSemanticLocationFromCsnPath( model, options, csnPath ) {
1578
1595
  else if (step === 'targetAspect') {
1579
1596
  // skip
1580
1597
  }
1581
- else if (step === 'xpr' || step === 'ref' || step === 'as' || step === 'value') {
1598
+ else if (step === 'xpr' || step === 'default' || step === 'ref' || step === 'as' || step === 'value') {
1582
1599
  break; // don't go into xprs, refs, aliases, values, etc.
1583
1600
  }
1584
1601
  else if (step === 'returns') {
package/lib/base/model.js CHANGED
@@ -27,6 +27,7 @@ const queryOps = {
27
27
  const availableBetaFlags = {
28
28
  // enabled by --beta-mode
29
29
  annotationExpressions: true,
30
+ odataAnnotationExpressions: true,
30
31
  assocsWithParams: true, // beta, because runtimes don't support it, yet.
31
32
  hanaAssocRealCardinality: true,
32
33
  mapAssocToJoinCardinality: true, // only SAP HANA HEX engine supports it
@@ -35,6 +36,9 @@ const availableBetaFlags = {
35
36
  optionalActionFunctionParameters: true, // not supported by runtime, yet.
36
37
  annotateForeignKeys: true,
37
38
  effectiveCsn: true,
39
+ tenantVariable: true,
40
+ calcAssoc: true,
41
+ vectorType: true,
38
42
  // disabled by --beta-mode
39
43
  nestedServices: false,
40
44
  };