@sap/cds-compiler 4.9.4 → 5.0.6

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 (87) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/bin/cds_remove_invalid_whitespace.js +2 -1
  3. package/bin/cdsc.js +15 -11
  4. package/bin/cdshi.js +1 -0
  5. package/doc/CHANGELOG_BETA.md +7 -0
  6. package/lib/api/main.js +6 -18
  7. package/lib/api/options.js +3 -11
  8. package/lib/api/trace.js +0 -1
  9. package/lib/base/builtins.js +1 -0
  10. package/lib/base/location.js +4 -1
  11. package/lib/base/message-registry.js +29 -29
  12. package/lib/base/messages.js +22 -26
  13. package/lib/base/model.js +0 -2
  14. package/lib/base/node-helpers.js +0 -1
  15. package/lib/checks/enricher.js +1 -5
  16. package/lib/checks/structuredAnnoExpressions.js +30 -0
  17. package/lib/checks/validator.js +8 -0
  18. package/lib/compiler/assert-consistency.js +4 -1
  19. package/lib/compiler/base.js +1 -1
  20. package/lib/compiler/builtins.js +18 -2
  21. package/lib/compiler/checks.js +2 -5
  22. package/lib/compiler/define.js +7 -7
  23. package/lib/compiler/extend.js +68 -33
  24. package/lib/compiler/generate.js +1 -1
  25. package/lib/compiler/index.js +23 -6
  26. package/lib/compiler/lsp-api.js +501 -2
  27. package/lib/compiler/populate.js +2 -2
  28. package/lib/compiler/propagator.js +1 -4
  29. package/lib/compiler/resolve.js +2 -15
  30. package/lib/compiler/shared.js +112 -31
  31. package/lib/compiler/tweak-assocs.js +2 -16
  32. package/lib/compiler/utils.js +2 -1
  33. package/lib/compiler/xsn-model.js +4 -0
  34. package/lib/edm/annotations/genericTranslation.js +95 -42
  35. package/lib/edm/csn2edm.js +16 -4
  36. package/lib/edm/edm.js +2 -3
  37. package/lib/edm/edmAnnoPreprocessor.js +1 -2
  38. package/lib/edm/edmPreprocessor.js +1 -7
  39. package/lib/gen/Dictionary.json +29 -2
  40. package/lib/gen/language.checksum +1 -1
  41. package/lib/gen/language.interp +2 -1
  42. package/lib/gen/languageParser.js +4995 -4817
  43. package/lib/json/csnVersion.js +1 -1
  44. package/lib/json/from-csn.js +4 -7
  45. package/lib/json/to-csn.js +23 -12
  46. package/lib/language/antlrParser.js +2 -2
  47. package/lib/language/errorStrategy.js +0 -1
  48. package/lib/language/genericAntlrParser.js +35 -12
  49. package/lib/language/multiLineStringParser.js +3 -2
  50. package/lib/language/textUtils.js +1 -0
  51. package/lib/main.d.ts +28 -9
  52. package/lib/main.js +7 -4
  53. package/lib/model/csnRefs.js +20 -4
  54. package/lib/model/csnUtils.js +0 -2
  55. package/lib/model/revealInternalProperties.js +1 -1
  56. package/lib/modelCompare/compare.js +1 -1
  57. package/lib/optionProcessor.js +28 -9
  58. package/lib/render/manageConstraints.js +1 -1
  59. package/lib/render/toCdl.js +36 -7
  60. package/lib/render/toSql.js +1 -0
  61. package/lib/render/utils/common.js +12 -9
  62. package/lib/render/utils/stringEscapes.js +1 -0
  63. package/lib/transform/db/applyTransformations.js +13 -8
  64. package/lib/transform/db/associations.js +62 -54
  65. package/lib/transform/db/expansion.js +1 -6
  66. package/lib/transform/db/flattening.js +89 -111
  67. package/lib/transform/db/temporal.js +3 -4
  68. package/lib/transform/db/views.js +0 -1
  69. package/lib/transform/draft/odata.js +51 -3
  70. package/lib/transform/effective/annotations.js +3 -2
  71. package/lib/transform/effective/flattening.js +135 -0
  72. package/lib/transform/effective/main.js +6 -6
  73. package/lib/transform/effective/types.js +13 -9
  74. package/lib/transform/forOdata.js +0 -2
  75. package/lib/transform/forRelationalDB.js +0 -19
  76. package/lib/transform/localized.js +7 -8
  77. package/lib/transform/odata/flattening.js +39 -31
  78. package/lib/transform/odata/typesExposure.js +5 -17
  79. package/lib/transform/transformUtils.js +1 -1
  80. package/lib/transform/translateAssocsToJoins.js +21 -3
  81. package/lib/utils/file.js +13 -7
  82. package/lib/utils/moduleResolve.js +59 -8
  83. package/lib/utils/term.js +3 -2
  84. package/package.json +7 -3
  85. package/share/messages/message-explanations.json +2 -0
  86. package/share/messages/type-unexpected-foreign-keys.md +52 -0
  87. package/share/messages/type-unexpected-on-condition.md +52 -0
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { isEdmPropertyRendered, transformExpression } = require('../../model/csnUtils');
4
- const { isBuiltinType } = require('../../base/builtins');
4
+ const { isBuiltinType, isMagicVariable } = require('../../base/builtins');
5
5
  const edmUtils = require('../edmUtils.js');
