@sap/cds-compiler 4.6.0 → 4.7.4

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 (70) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/bin/cds_update_identifiers.js +6 -2
  3. package/bin/cdsc.js +1 -1
  4. package/doc/CHANGELOG_ARCHIVE.md +9 -9
  5. package/doc/CHANGELOG_BETA.md +6 -0
  6. package/lib/api/main.js +56 -9
  7. package/lib/api/options.js +6 -3
  8. package/lib/api/validate.js +20 -29
  9. package/lib/base/message-registry.js +27 -3
  10. package/lib/base/messages.js +8 -3
  11. package/lib/base/model.js +2 -0
  12. package/lib/checks/dbFeatureFlags.js +28 -0
  13. package/lib/checks/elements.js +81 -13
  14. package/lib/checks/enricher.js +3 -2
  15. package/lib/checks/validator.js +38 -4
  16. package/lib/compiler/assert-consistency.js +4 -4
  17. package/lib/compiler/checks.js +5 -4
  18. package/lib/compiler/define.js +2 -2
  19. package/lib/compiler/generate.js +2 -1
  20. package/lib/compiler/populate.js +5 -1
  21. package/lib/compiler/propagator.js +3 -11
  22. package/lib/compiler/shared.js +2 -1
  23. package/lib/compiler/tweak-assocs.js +43 -24
  24. package/lib/edm/annotations/edmJson.js +3 -0
  25. package/lib/edm/annotations/genericTranslation.js +156 -106
  26. package/lib/edm/annotations/preprocessAnnotations.js +11 -14
  27. package/lib/edm/csn2edm.js +27 -24
  28. package/lib/edm/edm.js +8 -8
  29. package/lib/edm/edmPreprocessor.js +135 -37
  30. package/lib/edm/edmUtils.js +20 -7
  31. package/lib/gen/Dictionary.json +2 -1
  32. package/lib/gen/language.checksum +1 -1
  33. package/lib/gen/language.interp +9 -11
  34. package/lib/gen/languageParser.js +5942 -5446
  35. package/lib/json/to-csn.js +7 -114
  36. package/lib/language/genericAntlrParser.js +106 -48
  37. package/lib/model/cloneCsn.js +203 -0
  38. package/lib/model/csnRefs.js +11 -3
  39. package/lib/model/csnUtils.js +42 -85
  40. package/lib/optionProcessor.js +2 -2
  41. package/lib/render/manageConstraints.js +1 -1
  42. package/lib/render/toCdl.js +133 -88
  43. package/lib/render/toHdbcds.js +1 -5
  44. package/lib/render/toSql.js +7 -9
  45. package/lib/render/utils/common.js +9 -16
  46. package/lib/transform/addTenantFields.js +277 -102
  47. package/lib/transform/db/applyTransformations.js +14 -9
  48. package/lib/transform/db/backlinks.js +2 -1
  49. package/lib/transform/db/constraints.js +60 -82
  50. package/lib/transform/db/expansion.js +6 -6
  51. package/lib/transform/db/featureFlags.js +5 -0
  52. package/lib/transform/db/flattening.js +4 -4
  53. package/lib/transform/db/killAnnotations.js +1 -0
  54. package/lib/transform/db/rewriteCalculatedElements.js +2 -2
  55. package/lib/transform/db/transformExists.js +12 -0
  56. package/lib/transform/db/views.js +5 -2
  57. package/lib/transform/draft/odata.js +7 -6
  58. package/lib/transform/effective/associations.js +2 -1
  59. package/lib/transform/effective/main.js +3 -2
  60. package/lib/transform/effective/types.js +6 -3
  61. package/lib/transform/forOdata.js +39 -24
  62. package/lib/transform/forRelationalDB.js +34 -27
  63. package/lib/transform/localized.js +29 -9
  64. package/lib/transform/odata/flattening.js +419 -0
  65. package/lib/transform/odata/toFinalBaseType.js +95 -15
  66. package/lib/transform/odata/typesExposure.js +9 -7
  67. package/lib/transform/transformUtils.js +7 -6
  68. package/lib/transform/translateAssocsToJoins.js +3 -3
  69. package/lib/utils/objectUtils.js +14 -0
  70. package/package.json +1 -1
