@sap/cds-compiler 4.8.0 → 4.9.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 (95) hide show
  1. package/CHANGELOG.md +38 -4
  2. package/bin/cds_remove_invalid_whitespace.js +135 -0
  3. package/bin/cds_update_annotations.js +180 -0
  4. package/bin/cds_update_identifiers.js +3 -4
  5. package/bin/cdsc.js +30 -17
  6. package/doc/CHANGELOG_BETA.md +19 -0
  7. package/lib/api/main.js +59 -24
  8. package/lib/api/options.js +12 -1
  9. package/lib/api/validate.js +1 -5
  10. package/lib/base/builtins.js +27 -0
  11. package/lib/base/message-registry.js +38 -21
  12. package/lib/base/messages.js +51 -20
  13. package/lib/base/model.js +4 -5
  14. package/lib/checks/actionsFunctions.js +2 -2
  15. package/lib/checks/annotationsOData.js +3 -0
  16. package/lib/checks/defaultValues.js +5 -2
  17. package/lib/checks/queryNoDbArtifacts.js +3 -2
  18. package/lib/checks/validator.js +2 -34
  19. package/lib/compiler/assert-consistency.js +10 -3
  20. package/lib/compiler/checks.js +44 -18
  21. package/lib/compiler/define.js +38 -30
  22. package/lib/compiler/extend.js +33 -10
  23. package/lib/compiler/index.js +0 -1
  24. package/lib/compiler/lsp-api.js +5 -0
  25. package/lib/compiler/populate.js +0 -2
  26. package/lib/compiler/propagator.js +23 -19
  27. package/lib/compiler/resolve.js +48 -29
  28. package/lib/compiler/shared.js +60 -20
  29. package/lib/compiler/tweak-assocs.js +72 -116
  30. package/lib/compiler/xpr-rewrite.js +762 -0
  31. package/lib/edm/annotations/edmJson.js +24 -7
  32. package/lib/edm/annotations/genericTranslation.js +81 -61
  33. package/lib/edm/edm.js +4 -4
  34. package/lib/edm/edmInboundChecks.js +33 -0
  35. package/lib/edm/edmPreprocessor.js +9 -6
  36. package/lib/gen/Dictionary.json +129 -14
  37. package/lib/gen/language.checksum +1 -1
  38. package/lib/gen/language.interp +1 -1
  39. package/lib/gen/languageParser.js +1523 -1518
  40. package/lib/json/from-csn.js +13 -4
  41. package/lib/json/to-csn.js +12 -12
  42. package/lib/language/genericAntlrParser.js +14 -6
  43. package/lib/main.d.ts +67 -14
  44. package/lib/main.js +1 -0
  45. package/lib/model/cloneCsn.js +6 -3
  46. package/lib/model/csnRefs.js +23 -11
  47. package/lib/model/csnUtils.js +13 -7
  48. package/lib/model/enrichCsn.js +3 -1
  49. package/lib/model/revealInternalProperties.js +2 -1
  50. package/lib/model/sortViews.js +14 -6
  51. package/lib/modelCompare/compare.js +33 -34
  52. package/lib/optionProcessor.js +27 -2
  53. package/lib/render/DuplicateChecker.js +6 -6
  54. package/lib/render/manageConstraints.js +1 -0
  55. package/lib/render/toCdl.js +3 -1
  56. package/lib/transform/db/applyTransformations.js +33 -0
  57. package/lib/transform/db/constraints.js +75 -28
  58. package/lib/transform/db/expansion.js +8 -3
  59. package/lib/transform/db/flattening.js +2 -2
  60. package/lib/transform/db/groupByOrderBy.js +2 -2
  61. package/lib/transform/db/temporal.js +6 -3
  62. package/lib/transform/db/transformExists.js +2 -2
  63. package/lib/transform/effective/annotations.js +194 -0
  64. package/lib/transform/effective/main.js +6 -8
  65. package/lib/transform/effective/misc.js +31 -10
  66. package/lib/transform/forOdata.js +23 -7
  67. package/lib/transform/forRelationalDB.js +3 -3
  68. package/lib/transform/localized.js +7 -6
  69. package/lib/transform/odata/flattening.js +221 -124
  70. package/lib/transform/odata/toFinalBaseType.js +1 -1
  71. package/lib/transform/odata/typesExposure.js +15 -12
  72. package/lib/transform/parseExpr.js +4 -4
  73. package/lib/transform/transformUtils.js +47 -42
  74. package/lib/transform/translateAssocsToJoins.js +47 -47
  75. package/lib/transform/universalCsn/universalCsnEnricher.js +16 -19
  76. package/package.json +1 -1
  77. package/share/messages/anno-missing-rewrite.md +45 -0
  78. package/share/messages/message-explanations.json +1 -0
  79. package/bin/.eslintrc.json +0 -17
  80. package/lib/api/.eslintrc.json +0 -37
  81. package/lib/checks/.eslintrc.json +0 -31
  82. package/lib/compiler/.eslintrc.json +0 -8
  83. package/lib/edm/.eslintrc.json +0 -46
  84. package/lib/inspect/.eslintrc.json +0 -4
  85. package/lib/json/.eslintrc.json +0 -4
  86. package/lib/language/.eslintrc.json +0 -4
  87. package/lib/model/.eslintrc.json +0 -13
  88. package/lib/modelCompare/utils/.eslintrc.json +0 -22
  89. package/lib/render/.eslintrc.json +0 -22
  90. package/lib/transform/.eslintrc.json +0 -13
  91. package/lib/transform/db/.eslintrc.json +0 -41
  92. package/lib/transform/draft/.eslintrc.json +0 -4
  93. package/lib/transform/effective/.eslintrc.json +0 -4
  94. package/lib/transform/universalCsn/.eslintrc.json +0 -37
  95. package/lib/utils/.eslintrc.json +0 -7