6
6
  const oDataDictionary = require('../../gen/Dictionary.json');
7
7
  const preprocessAnnotations = require('./preprocessAnnotations.js');
@@ -60,6 +60,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
60
60
  if (defName.startsWith(`${serviceName}.`))
61
61
  assignParameterAnnotations(def);
62
62
  });
63
+
63
64
  // Crawl over the csn and trigger the annotation translation for all kinds
64
65
  // of annotated things.
65
66
  // Note: only works for single service
@@ -103,6 +104,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
103
104
  const scopeCheck = {
104
105
  ref: (elemref, prop, xpr, path) => {
105
106
  if (scopeCheck.scope === 'param' &&
107
+ !isMagicVariable(xpr[0]) &&
106
108
  (!elemref.param ||
107
109
  (xpr[0].id || xpr[0]) === '$self' && !def.elements.$self)) {
108
110
  error('odata-anno-xpr-ref', path, { anno: scopeCheck.anno, elemref, '#': 'notaparam' });
@@ -221,13 +223,16 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
221
223
 
222
224
  function handleDefinition( defName, def, location ) {
223
225
  // definition bound annotations
224
- handleAnnotations(defName, def, location);
226
+ handleAnnotations(defName, def, { location });
225
227
  // definition bound element annotations
226
228
  if (def.$elementsAnnoProxies) {
227
229
  Object.entries(def.$elementsAnnoProxies).forEach(([ elemPath, element ]) => {
228
230
  const edmTargetName = `${defName}/${elemPath}`;
229
- handleAnnotations(edmTargetName, element, element.$path,
230
- [ ...location, '$elementsAnnoProxies', elemPath ]);
231
+ handleAnnotations(edmTargetName, element,
232
+ {
233
+ location: element.$path,
234
+ csnPath: [ ...location, '$elementsAnnoProxies', elemPath ],
235
+ });
231
236
  });
232
237
  }
233
238
  // element bound annotations
@@ -235,7 +240,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
235
240
  Object.entries(def.elements).forEach(([ elemName, element ]) => {
236
241
  const edmTargetName = `${defName}/${elemName}`;
237
242
  const eLocation = [ ...location, 'elements', elemName ];
238
- handleAnnotations(edmTargetName, element, eLocation);
243
+ handleAnnotations(edmTargetName, element, { location: eLocation });
239
244
  });
240
245
  }
241
246
  // bound actions
@@ -261,6 +266,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
261
266
  const entityName = nameParts.pop();
262
267
 
263
268
  Object.entries(cObject.actions).forEach(([ n, action ]) => {
269
+ setProp(action, '$isBound', true);
264
270
  const actionName = `${serviceName}.${isV2() ? `${entityName}_` : ''}${n}`;
265
271
  handleAction(actionName, action, cObjectname, [ ...location, 'actions', n ]);
266
272
  });
@@ -273,6 +279,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
273
279
  // entityNameIfBound : qualified name of entity if bound action/function
274
280
  function handleAction( cActionName, cAction, entityNameIfBound, location ) {
275
281
  let actionName = cActionName;
282
+
276
283
  if (isV2()) { // Replace up to last dot with <serviceName>.EntityContainer
277
284
  const lastDotIndex = actionName.lastIndexOf('.');
278
285
  if (lastDotIndex > -1)
@@ -282,55 +289,70 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
282
289
  actionName += relParList();
283
290
  }
284
291
 
285
- handleAnnotations(actionName, cAction, location);
292
+ handleAnnotations(actionName, cAction, { location, cAction });
286
293
 
287
294
  if (cAction.params) {
288
295
  if (cAction.$paramsAnnoProxies) {
289
296
  Object.entries(cAction.$paramsAnnoProxies).forEach(([ paramPath, param ]) => {
290
- const edmTargetName = `${actionName}/${paramPath}`;
291
- handleAnnotations(edmTargetName, param, param.$path,
292
- [ ...location, '$paramsAnnoProxies', paramPath ]);
297
+ // skip explicit binding parameter in V2
298
+ if (!(options.isV2() && param.type === '$self' && paramPath === cAction.$bindingParam?.name)) {
299
+ const edmTargetName = `${actionName}/${paramPath}`;
300
+ handleAnnotations(edmTargetName, param,
301
+ {
302
+ location: param.$path,
303
+ csnPath: [ ...location, '$paramsAnnoProxies', paramPath ],
304
+ cAction,
305
+ });
306
+ }
293
307
  });
294
308
  }
309
+ // explicit binding parameter is removed from params in V2 during
310
+ // createActionV2(), no need to check ;)
295
311
  Object.entries(cAction.params).forEach(([ n, p ]) => {
296
312
  const edmTargetName = `${actionName}/${n}`;
297
313
  handleAnnotations(edmTargetName, p,
298
- [ ...location, 'params', n ]);
314
+ {
315
+ action: true,
316
+ location: [ ...location, 'params', n ],
317
+ cAction,
318
+ });
299
319
  });
300
320
  }
301
321
  if (cAction.returns) {
302
322
  if (cAction.$returnsAnnoProxies) {
303
323
  Object.entries(cAction.$returnsAnnoProxies).forEach(([ returnsPath, returns ]) => {
304
324
  const edmTargetName = `${actionName}/${returnsPath}`;
305
- handleAnnotations(edmTargetName, returns, returns.$path,
306
- [ ...location, '$returnsAnnoProxies', returnsPath ]);
325
+ handleAnnotations(edmTargetName, returns,
326
+ {
327
+ location: returns.$path,
328
+ csnPath: [ ...location, '$returnsAnnoProxies', returnsPath ],
329
+ cAction,
330
+ });
307
331
  });
308
332
  }
309
333
  const edmTargetName = `${actionName}/$ReturnType`;
310
334
  setProp(cAction.returns, '$appliesToReturnType', true);
311
335
  handleAnnotations(edmTargetName, cAction.returns,
312
- [ ...location, 'returns' ]);
336
+ {
337
+ location: [ ...location, 'returns' ],
338
+ cAction,
339
+ });
313
340
  delete cAction.returns.$appliesToReturnType;
314
341
  }
315
342
 
316
343
  function relParList() {
317
- // we rely on the order of params in the csn being the correct one
344
+ // we rely on the order of params in the csn being the correct one
318
345
  const params = [];
319
346
  if (entityNameIfBound) {
320
347
  // If this is an action and has an explicit binding parameter add it here
321
- if (cAction.$bindingParam && cAction.kind === 'action') {
348
+ if (cAction.$bindingParam && cAction.kind === 'action' ||
349
+ cAction.$bindingParam?.viaAnno) {
322
350
  params.push(
323
351
  cAction.$bindingParam.items
324
352
  ? `Collection(${entityNameIfBound})`
325
353
  : entityNameIfBound
326
354
  );
327
355
  }
328
- // If action/function has no explicit binding parameter add it here
329
- else if (!cAction.$bindingParam) {
330
- params.push(cAction['@cds.odata.bindingparameter.collection']
331
- ? `Collection(${entityNameIfBound})`
332
- : entityNameIfBound);
333
- }
334
356
  }
335
357
  // In case this is a function the explicit binding parameter is part of
336
358
  // the functions params dictionary. Only for functions all parameters must
@@ -348,12 +370,12 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
348
370
  return edmUtils.mapCdsToEdmType(p, messageFunctions, false /* is only called for v4 */);
349
371
  }
350
372
  else if (options.whatsMySchemaName) {
351
- const schemaName = options.whatsMySchemaName(p.type);
373
+ const schemaName = options.whatsMySchemaName(p._edmType || p.type);
352
374
  // strip the service namespace of from a parameter type
353
375
  if (schemaName && schemaName !== options.serviceName)
354
- return p.type.replace(`${options.serviceName}.`, '');
376
+ return (p._edmType || p.type).replace(`${options.serviceName}.`, '');
355
377
  }
356
- return p.type;
378
+ return p._edmType || p.type;
357
379
  }
358
380
  }
359
381
  }