package/lib/edm/edm.js CHANGED
@@ -664,7 +664,7 @@ function getEdm( options, messageFunctions ) {
664
664
  }
665
665
 
666
666
  // Set the collection property if this is either an element, parameter or a term def
667
- this._isCollection = (csn.kind === undefined || csn.kind === 'annotation') ? csn._isCollection : false;
667
+ this.$isCollection = (csn.kind === undefined || csn.kind === 'annotation') ? csn.$isCollection : false;
668
668
 
669
669
  if (options.whatsMySchemaName && this._edmAttributes[typeName]) {
670
670
  const schemaName = options.whatsMySchemaName(this._edmAttributes[typeName]);
@@ -675,7 +675,7 @@ function getEdm( options, messageFunctions ) {
675
675
  // store undecorated type for JSON
676
676
  this._type = this._edmAttributes[typeName];
677
677
  // decorate for XML (not for Complex/EntityType)
678
- if (this._isCollection && this._edmAttributes[typeName])
678
+ if (this.$isCollection && this._edmAttributes[typeName])
679
679
  this._edmAttributes[typeName] = `Collection(${this._edmAttributes[typeName]})`;
680
680
  }
681
681
 
@@ -694,8 +694,8 @@ function getEdm( options, messageFunctions ) {
694
694
  });
695
695
  }
696
696
 
697
- if (this._isCollection)
698
- json.$Collection = this._isCollection;
697
+ if (this.$isCollection)
698
+ json.$Collection = this.$isCollection;
699
699
 
700
700
  return json;
701
701
  }