@@ -248,8 +248,15 @@ function xpr2edmJson( carrier, anno, location, options, messageFunctions ) {
248
248
  transform['<='] = op('$Le');
249
249
  transform.$Le = noOp;
250
250
  transform.in = (parent, prop, xpr) => {
251
- evalArgs({ min: 1 }, xpr[1].list, prop);
252
- parent.$In = [ xpr[0], ...xpr[1].list ];
251
+ let args = xpr[1].list;
252
+ if (!args) {
253
+ if (Array.isArray(xpr[1].xpr))
254
+ args = xpr[1].xpr;
255
+ else
256
+ args = [ xpr[1] ];
257
+ }
258
+ evalArgs({ min: 1 }, args, prop);
259
+ parent.$In = [ xpr[0], args ];
253
260
  delete parent[prop];
254
261
  transformExpression(parent, undefined, transform);
255
262
  };
@@ -293,9 +300,9 @@ function xpr2edmJson( carrier, anno, location, options, messageFunctions ) {
293
300
  transform.$Neg = noOp;
294
301
  transform['*'] = op('$Mul');
295
302
  transform.$Mul = noOp;
296
- transform['/'] = op('$Div');
297
- transform.$Div = noOp;
298
- // $DivBy, $Mod are functions
303
+ transform['/'] = op('$DivBy');
304
+ transform.$DivBy = noOp;
305
+ // $Div, $Mod are functions
299
306
  //----------------------------------
300
307
  // LITERALS
301
308
  transform.val = (parent, prop, xpr, csnPath, parentparent, parentprop) => {
@@ -575,6 +582,15 @@ function xpr2edmJson( carrier, anno, location, options, messageFunctions ) {
575
582
  }
576
583
  }
577
584
  else {
585
+ // Error out for arbitrary types until we know better
586
+ // probably todo: Check for reachability of arb type names such as namespace
587
+ // reqDef entry etc...
588
+ if (typeDef) { // eslint-disable-line no-lonely-if
589
+ error('odata-anno-xpr-type', location, {
590
+ anno, op: `${xpr}(…)`, type: `${typeDef}`, '#': 'edm',
591
+ });
592
+ }
593
+ /*
578
594
  typeFacets.forEach((facet) => {
579
595
  if (facet.args.length === 1 && facet.args[0].val) {
580
596
  const facetName = facet.func.startsWith('$') ? facet.func.slice(1) : facet.func;
@@ -582,6 +598,7 @@ function xpr2edmJson( carrier, anno, location, options, messageFunctions ) {
582
598
  parent[`$${facetName}`] = facet.args[0].val;
583
599
  }
584
600
  });
601
+ */
585
602
  }
586
603
 
587
604
  delete typeProp.args;
@@ -648,8 +665,8 @@ function xpr2edmJson( carrier, anno, location, options, messageFunctions ) {
648
665
  const funcDefs = {
649
666
  $Has: twoArgs,
650
667
  Has: [ twoArgs, dollar ],
651
- $DivBy: twoArgs,
652
- DivBy: [ twoArgs, dollar ],
668
+ $Div: twoArgs,
669
+ Div: [ twoArgs, dollar ],
653
670
  $Mod: twoArgs,
654
671
  Mod: [ twoArgs, dollar ],
655
672
  $Apply: () => {
@@ -102,7 +102,9 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
102
102
  // qualified with #$parameters or if its applicable to an EntitySet or Singleton
103
103
  const scopeCheck = {
104
104
  ref: (elemref, prop, xpr, path) => {
105
- if (scopeCheck.scope === 'param' && (!elemref.param || (xpr[0].id || xpr[0]) === '$self')) {
105
+ if (scopeCheck.scope === 'param' &&
106
+ (!elemref.param ||
107
+ (xpr[0].id || xpr[0]) === '$self' && !def.elements.$self)) {
106
108
  error('odata-anno-xpr-ref', path, { anno: scopeCheck.anno, elemref, '#': 'notaparam' });
107
109
  // don't try to resolve those paths later on
108
110
  delete elemref[prop];
@@ -111,9 +113,13 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
111
113
  error('odata-anno-xpr-ref', path, { anno: scopeCheck.anno, elemref, '#': 'notaneelement' });
112
114
  delete elemref[prop];
113
115
  }
114
- if (scopeCheck.scope === 'param' && elemref.param)
116
+ if (scopeCheck.scope === 'param' && elemref.param) {
115
117
  // make sure that path is resolvable as element path later on
116
118
  delete elemref.param;
119
+ const head = xpr[0].id || xpr[0];
120
+ if (head[0] === '$')
121
+ xpr.unshift('$self');
122
+ }
117
123
  },
118
124
  };
119
125
  const checkDict = (dict, scope) => {
@@ -156,7 +162,8 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
156
162
  const steps = prefix.replace(`@${ns}.`, '').split('.');
157
163
  const paramAnnoParts = steps[0].split('#$parameters');
158
164
  const dictTerm = getDictTerm(`${ns}.${paramAnnoParts[0]}`, options);
159
- if (paramAnnoParts.length > 1 || [ 'Singleton', 'EntitySet' ].some(y => dictTerm?.AppliesTo?.includes(y))) {
165
+ if (paramAnnoParts.length > 1 ||
166
+ [ 'Singleton', 'EntitySet' ].some(y => dictTerm?.AppliesTo?.includes(y))) {
160
167
  steps[0] = `@${ns}.${paramAnnoParts.join('')}`;
161
168
  let newAnno = steps.join('.');
162
169
  if (innerAnnotation)
@@ -185,12 +192,14 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
185
192
  There is one exception (Schema), see below
186
193
 
187
194
  carrier = service
188
- the target is the EntityContainer, unless the annotation has an "AppliesTo" where only Schema is given, but not EntityContainer
189
- then the <Annotation ...> is directly put into <Schema ...> without an enclosing <Annotations ...>
195
+ the target is the EntityContainer, unless the annotation has an "AppliesTo"
196
+ where only Schema is given, but not EntityContainer then the <Annotation ...>
197
+ is directly put into <Schema ...> without an enclosing <Annotations ...>
190
198
 
191
199
  carrier = entity (incl. view/projection)
192
- the target is the corresponding EntityType, unless the annotation has an "AppliesTo" where only EntitySet is given, but not EntityType
193
- then the target is the corresponding EntitySet
200
+ the target is the corresponding EntityType, unless the annotation has an
201
+ "AppliesTo" where only EntitySet is given, but not EntityType then the target
202
+ is the corresponding EntitySet
194
203
 
195
204
  carrier = structured type
196
205
  the target is the corresponding ComplexType
@@ -217,7 +226,8 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
217
226
  if (def.$elementsAnnoProxies) {
218
227
  Object.entries(def.$elementsAnnoProxies).forEach(([ elemPath, element ]) => {
219
228
  const edmTargetName = `${defName}/${elemPath}`;
220
- handleAnnotations(edmTargetName, element, element.$path, [ ...location, '$elementsAnnoProxies', elemPath ]);
229
+ handleAnnotations(edmTargetName, element, element.$path,
230
+ [ ...location, '$elementsAnnoProxies', elemPath ]);
221
231
  });
222
232
  }
223
233
  // element bound annotations
@@ -278,24 +288,28 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
278
288
  if (cAction.$paramsAnnoProxies) {
279
289
  Object.entries(cAction.$paramsAnnoProxies).forEach(([ paramPath, param ]) => {
280
290
  const edmTargetName = `${actionName}/${paramPath}`;
281
- handleAnnotations(edmTargetName, param, param.$path, [ ...location, '$paramsAnnoProxies', paramPath ]);
291
+ handleAnnotations(edmTargetName, param, param.$path,
292
+ [ ...location, '$paramsAnnoProxies', paramPath ]);
282
293
  });
283
294
  }
284
295
  Object.entries(cAction.params).forEach(([ n, p ]) => {
285
296
  const edmTargetName = `${actionName}/${n}`;
286
- handleAnnotations(edmTargetName, p, [ ...location, 'params', n ]);
297
+ handleAnnotations(edmTargetName, p,
298
+ [ ...location, 'params', n ]);
287
299
  });
288
300
  }
289
301
  if (cAction.returns) {
290
302
  if (cAction.$returnsAnnoProxies) {
291
303
  Object.entries(cAction.$returnsAnnoProxies).forEach(([ returnsPath, returns ]) => {
292
304
  const edmTargetName = `${actionName}/${returnsPath}`;
293
- handleAnnotations(edmTargetName, returns, returns.$path, [ ...location, '$returnsAnnoProxies', returnsPath ]);
305
+ handleAnnotations(edmTargetName, returns, returns.$path,
306
+ [ ...location, '$returnsAnnoProxies', returnsPath ]);
294
307
  });
295
308
  }
296
309
  const edmTargetName = `${actionName}/$ReturnType`;
297
310
  setProp(cAction.returns, '$appliesToReturnType', true);
298
- handleAnnotations(edmTargetName, cAction.returns, [ ...location, 'returns' ]);
311
+ handleAnnotations(edmTargetName, cAction.returns,
312
+ [ ...location, 'returns' ]);
299
313
  delete cAction.returns.$appliesToReturnType;
300
314
  }
301
315
 
@@ -304,12 +318,19 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
304
318
  const params = [];
305
319
  if (entityNameIfBound) {
306
320
  // If this is an action and has an explicit binding parameter add it here
307
- if (cAction.$bindingParam && cAction.kind === 'action')
308
- params.push(cAction.$bindingParam.items ? `Collection(${entityNameIfBound})` : entityNameIfBound);
309
-
321
+ if (cAction.$bindingParam && cAction.kind === 'action') {
322
+ params.push(
323
+ cAction.$bindingParam.items
324
+ ? `Collection(${entityNameIfBound})`
325
+ : entityNameIfBound
326
+ );
327
+ }
310
328
  // If action/function has no explicit binding parameter add it here
311
- else if (!cAction.$bindingParam)
312
- params.push(cAction['@cds.odata.bindingparameter.collection'] ? `Collection(${entityNameIfBound})` : entityNameIfBound);
329
+ else if (!cAction.$bindingParam) {
330
+ params.push(cAction['@cds.odata.bindingparameter.collection']
331
+ ? `Collection(${entityNameIfBound})`
332
+ : entityNameIfBound);
333
+ }
313
334
  }
314
335
  // In case this is a function the explicit binding parameter is part of
315
336
  // the functions params dictionary. Only for functions all parameters must
@@ -369,50 +390,49 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
369
390
  if (knownAnnos.length === 0)
370
391
  return;
371
392
  }
372
- if (isBetaEnabled(options, 'odataAnnotationExpressions')) {
373
- knownAnnos.forEach((knownAnno) => {
374
- if (knownAnno.search(/\.\$edmJson\./g) < 0) {
375
- if (isBetaEnabled(options, 'odataPathsInAnnotationExpressions')) {
376
- transformExpression(carrier, knownAnno, {
377
- ref: (elemref, prop, xpr, csnPath) => {
378
- const { links, scope } = reqDefsUtils.inspectRef(csnPath);
379
- let i = scope === '$self' ? 1 : 0;
380
- const getProp = propName => (links[i].art ? (links[i].art[propName] || reqDefsUtils.effectiveType(links[i].art)[propName]) : undefined);
381
- if (scope === '$magic')
382
- return;
383
- let stop = false;
384
- for (; i < links.length && !stop; i++) {
385
- const cardinality = getProp('cardinality');
386
- if ((cardinality && cardinality.max !== 1) || getProp('items')) {
387
- error('odata-anno-xpr-ref', location, {
388
- count: i + 1, elemref, anno: knownAnno, '#': 'tomany',
389
- });
390
- stop = true;
391
- }
392
- if (!isEdmPropertyRendered(links[i].art, csnPath)) {
393
- error('odata-anno-xpr-ref', location, {
394
- count: i + 1, elemref, anno: knownAnno, '#': 'notrendered',
395
- });
396
- stop = true;
397
- }
398
- if (links[i].art?._target?.$proxy && i < links.length - 1) {
399
- const proxy = links[i].art?._target;
400
- const eltName = links[i + 1].art?.name;
401
- if (!proxy.elements[eltName]) {
402
- error('odata-anno-xpr-ref', location, {
403
- count: i + 2, elemref, anno: knownAnno, '#': 'notrendered',
404
- });
405
- stop = true;
406
- }
407
- }
393
+
394
+ knownAnnos.forEach((knownAnno) => {
395
+ if (knownAnno.search(/\.\$edmJson\./g) < 0) {
396
+ transformExpression(carrier, knownAnno, {
397
+ ref: (elemref, prop, xpr, csnPath) => {
398
+ if (options.isV2() && elemref.$bparam) {
399
+ error('odata-anno-xpr-ref', location, {
400
+ elemref, anno: knownAnno, version: '2.0', '#': 'bparam_v2',
401
+ });
402
+ return;
403
+ }
404
+ const { links, scope } = reqDefsUtils.inspectRef(csnPath);
405
+ let i = scope === '$self' ? 1 : 0;
406
+ if (scope === '$magic') {
407
+ error('odata-anno-xpr-ref', location, {
408
+ elemref, anno: knownAnno, '#': 'magic',
409
+ });
410
+ return;
411
+ }
412
+ let stop = false;
413
+ for (; i < links.length && !stop; i++) {
414
+ if (!isEdmPropertyRendered(links[i].art, csnPath)) {
415
+ error('odata-anno-xpr-ref', location, {
416
+ count: i + 1, elemref, anno: knownAnno, '#': 'notrendered',
417
+ });
418
+ stop = true;
419
+ }
420
+ if (links[i].art?._target?.$proxy && i < links.length - 1) {
421
+ const proxy = links[i].art?._target;
422
+ const eltName = links[i + 1].art?.name;
423
+ if (!proxy.elements[eltName]) {
424
+ error('odata-anno-xpr-ref', location, {
425
+ count: i + 2, elemref, anno: knownAnno, '#': 'notrendered',
426
+ });
427
+ stop = true;
408
428
  }
409
- },
410
- }, csnPathResolutionLocation);
411
- }
412
- xpr2edmJson(carrier, knownAnno, location, options, messageFunctions);
413
- }
414
- });
415
- }
429
+ }
430
+ }
431
+ },
432
+ }, csnPathResolutionLocation);
433
+ xpr2edmJson(carrier, knownAnno, location, options, messageFunctions);
434
+ }
435
+ });
416
436
 
417
437
  const prefixTree = createPrefixTree();
418
438
 
@@ -1014,7 +1034,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
1014
1034
  typeName = dTypeName.split('.')[1];
1015
1035
  }
1016
1036
 
1017
- if (value) {
1037
+ if (typeof value === 'string') {
1018
1038
  // replace all occurrences of '.' by '/' up to first '@'
1019
1039
  value = value.split('@').map((o, i) => (i === 0 ? o.replace(/\./g, '/') : o)).join('@');
1020
1040
  }
package/lib/edm/edm.js CHANGED
@@ -19,11 +19,11 @@ function getEdm( options, messageFunctions ) {
19
19
  */
20
20
  constructor(version, attributes = Object.create(null), csn = undefined) {
21
21
  if (!attributes || typeof attributes !== 'object')
22
- error(null, 'Please debug me: attributes must be a dictionary');
22
+ error(null, 'Debug me: attributes must be a dictionary');
23
23
  if (!Array.isArray(version))
24
- error(null, `Please debug me: v is either undefined or not an array: ${version}`);
24
+ error(null, `Debug me: v is either undefined or not an array: ${version}`);
25
25
  if (version.filter(v => v).length !== 1)
26
- error(null, 'Please debug me: exactly one version must be set');
26
+ error(null, 'Debug me: exactly one version must be set');
27
27
 
28
28
  // Common attributes of JSON and XML.
29
29
  // Note: Can't assign attributes directly, due to the input object being modified.
@@ -1108,7 +1108,7 @@ function getEdm( options, messageFunctions ) {
1108
1108
  json.$OnDelete = c._edmAttributes.Action;
1109
1109
  break;
1110
1110
  default:
1111
- error(null, `Please debug me: Unhandled NavProp child: ${c.kind}`);
1111
+ error(null, `Debug me: Unhandled NavProp child: ${c.kind}`);
1112
1112
  }
1113
1113
  });
1114
1114
  // TODO Annotations
@@ -3,6 +3,7 @@
3
3
  const { setProp, isBetaEnabled } = require('../base/model');
4
4
  const {
5
5
  forEachDefinition, forEachMemberRecursively, getUtils,
6
+ transformExpression, findAnnotationExpression,
6
7
  } = require('../model/csnUtils');
7
8
  const { isBuiltinType } = require('../base/builtins');
8
9
  const { assignAnnotation } = require('./edmUtils.js');
@@ -55,8 +56,10 @@ function inboundQualificationChecks( csn, options, messageFunctions,
55
56
  Object.entries(def.actions).forEach(([ n, action ]) => {
56
57
  const aLoc = location.concat('actions', n);
57
58
  checkIfItemsOfItems(action, undefined, undefined, aLoc);
59
+ markBindingParamPaths(action, aLoc);
58
60
  forEachMemberRecursively(action, checkIfItemsOfItems, aLoc);
59
61
  checkIfItemsOfItems(action.returns, undefined, undefined, aLoc.concat('returns'));
62
+ markBindingParamPaths(action, aLoc);
60
63
  });
61
64
  }
62
65
 
@@ -124,6 +127,36 @@ function inboundQualificationChecks( csn, options, messageFunctions,
124
127
  message('chained-array-of', path);
125
128
  }
126
129
  }
130
+
131
+ // we need to know if the first path step is the bindind param
132
+ // for the rejection of V2 paths where the BP is ignored
133
+ function markBindingParamPaths( action, loc ) {
134
+ const special$self = !csn?.definitions?.$self && '$self';
135
+ if (action.params) {
136
+ const params = Object.entries(action.params);
137
+ const firstParam = params[0][1];
138
+ const type = firstParam?.items?.type || firstParam?.type;
139
+ if (type === special$self) {
140
+ const bindingParamName = params[0][0];
141
+ const markBindingParam = {
142
+ ref: (parent, prop, xpr) => {
143
+ if ((xpr[0].id || xpr[0]) === bindingParamName)
144
+ parent.$bparam = true;
145
+ },
146
+ };
147
+ let exprAnnos = Object.keys(action).filter(pn => findAnnotationExpression(action, pn));
148
+ exprAnnos.forEach((pn) => {
149
+ transformExpression(action, pn, markBindingParam, loc);
150
+ });
151
+ forEachMemberRecursively(action, (member, _memberName, _prop, path, _parent) => {
152
+ exprAnnos = Object.keys(member).filter(pn => findAnnotationExpression(member, pn));
153
+ exprAnnos.forEach((pn) => {
154
+ transformExpression(member, pn, markBindingParam, path);
155
+ });
156
+ }, loc);
157
+ }
158
+ }
159
+ }
127
160
  }
128
161
 
129
162
  function checkNestedContextsAndServices() {
@@ -127,7 +127,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
127
127
  const mySchemaName = whatsMySchemaName(defName);
128
128
  if (mySchemaName)
129
129
  setProp(def, '$mySchemaName', mySchemaName);
130
- if (isMyServiceRequested(defName) && def.kind !== 'aspect')
130
+ if (isMyServiceRequested(defName) && def.kind !== 'aspect' && def.kind !== 'event')
131
131
  reqDefs.definitions[defName] = def;
132
132
  },
133
133
  linkAssociationTarget,
@@ -1641,7 +1641,10 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
1641
1641
  if (art.type && !isBuiltinType(art.type))
1642
1642
  art = art._type || csnUtils.getCsnDef(art.type);
1643
1643
  }
1644
- keyPaths.push(...produceKeyRefPaths(art, prefix + options.pathDelimiter + k.ref.join(options.pathDelimiter), path));
1644
+ if (art === eltCsn)
1645
+ error('odata-key-recursive', path, { name: prefix });
1646
+ else
1647
+ keyPaths.push(...produceKeyRefPaths(art, prefix + options.pathDelimiter + k.ref.join(options.pathDelimiter), path));
1645
1648
  });
1646
1649
  }
1647
1650
  else {
@@ -2176,7 +2179,6 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
2176
2179
  let isSubTreeSpan = true;
2177
2180
 
2178
2181
  let rootPrefix = absPath.slice(1, absPath.length - 1);
2179
- const isExprAnno = (obj, pn) => isBetaEnabled(options, 'odataPathsInAnnotationExpressions') && findAnnotationExpression(obj, pn);
2180
2182
 
2181
2183
  const subTreeSpan = {
2182
2184
  ref: (parent, _prop, xpr) => {
@@ -2228,7 +2230,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
2228
2230
  if (absPath.length > 2) {
2229
2231
  const [ xprANames, nxprANames ] = Object.keys(carrier).reduce((acc, pn) => {
2230
2232
  if (pn[0] === '@')
2231
- acc[isExprAnno(carrier, pn) ? 0 : 1].push(pn);
2233
+ acc[findAnnotationExpression(carrier, pn) ? 0 : 1].push(pn);
2232
2234
  return acc;
2233
2235
  }, [ [], [] ]);
2234
2236
 
@@ -2244,8 +2246,10 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
2244
2246
  if (scope === 'actions' && def[scope][carrier.$path[3]]) {
2245
2247
  def = def[scope][carrier.$path[3]];
2246
2248
  scope = carrier.$path[4];
2247
- if (scope === 'params')
2249
+ if (scope === 'params') {
2248
2250
  rootPrefix = absPath.slice(2, absPath.length - 1);
2251
+ eltPath = absPath.slice(2).join('/');
2252
+ }
2249
2253
  if (scope === 'returns') {
2250
2254
  absPath[2] = '$ReturnType';
2251
2255
  rootPrefix = absPath.slice(3, absPath.length - 1);
@@ -2263,7 +2267,6 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
2263
2267
  else {
2264
2268
  absolutize.scope = scope;
2265
2269
  transformExpression(carrier, xprAName, absolutize);
2266
-
2267
2270
  if (!def[proxyDict])
2268
2271
  setProp(def, proxyDict, Object.create(null));
2269
2272
  let proxyCarrier = def[proxyDict][eltPath];