@@ -363,7 +385,9 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
363
385
  // edmTargetName : string, name of the target in edm
364
386
  // carrier: object, the annotated cds thing, contains all the annotations
365
387
  // as properties with names starting with @
366
- function handleAnnotations( edmTargetName, carrier, location, csnPathResolutionLocation = location ) {
388
+ // ctx: locations and other information that is required to write the
389
+ // annotations
390
+ function handleAnnotations( edmTargetName, carrier, ctx ) {
367
391
  // collect the names of the carrier's annotation properties
368
392
  // keep only those annotations that - start with a known vocabulary name
369
393
  // - have a value other than null
@@ -377,6 +401,8 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
377
401
  (isV2() && (edmUtils.isDerivedType(carrier))))
378
402
  return;
379
403
 
404
+ if (ctx.location == null)
405
+ throw Error('location required');
380
406
 
381
407
  // Filter unknown toplevel annotations
382
408
  // Final filtering of all annotations is done in handleTerm
@@ -396,15 +422,15 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
396
422
  transformExpression(carrier, knownAnno, {
397
423
  ref: (elemref, prop, xpr, csnPath) => {
398
424
  if (options.isV2() && elemref.$bparam) {
399
- error('odata-anno-xpr-ref', location, {
400
- elemref, anno: knownAnno, version: '2.0', '#': 'bparam_v2',
425
+ error('odata-anno-xpr-ref', ctx.location, {
426
+ elemref, anno: knownAnno, version: '2.0', '#': 'bparam_v2_expl',
401
427
  });
402
428
  return;
403
429
  }
404
430
  const { links, scope } = reqDefsUtils.inspectRef(csnPath);
405
431
  let i = scope === '$self' ? 1 : 0;
406
432
  if (scope === '$magic') {
407
- error('odata-anno-xpr-ref', location, {
433
+ error('odata-anno-xpr-ref', ctx.location, {
408
434
  elemref, anno: knownAnno, '#': 'magic',
409
435
  });
410
436
  return;
@@ -412,7 +438,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
412
438
  let stop = false;
413
439
  for (; i < links.length && !stop; i++) {
414
440
  if (!isEdmPropertyRendered(links[i].art, csnPath)) {
415
- error('odata-anno-xpr-ref', location, {
441
+ error('odata-anno-xpr-ref', ctx.location, {
416
442
  count: i + 1, elemref, anno: knownAnno, '#': 'notrendered',
417
443
  });
418
444
  stop = true;
@@ -421,16 +447,27 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
421
447
  const proxy = links[i].art?._target;
422
448
  const eltName = links[i + 1].art?.name;
423
449
  if (!proxy.elements[eltName]) {
424
- error('odata-anno-xpr-ref', location, {
450
+ error('odata-anno-xpr-ref', ctx.location, {
425
451
  count: i + 2, elemref, anno: knownAnno, '#': 'notrendered',
426
452
  });
427
453
  stop = true;
428
454
  }
429
455
  }
430
456
  }
457
+ if (!stop && ctx.cAction?.$isBound && scope === '$self') {
458
+ if (options.isV2()) {
459
+ error('odata-anno-xpr-ref', ctx.location, {
460
+ elemref, anno: knownAnno, version: '2.0', '#': 'bparam_v2_impl',
461
+ });
462
+ }
463
+ else {
464
+ xpr[0] = ctx.cAction.$bindingParam.name;
465
+ elemref.param = true;
466
+ }
467
+ }
431
468
  },
432
- }, csnPathResolutionLocation);
433
- xpr2edmJson(carrier, knownAnno, location, options, messageFunctions);
469
+ }, ctx.csnPath || ctx.location);
470
+ xpr2edmJson(carrier, knownAnno, ctx.location, options, messageFunctions);
434
471
  }
435
472
  });
436
473
 
@@ -457,7 +494,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
457
494
  const alternativeAnnotations = [];
458
495
 
459
496
  // now create annotation objects for all the annotations of carrier
460
- handleAnno2(addAnnotation, prefixTree, location);
497
+ handleAnno2(addAnnotation, prefixTree, ctx.location);
461
498
 
462
499
  // Produce Edm.Annotations and attach collected Edm.Annotation(s) to the
463
500
  // envelope (or directly to the Schema)
@@ -506,7 +543,6 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
506
543
  }
507
544
 
508
545
  function initCarrierControlVars() {
509
- // eslint-disable-next-line no-unused-vars
510
546
  let testToStandardEdmTargetP = () => true; // if true, assign to standard Edm Target
511
547
  let stdEdmTargetNameP = edmTargetName;
512
548
  let alternativeEdmTargetNameP = null;
@@ -516,13 +552,14 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
516
552
  if (carrier.kind === 'entity') {
517
553
  // If AppliesTo=[EntitySet/Singleton/Collection, EntityType], EntitySet/Singleton/Collection has precedence
518
554
  testToAlternativeEdmTargetP = ((x) => {
519
- if (options.isV2())
520
- return [ 'Singleton', 'EntitySet', 'Collection' ].some(y => x.includes(y));
521
-
522
-
523
- return edmUtils.isSingleton(carrier)
524
- ? x.includes('Singleton')
525
- : [ 'EntitySet', 'Collection' ].some(y => x.includes(y));
555
+ if (x) {
556
+ if (options.isV2())
557
+ return [ 'Singleton', 'EntitySet', 'Collection' ].some(y => x.includes(y));
558
+ return edmUtils.isSingleton(carrier)
559
+ ? x.includes('Singleton')
560
+ : [ 'EntitySet', 'Collection' ].some(y => x.includes(y));
561
+ }
562
+ return true;
526
563
  });
527
564
  testToStandardEdmTargetP = (x => (x ? x.includes('EntityType') : true));
528
565
  // if carrier has an alternate 'entitySetName' use this instead of EdmTargetName
@@ -540,6 +577,23 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
540
577
  else if (carrier.kind === 'type') {
541
578
  testToStandardEdmTargetP = (x => (x ? x.includes(carrier.elements ? 'ComplexType' : 'TypeDefinition') : true));
542
579
  }
580
+ else if (carrier.kind === 'action' || carrier.kind === 'function') {
581
+ const type = carrier.kind === 'action' ? 'Action' : 'Function';
582
+ const container = carrier.kind === 'action' ? 'ActionImport' : 'FunctionImport';
583
+ if (options.isV4()) {
584
+ testToStandardEdmTargetP = (x => (x ? x.includes(type) : true));
585
+ // Unbound actions/functions are Action/FunctionImports and are bound to container target
586
+ testToAlternativeEdmTargetP = (x => (x ? x.includes(container) && !carrier.$isBound : true));
587
+ const lastDotIndex = carrier.name.lastIndexOf('.');
588
+ alternativeEdmTargetNameP = lastDotIndex > -1
589
+ ? `${serviceName}.EntityContainer/${carrier.name.substring(lastDotIndex + 1)}`
590
+ : `${serviceName}.EntityContainer/${carrier.name}`;
591
+ hasAlternativeCarrierP = true;
592
+ }
593
+ if (options.isV2())
594
+ // same as in V4 but everything goes to standard target
595
+ testToStandardEdmTargetP = (x => (x ? x.includes(type) || (x.includes(container) && !carrier.$isBound) : true));
596
+ }
543
597
  else if (carrier.kind === 'service') {
544
598
  // if annotated object is a service, annotation goes to EntityContainer,
545
599
  // except if AppliesTo contains Schema but not EntityContainer, then annotation goes to Schema
@@ -764,7 +818,6 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
764
818
  // addAnnotationFunc needs AppliesTo message from dictionary to decide where to put the anno
765
819
  const termName = fullTermName.replace(/#(\w+)$/g, ''); // remove qualifier
766
820
  const dictTerm = getDictTerm(termName, msg); // message for unknown term was already issued in handleTerm
767
- // eslint-disable-next-line sonarjs/no-collapsible-if
768
821
  if (!addAnnotationFunc(anno, dictTerm && dictTerm.AppliesTo)) {
769
822
  if (dictTerm && dictTerm.AppliesTo) {
770
823
  message('odata-anno-def', location,
@@ -732,11 +732,13 @@ function csn2edmAll( _csn, _options, serviceNames, messageFunctions ) {
732
732
  if (type === special$self) {
733
733
  bpName = entries[0][0];
734
734
  setProp(actionCsn, '$bindingParam', firstParam);
735
+ // preserve the original type (as it is the key to reqDefs.defintions)
736
+ // for annotation path resolution (eg. for $draft.IsActiveEntity)
735
737
  if (bpType) {
736
738
  if (firstParam.items?.type)
737
- firstParam.items.type = bpType;
739
+ setProp(firstParam.items, '_edmType', bpType);
738
740
  if (firstParam.type)
739
- firstParam.type = bpType;
741
+ setProp(firstParam, '_edmType', bpType);
740
742
  }
741
743
  if (!edmUtils.isODataSimpleIdentifier(bpName))
742
744
  message('odata-spec-violation-id', [ ...location, 'params', bpName ], { id: bpName });
@@ -775,11 +777,20 @@ function csn2edmAll( _csn, _options, serviceNames, messageFunctions ) {
775
777
  if (entityCsn) {
776
778
  actionNode.setEdmAttribute('IsBound', true);
777
779
  if (!actionCsn.$bindingParam) {
780
+ const bpDef = {
781
+ name: bpName,
782
+ viaAnno: true,
783
+ };
778
784
  // Binding Parameter: 'in' at first position in sequence, this is decisive!
779
- if (actionCsn['@cds.odata.bindingparameter.collection'])
785
+ if (actionCsn['@cds.odata.bindingparameter.collection']) {
780
786
  actionNode.append(new Edm.Parameter(v, { Name: bpName, Type: bpType, Collection: true/* , Nullable: false */ } ));
781
- else
787
+ bpDef.items = { type: bpType };
788
+ }
789
+ else {
782
790
  actionNode.append(new Edm.Parameter(v, { Name: bpName, Type: bpType } ));
791
+ bpDef.type = bpType;
792
+ }
793
+ setProp(actionCsn, '$bindingParam', bpDef);
783
794
  }
784
795
  }
785
796
  else if (EntityContainer) { // unbound => produce Action/FunctionImport
@@ -891,6 +902,7 @@ function csn2edmAll( _csn, _options, serviceNames, messageFunctions ) {
891
902
  if (i === 0 && type === special$self) {
892
903
  // skip and remove the first parameter if it is a $self binding parameter to
893
904
  // omit annotation rendering later on
905
+ setProp(actionCsn, '$bindingParam', parameterCsn);
894
906
  delete actionCsn.params[parameterName];
895
907
  }
896
908
  else {
package/lib/edm/edm.js CHANGED
@@ -625,7 +625,8 @@ function getEdm( options, messageFunctions ) {
625
625
  edmUtils.addTypeFacets(this, this._scalarType);
626
626
  }
627
627
  else {
628
- this._edmAttributes[typeName] = typecsn.type;
628
+ // it's either _edmType or type (_edmType only used for explicit binding param)
629
+ this._edmAttributes[typeName] = typecsn._edmType || typecsn.type;
629
630
  }
630
631
  }
631
632
  // CDXCORE-245:
@@ -897,7 +898,6 @@ function getEdm( options, messageFunctions ) {
897
898
  super(version, attributes, csn);
898
899
  // TIPHANACDS-4180
899
900
  if (this.v2) {
900
- // eslint-disable-next-line sonarjs/no-redundant-boolean
901
901
  if (csn['@odata.etag'] || csn['@cds.etag'])
902
902
  this._edmAttributes.ConcurrencyMode = 'Fixed';
903
903
 
@@ -1037,7 +1037,6 @@ function getEdm( options, messageFunctions ) {
1037
1037
  See csn2edm.createEntityTypeAndSet() for details
1038
1038
  2) ContainsTarget stems from the @odata.contained annotation
1039
1039
  */
1040
- // eslint-disable-next-line sonarjs/no-redundant-boolean
1041
1040
  if (csn['@odata.contained'] || csn.containsTarget)
1042
1041
  this._edmAttributes.ContainsTarget = true;
1043
1042
 
@@ -59,7 +59,6 @@ function applyAppSpecificLateCsnTransformationOnElement( options, element, struc
59
59
  // runtime cannot set that okra flag (alternatively the runtime has to search
60
60
  // for @[odata|cds].etag annotations...
61
61
  if (options.isV4() && (element['@odata.etag'] || element['@cds.etag'])) {
62
- // eslint-disable-next-line sonarjs/no-redundant-boolean
63
62
  // don't put element name into collection as per advice from Ralf Handl, as
64
63
  // no runtime is interested in the property itself, it is sufficient to mark
65
64
  // the entity set.
@@ -243,7 +242,7 @@ function setSAPSpecificV2AnnotationsToEntitySet( options, carrier ) {
243
242
  '@sap.updatable.path': addToSetAttr,
244
243
  '@sap.deletable.path': addToSetAttr,
245
244
  '@sap.searchable': addToSetAttr,
246
- '@sap.pagable': addToSetAttr,
245
+ '@sap.pageable': addToSetAttr,
247
246
  '@sap.topable': addToSetAttr,
248
247
  '@sap.countable': addToSetAttr,
249
248
  '@sap.addressable': addToSetAttr,
@@ -100,7 +100,6 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
100
100
  as a step in the OData transformer with the goal to have a protocol agnostic OData CSN.
101
101
  */
102
102
  if (csn.meta && csn.meta.options && csn.meta.options.odataVersion === 'v4' && options.isV2()) {
103
- // eslint-disable-next-line global-require
104
103
  const { toFinalBaseType } = require('../transform/transformUtils').getTransformers(csn, options, messageFunctions);
105
104
  expandCSNToFinalBaseType(csn, { toFinalBaseType }, csnUtils, serviceRootNames, options);
106
105
  }
@@ -704,11 +703,6 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
704
703
  validFrom.push(element);
705
704
 
706
705
  // forward annotations from managed association element to its foreign keys
707
- // TODO: Try to eliminate this code by rearranging
708
- // forOdata::addCommonValueListviaAssociation(member, memberName)
709
- // such that the VL annotations are distributed to the associations *before*
710
- // FK creation.
711
- // The FK creation already propagates the annotations from the association
712
706
  const elements = construct.items?.elements || construct.elements;
713
707
  const assoc = elements[element['@odata.foreignKey4']];
714
708
  if (assoc) {
@@ -1915,7 +1909,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
1915
1909
  function markCollection( obj ) {
1916
1910
  const items = obj.items || csn.definitions[obj.type] && csn.definitions[obj.type].items;
1917
1911
  if (items) {
1918
- edmUtils.assignProp(obj, '_NotNullCollection', items.notNull !== undefined ? items.notNull : true);
1912
+ edmUtils.assignProp(obj, '_NotNullCollection', items.notNull !== undefined ? items.notNull : false);
1919
1913
  edmUtils.assignProp(obj, '$isCollection', true);
1920
1914
  }
1921
1915
  }
@@ -1885,9 +1885,18 @@
1885
1885
  "UI.Placeholder": {
1886
1886
  "Type": "Edm.String",
1887
1887
  "AppliesTo": [
1888
- "Property"
1888
+ "Property",
1889
+ "Parameter"
1889
1890
  ]
1890
1891
  },
1892
+ "UI.InputMask": {
1893
+ "Type": "UI.InputMaskType",
1894
+ "AppliesTo": [
1895
+ "Property",
1896
+ "Parameter"
1897
+ ],
1898
+ "$experimental": true
1899
+ },
1891
1900
  "UI.TextArrangement": {
1892
1901
  "Type": "UI.TextArrangementType",
1893
1902
  "AppliesTo": [
@@ -3823,7 +3832,8 @@
3823
3832
  "ResultSizeDefault": "Edm.Int32",
3824
3833
  "ResultSizeMaximum": "Edm.Int32",
3825
3834
  "IANATimezoneFormat": "Edm.Boolean",
3826
- "Treeview": "Edm.Boolean"
3835
+ "Treeview": "Edm.Boolean",
3836
+ "TextDirectionLayout": "Edm.Boolean"
3827
3837
  }
3828
3838
  },
3829
3839
  "PersonalData.EntitySemanticsType": {
@@ -4274,6 +4284,23 @@
4274
4284
  "High": "Edm.PrimitiveType"
4275
4285
  }
4276
4286
  },
4287
+ "UI.InputMaskType": {
4288
+ "$kind": "ComplexType",
4289
+ "Properties": {
4290
+ "Mask": "Edm.String",
4291
+ "PlaceholderSymbol": "Edm.String",
4292
+ "Rules": "Collection(UI.InputMaskRuleType)"
4293
+ },
4294
+ "$experimental": true
4295
+ },
4296
+ "UI.InputMaskRuleType": {
4297
+ "$kind": "ComplexType",
4298
+ "Properties": {
4299
+ "MaskSymbol": "Edm.String",
4300
+ "RegExp": "Edm.String"
4301
+ },
4302
+ "$experimental": true
4303
+ },
4277
4304
  "UI.NoteType": {
4278
4305
  "$kind": "ComplexType",
4279
4306
  "Properties": {
@@ -1 +1 @@
1
- 0c76b255e5fe55c0f8527a4d9f1b563f
1
+ d2eab9ea0d46c406f6078d8a1125152e