@@ -848,7 +848,7 @@ function getEdm( options, messageFunctions ) {
848
848
 
849
849
  setNullable() {
850
850
  // From the Spec: In OData 4.01 responses a collection-valued property MUST specify a value for the Nullable attribute.
851
- if (this._isCollection)
851
+ if (this.$isCollection)
852
852
  this._edmAttributes.Nullable = !this.isNotNullable();
853
853
 
854
854
  // Nullable=true is default, mention Nullable=false only in XML
@@ -1000,7 +1000,7 @@ function getEdm( options, messageFunctions ) {
1000
1000
  const [ src, tgt ] = edmUtils.determineMultiplicity(csn._constraints._partnerCsn || csn);
1001
1001
  csn._constraints._multiplicity = csn._constraints._partnerCsn ? [ tgt, src ] : [ src, tgt ];
1002
1002
  this._type = attributes.Type;
1003
- this._isCollection = this.isToMany();
1003
+ this.$isCollection = this.isToMany();
1004
1004
  this._targetCsn = csn._target;
1005
1005
 
1006
1006
  if (this.v4) {
@@ -1008,7 +1008,7 @@ function getEdm( options, messageFunctions ) {
1008
1008
  this._edmAttributes.Nullable = false;
1009
1009
 
1010
1010
  // either csn has multiplicity or we have to use the multiplicity of the backlink
1011
- if (this._isCollection) {
1011
+ if (this.$isCollection) {
1012
1012
  this._edmAttributes.Type = `Collection(${attributes.Type})`;
1013
1013
  // attribute Nullable is not allowed in combination with Collection (see Spec)
1014
1014
  // Even if min cardinality is > 0, remove Nullable, because the implicit OData contract
@@ -1082,7 +1082,7 @@ function getEdm( options, messageFunctions ) {
1082
1082
  return (nodeCsn.notNull === true && !nodeCsn.target || tgtCard.min > 0);
1083
1083
  }
1084
1084
  isToMany() {
1085
- return (this._isCollection || this._csn._constraints._multiplicity[1] === '*');
1085
+ return (this.$isCollection || this._csn._constraints._multiplicity[1] === '*');
1086
1086
  }
1087
1087
 
1088
1088
  toJSONattributes(json) {
@@ -4,14 +4,17 @@
4
4
  const { setProp, isDeprecatedEnabled, isBetaEnabled } = require('../base/model');
5
5
  const {
6
6
  forEachDefinition, forEachGeneric, forEachMemberRecursively,
7
- isEdmPropertyRendered, getUtils, cloneCsnNonDict,
8
- isBuiltinType, applyTransformations, cloneAnnotationValue, cardinality2str, isAnnotationExpression,
7
+ isEdmPropertyRendered, getUtils,
8
+ isBuiltinType, applyTransformations, transformExpression, findAnnotationExpression,
9
+ cardinality2str, isMagicVariable,
9
10
  } = require('../model/csnUtils');
10
11
  const edmUtils = require('./edmUtils.js');
11
12
  const edmAnnoPreproc = require('./edmAnnoPreprocessor.js');
12
13
  const { inboundQualificationChecks } = require('./edmInboundChecks.js');
13
14
  const typesExposure = require('../transform/odata/typesExposure');
14
15
  const expandCSNToFinalBaseType = require('../transform/odata/toFinalBaseType');
16
+ const { cloneCsnNonDict, cloneAnnotationValue } = require('../model/cloneCsn');
17
+ const { forEach, forEachKey } = require('../utils/objectUtils.js');
15
18
 
16
19
  const NavResAnno = '@Capabilities.NavigationRestrictions.RestrictedProperties';
17
20
 
@@ -504,16 +507,10 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
504
507
  setProp(parameterCsn, '_origin', entityCsn);
505
508
  // create the Type Definition
506
509
  // modify the original parameter entity with backlink and new name
507
- if (csn.definitions[typeEntityName]) {
510
+ if (csn.definitions[typeEntityName])
508
511
  error('odata-definition-exists', [ 'definitions', entityName ], { '#': 'std', name: typeEntityName });
509
- }
510
- else {
511
- csn.definitions[typeEntityName] = entityCsn;
512
- reqDefs.definitions[typeEntityName] = entityCsn;
513
- delete csn.definitions[entityCsn.name];
514
- delete reqDefs.definitions[entityCsn.name];
512
+ else
515
513
  entityCsn.name = typeEntityName;
516
- }
517
514
  setProp(entityCsn, '$entitySetName', typeEntitySetName);
518
515
  // add backlink association
519
516
  if (hasBacklink) {
@@ -526,15 +523,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
526
523
  setProp(entityCsn.elements[typeToParameterAssocName], '_selfReferences', []);
527
524
  setProp(entityCsn.elements[typeToParameterAssocName], '_target', parameterCsn);
528
525
  setProp(entityCsn.elements[typeToParameterAssocName], '$path',
529
- [ 'definitions', typeEntityName, 'elements', typeToParameterAssocName ] );
530
-
531
- // rewrite $path
532
- if (entityCsn.$path)
533
- entityCsn.$path[1] = typeEntityName;
534
- forEachMemberRecursively(entityCsn, (member) => {
535
- if (member.$path)
536
- member.$path[1] = typeEntityName;
537
- });
526
+ [ 'definitions', entityName, 'elements', typeToParameterAssocName ] );
538
527
  }
539
528
 
540
529
  /*
@@ -720,10 +709,10 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
720
709
  // such that the VL annotations are distributed to the associations *before*
721
710
  // FK creation.
722
711
  // The FK creation already propagates the annotations from the association
723
- const elements = construct.items && construct.items.elements || construct.elements;
712
+ const elements = construct.items?.elements || construct.elements;
724
713
  const assoc = elements[element['@odata.foreignKey4']];
725
714
  if (assoc) {
726
- Object.keys(assoc).filter(pn => pn[0] === '@' && !isAnnotationExpression(assoc[pn])).forEach((pn) => {
715
+ Object.keys(assoc).filter(pn => pn[0] === '@' && !findAnnotationExpression(assoc, pn)).forEach((pn) => {
727
716
  edmUtils.assignAnnotation(element, pn, assoc[pn]);
728
717
  });
729
718
  }
@@ -731,15 +720,16 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
731
720
  if (options.isV2())
732
721
  edmAnnoPreproc.setSAPSpecificV2AnnotationsToAssociation(element);
733
722
 
723
+ const absPath = $path2path(element.$path);
724
+
734
725
  // initialize an association
735
726
  if (element.target) {
736
727
  // in case this is a forward assoc, store the backlink partners here, _selfReferences.length > 1 => error
737
728
  edmUtils.assignProp(element, '_selfReferences', []);
738
729
  edmUtils.assignProp(element._target, '$proxies', []);
739
730
  // $abspath is used as partner path
740
- edmUtils.assignProp(element, '$abspath', $path2path(element.$path));
731
+ edmUtils.assignProp(element, '$abspath', absPath);
741
732
  }
742
-
743
733
  // Collect keys
744
734
  if (element.key)
745
735
  keys[elementName] = element;
@@ -935,7 +925,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
935
925
  const targetSchemaName = fqSchemaName.replace(`${srn}.`, '');
936
926
  if (serviceRootNames.includes(targetSchemaName)) {
937
927
  // remove all definitions starting with < fqSchemaName >. and add a schema reference
938
- Object.keys(csn.definitions).forEach((dn) => {
928
+ forEachKey(csn.definitions, (dn) => {
939
929
  if (dn.startsWith(fqSchemaName)) {
940
930
  delete csn.definitions[dn];
941
931
  delete reqDefs.definitions[dn];
@@ -1075,7 +1065,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
1075
1065
  function muteNavProp( elt, msg = 'std' ) {
1076
1066
  edmUtils.assignAnnotation(elt, '@odata.navigable', false);
1077
1067
  if (elt._target['@cds.autoexpose'] !== false) {
1078
- warning('odata-navigation', [ 'definitions', struct.name, 'elements', elt.name ],
1068
+ warning('odata-navigation', elt.$path,
1079
1069
  { target: elt._target.name, service: globalSchemaPrefix, '#': msg });
1080
1070
  }
1081
1071
  }
@@ -1118,7 +1108,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
1118
1108
  setProp(proxy, '$hasEntitySet', false);
1119
1109
  setProp(proxy, '$exposedTypes', Object.create(null));
1120
1110
  // copy all annotations of the target to the proxy
1121
- Object.entries(assoc._target).forEach(([ k, v ]) => {
1111
+ forEach(assoc._target, ( k, v ) => {
1122
1112
  if (k[0] === '@' && k !== '@open')
1123
1113
  proxy[k] = v;
1124
1114
  });
@@ -1165,7 +1155,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
1165
1155
  }
1166
1156
  else {
1167
1157
  newElt = Object.create(null);
1168
- Object.keys(e).forEach((prop) => {
1158
+ forEachKey(e, (prop) => {
1169
1159
  newElt[prop] = e[prop];
1170
1160
  });
1171
1161
  }
@@ -1241,7 +1231,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
1241
1231
  if (typeClone) {
1242
1232
  // Recurse into elements of 'type' (if any)
1243
1233
  if (typeClone.elements) {
1244
- Object.entries(typeClone.elements).forEach(([ elemName, elem ]) => {
1234
+ forEach(typeClone.elements, ( elemName, elem ) => {
1245
1235
  // if this is a foreign key element, we must check whether or not the association
1246
1236
  // has been exposed as proxy. If it has not been exposed, no further structured
1247
1237
  // types must be exposed as 'Proxy_' types.
@@ -1298,10 +1288,10 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
1298
1288
  type['@open'] = typeDef['@open'];
1299
1289
 
1300
1290
  if (typeDef.elements) {
1301
- Object.entries(typeDef.elements).forEach( ([ elemName, elem ]) => {
1291
+ forEach(typeDef.elements, ( elemName, elem ) => {
1302
1292
  if (!elem.target) {
1303
1293
  type.elements[elemName] = Object.create(null);
1304
- Object.keys(elem).forEach((prop) => {
1294
+ forEachKey(elem, (prop) => {
1305
1295
  type.elements[elemName][prop] = elem[prop];
1306
1296
  });
1307
1297
  }
@@ -1478,7 +1468,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
1478
1468
  // followed by all namespaces that are potentially exposed by the exposed types
1479
1469
  // don't forget to prepend the global namespace prefix
1480
1470
  // schemas are ordered in csn2edm.js for each service
1481
- Object.keys(proxy.$exposedTypes).forEach(t => schemaSet.add(`${proxy.$globalSchemaPrefix}.${edmUtils.getSchemaPrefix(t)}`));
1471
+ forEachKey(proxy.$exposedTypes, t => schemaSet.add(`${proxy.$globalSchemaPrefix}.${edmUtils.getSchemaPrefix(t)}`));
1482
1472
  schemaSet.forEach((schemaName) => {
1483
1473
  if (!schemas[schemaName]) {
1484
1474
  schemas[schemaName] = { kind: 'schema', name: schemaName };
@@ -1490,7 +1480,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
1490
1480
  csn.definitions[fqProxyName] = proxy;
1491
1481
  reqDefs.definitions[fqProxyName] = proxy;
1492
1482
  setProp(proxy, '$path', [ 'definitions', fqProxyName ]);
1493
- Object.entries(proxy.$exposedTypes).forEach(([ tn, v ]) => {
1483
+ forEach(proxy.$exposedTypes, ( tn, v ) => {
1494
1484
  const fqtn = `${proxy.$globalSchemaPrefix}.${tn}`;
1495
1485
  if (csn.definitions[fqtn] === undefined) {
1496
1486
  csn.definitions[fqtn] = v;
@@ -1610,7 +1600,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
1610
1600
  elements = finalType?.elements || finalType?.items?.elements;
1611
1601
  }
1612
1602
  if (elements) {
1613
- Object.entries(elements).forEach(([ eltName, elt ]) => {
1603
+ forEach(elements, ( eltName, elt ) => {
1614
1604
  if (!elt.$visited) {
1615
1605
  setProp(elt, '$visited', true);
1616
1606
  let newRefs = [];
@@ -1711,7 +1701,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
1711
1701
  'Edm.TimeOfDay': 1,
1712
1702
  };
1713
1703
  if (!(edmType in legalEdmTypes)) {
1714
- warning('odata-spec-violation-key-type', location,
1704
+ message('odata-spec-violation-key-type', location,
1715
1705
  {
1716
1706
  name: pathSegment, type: type.type, id: edmType, '#': pathSegment ? 'std' : 'scalar',
1717
1707
  });
@@ -1909,6 +1899,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
1909
1899
  mapCdsToEdmProp(member);
1910
1900
  annotateAllowedValues(member, location);
1911
1901
  ComputedDefaultValue(member);
1902
+ rewriteAnnotationExpressions(member);
1912
1903
  if (member.returns) {
1913
1904
  edmUtils.assignAnnotation(member.returns, '@Core.Description', member.returns.doc);
1914
1905
  markCollection(member.returns);
@@ -1921,7 +1912,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
1921
1912
  const items = obj.items || csn.definitions[obj.type] && csn.definitions[obj.type].items;
1922
1913
  if (items) {
1923
1914
  edmUtils.assignProp(obj, '_NotNullCollection', items.notNull !== undefined ? items.notNull : true);
1924
- edmUtils.assignProp(obj, '_isCollection', true);
1915
+ edmUtils.assignProp(obj, '$isCollection', true);
1925
1916
  }
1926
1917
  }
1927
1918
 
@@ -2029,6 +2020,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
2029
2020
  if (npe.NavigationProperty &&
2030
2021
  npe.NavigationProperty['='] &&
2031
2022
  typeof npe.NavigationProperty['='] === 'string') {
2023
+ // TODO: replace with transformExpression
2032
2024
  applyTransformations({ definitions: { npe } }, {
2033
2025
  '=': (parent, prop, value) => {
2034
2026
  parent[prop] = prefix.concat(value).join('.');
@@ -2146,12 +2138,12 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
2146
2138
  const edmType = edmUtils.mapCdsToEdmType(obj, messageFunctions, _options.odataVersion === 'v2', obj['@Core.MediaType']);
2147
2139
  edmUtils.assignProp(obj, '_edmType', edmType);
2148
2140
  }
2149
- else if (obj._isCollection && (obj.items && isBuiltinType(csnUtils.getFinalTypeInfo(obj.items.type)?.type))) {
2141
+ else if (obj.$isCollection && (obj.items && isBuiltinType(csnUtils.getFinalTypeInfo(obj.items.type)?.type))) {
2150
2142
  const edmType = edmUtils.mapCdsToEdmType(obj.items, messageFunctions, _options.odataVersion === 'v2', obj['@Core.MediaType'], obj.$path);
2151
2143
  edmUtils.assignProp(obj, '_edmType', edmType);
2152
2144
  }
2153
2145
  // This is the special case when we have array of array, but will not be supported in the future
2154
- else if (obj._isCollection && obj.items && obj.items.type && obj.items.items && isBuiltinType(csnUtils.getFinalTypeInfo(obj.items.items.type)?.type)) {
2146
+ else if (obj.$isCollection && obj.items && obj.items.type && obj.items.items && isBuiltinType(csnUtils.getFinalTypeInfo(obj.items.items.type)?.type)) {
2155
2147
  const edmType = edmUtils.mapCdsToEdmType(obj.items.items, messageFunctions, _options.odataVersion === 'v2', obj['@Core.MediaType']);
2156
2148
  edmUtils.assignProp(obj, '_edmType', edmType);
2157
2149
  }
@@ -2175,6 +2167,112 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
2175
2167
  edmUtils.assignAnnotation(member, '@Core.ComputedDefaultValue', true);
2176
2168
  }
2177
2169
  }
2170
+
2171
+ function rewriteAnnotationExpressions( carrier ) {
2172
+ // rewrite annotation expression paths such that they are defined against the definition
2173
+ const absPath = $path2path(carrier.$path);
2174
+ let isSubTreeSpan = true;
2175
+ const rootPrefix = absPath.slice(1, absPath.length - 1);
2176
+
2177
+ const isExprAnno = (obj, pn) => isBetaEnabled(options, 'odataPathsInAnnotationExpressions') && findAnnotationExpression(obj, pn);
2178
+
2179
+ const subTreeSpan = {
2180
+ ref: (parent, _prop, xpr) => {
2181
+ const head = xpr[0].id || xpr[0];
2182
+ if (head === '$self' || parent.param) {
2183
+ let j = parent.param ? 0 : 1;
2184
+ for (let i = 1; i < absPath.length - 1 && isSubTreeSpan; i++, j++)
2185
+ isSubTreeSpan = (xpr[j].id || xpr[j]) === absPath[i];
2186
+ }
2187
+ },
2188
+ };
2189
+ // this element was not a top level element before type exposure
2190
+ // rectify all absolute annotation paths inside
2191
+ const relativize = {
2192
+ ref: (parent, _prop, xpr) => {
2193
+ const head = xpr[0].id || xpr[0];
2194
+ let absPathPrefixEqual = true;
2195
+ if (head === '$self' || parent.param) {
2196
+ let j = parent.param ? 0 : 1;
2197
+ for (let i = 1; i < absPath.length - 1 && absPathPrefixEqual; i++, j++)
2198
+ absPathPrefixEqual = (xpr[j].id || xpr[j]) === absPath[i];
2199
+
2200
+ if (absPathPrefixEqual)
2201
+ // remove prefix between $self and leaf element name
2202
+ // or starting with the parameter name
2203
+ xpr.splice(parent.param ? 0 : 1, absPath.length - 2);
2204
+ }
2205
+ },
2206
+ };
2207
+
2208
+ const absolutize = {
2209
+ ref: (parent, prop, xpr) => {
2210
+ const head = xpr[0].id || xpr[0];
2211
+ if (head !== '$self' && !parent.param && !isMagicVariable(head)) {
2212
+ parent[prop] = [ ...rootPrefix, ...xpr ];
2213
+ if (absolutize.scope === 'params')
2214
+ parent.param = true;
2215
+ else
2216
+ parent[prop].unshift('$self');
2217
+ }
2218
+ },
2219
+ };
2220
+
2221
+ if (absPath.length > 2) {
2222
+ const [ xprANames, nxprANames ] = Object.keys(carrier).reduce((acc, pn) => {
2223
+ if (pn[0] === '@')
2224
+ acc[isExprAnno(carrier, pn) ? 0 : 1].push(pn);
2225
+ return acc;
2226
+ }, [ [], [] ]);
2227
+ xprANames.forEach((xprAName) => {
2228
+ isSubTreeSpan = true;
2229
+ transformExpression(carrier, xprAName, subTreeSpan);
2230
+ if (isSubTreeSpan) {
2231
+ transformExpression(carrier, xprAName, relativize);
2232
+ }
2233
+ else {
2234
+ const scope = carrier.$path[2];
2235
+ absolutize.scope = scope;
2236
+ transformExpression(carrier, xprAName, absolutize);
2237
+ const def = csn.definitions[absPath[0]];
2238
+ const eltPath = absPath.slice(1).join('/');
2239
+ const proxyDict = scope === 'elements' ? '$eltAnnoProxies' : '$paramAnnoProxies';
2240
+
2241
+ if (!def[proxyDict])
2242
+ setProp(def, proxyDict, Object.create(null));
2243
+ let eltProxy = def[proxyDict][eltPath];
2244
+ if (!eltProxy) {
2245
+ eltProxy = Object.create(null);
2246
+ // these attributes are needed to test for
2247
+ // Property, Parameter, NavigationProperty, Collection
2248
+ // Applicability
2249
+ [ 'target',
2250
+ 'cardinality',
2251
+ 'keys',
2252
+ '$isCollection',
2253
+ '$appliesToReturnType',
2254
+ '$path',
2255
+ '@cds.api.ignore',
2256
+ '@odata.navigable' ].forEach((prop) => {
2257
+ if (carrier[prop] != null)
2258
+ setProp(eltProxy, prop, carrier[prop]);
2259
+ });
2260
+
2261
+ Object.keys(carrier).filter(pn => pn[0] !== '@').forEach((pn) => {
2262
+ eltProxy[pn] = carrier[pn];
2263
+ });
2264
+ def[proxyDict][eltPath] = eltProxy;
2265
+ }
2266
+ eltProxy[xprAName] = carrier[xprAName];
2267
+ carrier[xprAName] = null;
2268
+ nxprANames.filter(an => an.startsWith(`${xprAName}.`)).forEach((nxprAName) => {
2269
+ eltProxy[nxprAName] = carrier[nxprAName];
2270
+ carrier[nxprAName] = null;
2271
+ });
2272
+ }
2273
+ });
2274
+ }
2275
+ }
2178
2276
  }
2179
2277
 
2180
2278
  module.exports = {
@@ -1,11 +1,12 @@
1
1
  'use strict';
2
2
 
3
- const { setProp } = require('../base/model');
3
+ const { setProp, isBetaEnabled } = require('../base/model');
4
4
  const {
5
- isBuiltinType, isEdmPropertyRendered, applyTransformations, cloneAnnotationValue,
5
+ isBuiltinType, isEdmPropertyRendered, applyTransformations,
6
6
  } = require('../model/csnUtils');
7
7
  const { escapeString, hasControlCharacters, hasUnpairedUnicodeSurrogate } = require('../render/utils/stringEscapes');
8
8
  const { CompilerAssertion } = require('../base/error');
9
+ const { cloneAnnotationValue } = require('../model/cloneCsn');
9
10
 
10
11
  /* eslint max-statements-per-line:off */
11
12
  function validateOptions( _options ) {
@@ -31,6 +32,19 @@ function validateOptions( _options ) {
31
32
 
32
33
  options.pathDelimiter = options.isStructFormat ? '/' : '_';
33
34
 
35
+ if (isBetaEnabled(options, 'v5preview')) {
36
+ if (!options.severities)
37
+ options.severities = {};
38
+ options.severities['odata-spec-violation-array'] ??= 'Error';
39
+ options.severities['odata-spec-violation-assoc'] ??= 'Error';
40
+ options.severities['odata-spec-violation-namespace'] ??= 'Error';
41
+ options.severities['odata-spec-violation-param'] ??= 'Error';
42
+ options.severities['odata-spec-violation-returns'] ??= 'Error';
43
+ options.severities['odata-spec-violation-type-unknown'] ??= 'Error';
44
+ options.severities['odata-spec-violation-no-key'] ??= 'Error';
45
+ options.severities['odata-spec-violation-key-type'] ??= 'Error';
46
+ options.severities['odata-spec-violation-property-name'] ??= 'Error';
47
+ }
34
48
  return options;
35
49
  }
36
50
  return _options;
@@ -575,15 +589,14 @@ function addTypeFacets( node, csn ) {
575
589
  const decimalTypes = { 'cds.Decimal': 1, 'cds.DecimalFloat': 1, 'cds.hana.SMALLDECIMAL': 1 };
576
590
  if (csn.length != null)
577
591
  node.setEdmAttribute('MaxLength', csn.length);
578
- if (csn.scale !== undefined)
579
- node.setEdmAttribute('Scale', csn.scale);
580
- // else if (csn.type === 'cds.hana.SMALLDECIMAL' && !isV2)
581
- // node._edmAttributes.Scale = 'floating';
582
-
583
592
  if (csn.precision != null)
584
593
  node.setEdmAttribute('Precision', csn.precision);
585
594
  // else if (csn.type === 'cds.hana.SMALLDECIMAL' && !isV2)
586
595
  // node.Precision = 16;
596
+ if (csn.scale !== undefined)
597
+ node.setEdmAttribute('Scale', csn.scale);
598
+ // else if (csn.type === 'cds.hana.SMALLDECIMAL' && !isV2)
599
+ // node._edmAttributes.Scale = 'floating';
587
600
  else if (csn.type === 'cds.Timestamp' && node._edmAttributes.Type === 'Edm.DateTimeOffset')
588
601
  node.setEdmAttribute('Precision', 7);
589
602
  if (csn.type in decimalTypes) {
@@ -2690,7 +2690,7 @@
2690
2690
  "Capabilities.PermissionType": {
2691
2691
  "$kind": "ComplexType",
2692
2692
  "Properties": {
2693
- "SchemeName": "Auth.SchemeName",
2693
+ "SchemeName": "Authorization.SchemeName",
2694
2694
  "Scopes": "Collection(Capabilities.ScopeType)"
2695
2695
  }
2696
2696
  },
@@ -3594,6 +3594,7 @@
3594
3594
  "$kind": "ComplexType",
3595
3595
  "Properties": {
3596
3596
  "ChangeNextSiblingAction": "Common.QualifiedName",
3597
+ "ChangeSiblingForRootsSupported": "Edm.Boolean",
3597
3598
  "CopyAction": "Common.QualifiedName"
3598
3599
  }
3599
3600
  },
@@ -1 +1 @@
1
- 99b88c455f59a02a22d3d2ee662b8136
1
+ 37b3697769a5035b6409cd959ebdf610