@sap/cds-compiler 5.9.4 → 6.0.12

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 (114) hide show
  1. package/CHANGELOG.md +117 -319
  2. package/README.md +1 -1
  3. package/bin/cds_update_identifiers.js +3 -5
  4. package/bin/cdsc.js +24 -9
  5. package/bin/cdshi.js +1 -1
  6. package/bin/cdsse.js +4 -4
  7. package/doc/CHANGELOG_BETA.md +11 -0
  8. package/doc/CHANGELOG_DEPRECATED.md +29 -0
  9. package/lib/api/main.js +8 -5
  10. package/lib/api/options.js +12 -10
  11. package/lib/base/builtins.js +1 -0
  12. package/lib/base/message-registry.js +191 -99
  13. package/lib/base/messages.js +35 -21
  14. package/lib/base/model.js +14 -24
  15. package/lib/checks/actionsFunctions.js +10 -20
  16. package/lib/checks/annotationsOData.js +1 -1
  17. package/lib/checks/elements.js +35 -10
  18. package/lib/checks/enums.js +31 -0
  19. package/lib/checks/foreignKeys.js +2 -2
  20. package/lib/checks/hasPersistedElements.js +5 -0
  21. package/lib/checks/invalidTarget.js +1 -1
  22. package/lib/checks/managedWithoutKeys.js +5 -4
  23. package/lib/checks/queryNoDbArtifacts.js +10 -8
  24. package/lib/checks/types.js +5 -5
  25. package/lib/checks/validator.js +6 -4
  26. package/lib/compiler/assert-consistency.js +13 -9
  27. package/lib/compiler/checks.js +20 -52
  28. package/lib/compiler/define.js +31 -6
  29. package/lib/compiler/extend.js +5 -1
  30. package/lib/compiler/generate.js +14 -17
  31. package/lib/compiler/populate.js +8 -31
  32. package/lib/compiler/propagator.js +21 -35
  33. package/lib/compiler/resolve.js +64 -29
  34. package/lib/compiler/shared.js +16 -4
  35. package/lib/compiler/tweak-assocs.js +1 -1
  36. package/lib/compiler/utils.js +1 -1
  37. package/lib/edm/annotations/edmJson.js +23 -20
  38. package/lib/edm/annotations/genericTranslation.js +12 -10
  39. package/lib/edm/csn2edm.js +50 -56
  40. package/lib/edm/edm.js +33 -28
  41. package/lib/edm/edmInboundChecks.js +2 -2
  42. package/lib/edm/edmPreprocessor.js +54 -88
  43. package/lib/edm/edmUtils.js +9 -12
  44. package/lib/gen/BaseParser.js +63 -52
  45. package/lib/gen/CdlGrammar.checksum +1 -1
  46. package/lib/gen/CdlParser.js +1153 -1165
  47. package/lib/gen/Dictionary.json +21 -1
  48. package/lib/json/from-csn.js +70 -43
  49. package/lib/json/to-csn.js +6 -8
  50. package/lib/language/multiLineStringParser.js +3 -2
  51. package/lib/main.d.ts +58 -24
  52. package/lib/model/cloneCsn.js +3 -0
  53. package/lib/model/csnUtils.js +28 -39
  54. package/lib/model/xprAsTree.js +23 -9
  55. package/lib/modelCompare/compare.js +5 -4
  56. package/lib/optionProcessor.js +24 -17
  57. package/lib/parsers/AstBuildingParser.js +81 -25
  58. package/lib/parsers/XprTree.js +57 -3
  59. package/lib/parsers/identifiers.js +1 -1
  60. package/lib/parsers/index.js +0 -3
  61. package/lib/render/manageConstraints.js +25 -25
  62. package/lib/render/toCdl.js +173 -170
  63. package/lib/render/toHdbcds.js +126 -128
  64. package/lib/render/toRename.js +7 -7
  65. package/lib/render/toSql.js +128 -125
  66. package/lib/render/utils/common.js +47 -22
  67. package/lib/render/utils/delta.js +25 -25
  68. package/lib/render/utils/operators.js +2 -2
  69. package/lib/render/utils/pretty.js +5 -5
  70. package/lib/render/utils/sql.js +13 -13
  71. package/lib/render/utils/standardDatabaseFunctions.js +115 -103
  72. package/lib/render/utils/unique.js +4 -4
  73. package/lib/transform/db/applyTransformations.js +1 -1
  74. package/lib/transform/db/assertUnique.js +2 -2
  75. package/lib/transform/db/associations.js +6 -7
  76. package/lib/transform/db/assocsToQueries/utils.js +4 -5
  77. package/lib/transform/db/backlinks.js +12 -9
  78. package/lib/transform/db/cdsPersistence.js +8 -7
  79. package/lib/transform/db/constraints.js +13 -10
  80. package/lib/transform/db/expansion.js +7 -3
  81. package/lib/transform/db/flattening.js +4 -14
  82. package/lib/transform/db/processSqlServices.js +2 -1
  83. package/lib/transform/db/temporal.js +5 -7
  84. package/lib/transform/db/views.js +2 -4
  85. package/lib/transform/draft/db.js +8 -8
  86. package/lib/transform/draft/odata.js +10 -7
  87. package/lib/transform/forOdata.js +10 -5
  88. package/lib/transform/forRelationalDB.js +5 -75
  89. package/lib/transform/localized.js +1 -1
  90. package/lib/transform/odata/createForeignKeys.js +11 -10
  91. package/lib/transform/odata/flattening.js +8 -4
  92. package/lib/transform/odata/foreignKeyRefsInXprAnnos.js +96 -0
  93. package/lib/transform/odata/typesExposure.js +3 -3
  94. package/lib/transform/transformUtils.js +4 -8
  95. package/lib/transform/translateAssocsToJoins.js +14 -7
  96. package/lib/transform/universalCsn/universalCsnEnricher.js +10 -4
  97. package/lib/utils/objectUtils.js +0 -17
  98. package/package.json +10 -13
  99. package/share/messages/def-upcoming-virtual-change.md +1 -1
  100. package/LICENSE +0 -37
  101. package/bin/cds_remove_invalid_whitespace.js +0 -138
  102. package/doc/CHANGELOG_ARCHIVE.md +0 -3604
  103. package/lib/gen/genericAntlrParser.js +0 -3
  104. package/lib/gen/language.checksum +0 -1
  105. package/lib/gen/language.interp +0 -456
  106. package/lib/gen/language.tokens +0 -180
  107. package/lib/gen/languageLexer.interp +0 -439
  108. package/lib/gen/languageLexer.js +0 -1483
  109. package/lib/gen/languageLexer.tokens +0 -167
  110. package/lib/gen/languageParser.js +0 -24941
  111. package/lib/language/antlrParser.js +0 -205
  112. package/lib/language/errorStrategy.js +0 -646
  113. package/lib/language/genericAntlrParser.js +0 -1572
  114. package/lib/parsers/CdlGrammar.g4 +0 -2070
@@ -143,10 +143,6 @@ function resolve( model ) {
143
143
  const msg = semanticLoc && 'target';
144
144
  error( 'ref-cyclic', [ location, semanticLoc || user ], {
145
145
  art, '#': msg,
146
- }, {
147
- std: 'Illegal circular reference to $(ART)',
148
- element: 'Illegal circular reference to element $(MEMBER) of $(ART)',
149
- target: 'Illegal circular reference to target $(ART)',
150
146
  } );
151
147
  }
152
148
  } );
@@ -1172,12 +1168,24 @@ function resolve( model ) {
1172
1168
  return [ null, '$navElement', '$tableAlias' ][path.length] === (kind || true) && elem._origin;
1173
1169
  }
1174
1170
 
1175
- function addImplicitForeignKeys( art, obj, target ) {
1171
+ function isQuasiVirtualAssociation( art ) {
1172
+ if (art.on)
1173
+ return false;
1174
+ if (art.foreignKeys != null)
1175
+ return !art.foreignKeys;
1176
1176
  const max = art.cardinality?.targetMax;
1177
- if (max && (typeof max.val !== 'number' || max.val > 1) &&
1178
- !art.$inferred && !art.virtual?.val) {
1179
- warning( 'assoc-incomplete-to-many', [ max.location, art ], null,
1180
- 'Provide an ON-condition or foreign keys to this to-many association' );
1177
+ return max && (typeof max.val !== 'number' || max.val > 1);
1178
+ }
1179
+
1180
+ function addImplicitForeignKeys( art, obj, target ) {
1181
+ if (!art.$inferred && !art.virtual?.val && isQuasiVirtualAssociation( obj )) {
1182
+ if (!isDeprecatedEnabled( options, 'noQuasiVirtualAssocs' )) {
1183
+ // TODO: set `foreignKeys`, `ON` or `virtual` to false or similar to
1184
+ // indicate that it is already handled (and that we might not be able to
1185
+ // follow the assoc)? Let us set foreignKeys to false
1186
+ obj.foreignKeys = false;
1187
+ return; // no foreign keys for `Association to many Target`;
1188
+ }
1181
1189
  }
1182
1190
  obj.foreignKeys = Object.create( null );
1183
1191
  forEachInOrder( target, 'elements', ( elem, name ) => {
@@ -1306,6 +1314,8 @@ function resolve( model ) {
1306
1314
  'The redirected target is the original $(ART)' );
1307
1315
  }
1308
1316
 
1317
+ // No check with user-provided ON/fKeys (remark: compiler deduceds ON/fKeys
1318
+ // _after_ redirecting the target = no $inferred test necessary):
1309
1319
  if (elem.foreignKeys || elem.on)
1310
1320
  return; // TODO: or should we still bring an msg if nothing in common?
1311
1321
 
@@ -1456,19 +1466,35 @@ function resolve( model ) {
1456
1466
  }
1457
1467
  }
1458
1468
 
1459
- function resolveAnnoExpr( expr, art, anno = expr ) {
1469
+ function resolveAnnoExpr( expr, art, anno = expr, topItem = false ) {
1460
1470
  if (expr.$tokenTexts) {
1461
- if (!anno.kind)
1471
+ if (anno === expr) {
1462
1472
  initAnnotationForExpression( anno, art );
1473
+ }
1474
+ else if (topItem) { // item of top-level array annotation
1475
+ setLink( expr, '_outer', anno );
1476
+ anno = expr;
1477
+ }
1478
+
1463
1479
  const type = anno === expr && anno.name;
1464
1480
  // TODO: it might be best to set an _artifact link also for property values
1465
1481
  // like in `@Anno: [ { foo: #EnumSymbol }]
1466
1482
  resolveExpr( expr, 'annotation', anno, type );
1467
1483
  }
1468
1484
  else if (expr.literal === 'array') {
1469
- expr.val.forEach( val => resolveAnnoExpr( val, art, anno ) );
1485
+ const withExpr = anno === expr &&
1486
+ // the following is needed for checkAnnotationAcceptsExpressions(),
1487
+ // otherwise @cds.persistence.skip: [hdi, hdbcds, sql.postgres] fails
1488
+ expr.val.some( item => item.$tokenTexts || item.literal === 'struct');
1489
+ if (withExpr)
1490
+ initAnnotationForExpression( anno, art );
1491
+ expr.val.forEach( val => resolveAnnoExpr( val, art, anno, withExpr ) );
1470
1492
  }
1471
1493
  else if (expr.literal === 'struct') {
1494
+ if (topItem) { // item of top-level array annotation
1495
+ setLink( expr, '_outer', anno );
1496
+ anno = expr;
1497
+ }
1472
1498
  Object.values( expr.struct ).forEach( val => resolveAnnoExpr( val, art, anno ) );
1473
1499
  }
1474
1500
  }
@@ -1480,10 +1506,9 @@ function resolve( model ) {
1480
1506
  * @param {XSN.Artifact} art
1481
1507
  */
1482
1508
  function initAnnotationForExpression( anno, art ) {
1483
- anno.kind = '$annotation';
1484
1509
  setLink( anno, '_outer', art );
1485
1510
  art.$contains ??= {};
1486
- art.$contains.$annotation = { // set in resolveExprNode
1511
+ art.$contains.$annotation ??= { // set in resolveExprPath
1487
1512
  $path: false,
1488
1513
  $self: false,
1489
1514
  };
@@ -1491,6 +1516,9 @@ function resolve( model ) {
1491
1516
  // Might be useful for future recursive types.
1492
1517
  }
1493
1518
 
1519
+ // Note: for annotation assignments, `art` should be the annotation, not the
1520
+ // assignee (element, ...); otherwise, artifact links could be resolved in the
1521
+ // wrong block
1494
1522
  function resolveExpr( expr, exprCtx, art, type = null ) {
1495
1523
  traverseTypedExpr( expr, exprCtx, art, type, resolveExprNode );
1496
1524
  }
@@ -1543,8 +1571,12 @@ function resolve( model ) {
1543
1571
  const ref = resolvePath( expr, expected, user );
1544
1572
 
1545
1573
  if (expected === 'annotation') {
1546
- user._outer.$contains.$annotation.$path = true;
1547
- user._outer.$contains.$annotation.$self ||= expr.path[0]?._navigation?.kind === '$self';
1574
+ const ruser = (user._outer.kind === '$annotation')
1575
+ ? user._outer._outer
1576
+ : user._outer;
1577
+ // if (!ruser.$contains) console.log('UO:',!!ruser,!!user._block,user._outer)
1578
+ ruser.$contains.$annotation.$path = true;
1579
+ ruser.$contains.$annotation.$self ||= expr.path[0]?._navigation?.kind === '$self';
1548
1580
  }
1549
1581
 
1550
1582
  // check whether arguments and filters are allowed on last path item;
@@ -1562,9 +1594,10 @@ function resolve( model ) {
1562
1594
  const art = type && (type.kind === 'entity' ? type : type.target?._artifact);
1563
1595
  if (!art)
1564
1596
  return ref; // error already reported via resolvePathItem()
1565
- const unexpectedFilter = expected !== 'column' && expected !== 'calc';
1597
+ const unexpectedFilter = expected !== 'column' && expected !== 'calc' && 'std' ||
1598
+ isQuasiVirtualAssociation( type ) && 'model-only';
1566
1599
  if (last.args || last.where || last.cardinality)
1567
- reportUnexpectedArgsAndFilter( last, expected, user, art, unexpectedFilter && 'std' );
1600
+ reportUnexpectedArgsAndFilter( last, expected, user, art, unexpectedFilter );
1568
1601
  // TODO: we should have different message-ids for the "last" stuff: adding
1569
1602
  // `.item` likely corrects the ref, probably with location at end of ref
1570
1603
  return ref;
@@ -1622,12 +1655,12 @@ function resolve( model ) {
1622
1655
  function resolveEnumSymbol( expr, expected, user, type ) {
1623
1656
  const { sym } = expr;
1624
1657
  // CSN input with both '#'+val (recompilation) → do not resolve
1625
- if (!sym || expr.val !== undefined || !type)
1658
+ if (!sym || expr.val !== undefined)
1626
1659
  return;
1627
1660
  // The parameter def for an argument, and the annotation def for an assignment
1628
1661
  // is in `type._artifact`, it is not `type` itself:
1629
- type = effectiveType( type.id ? type._artifact : type );
1630
- // Remark: do not use `?.`, type could be 0 for cyclic parameter type
1662
+ type = type && effectiveType( type.id ? type._artifact : type );
1663
+ // Remark: type could be 0 for cyclic parameter type
1631
1664
  if (type && type.foreignKeys) {
1632
1665
  const keys = Object.values( type.foreignKeys );
1633
1666
  if (keys.length === 1) {
@@ -1636,11 +1669,14 @@ function resolve( model ) {
1636
1669
  }
1637
1670
  }
1638
1671
  const symbols = type && type.enum;
1639
- if (!symbols)
1640
- return;
1641
-
1642
- // TODO: or warning if enum symbol but non-enum type?
1643
- if (symbols[sym.id]) {
1672
+ if (!symbols) {
1673
+ if (user.kind !== '$annotation') { // TODO: better type deduction for annotations
1674
+ const msg = (user.kind === 'enum') ? 'symbolDef' : type && 'invalidType';
1675
+ warning( 'ref-unexpected-enum', [ expr.location, user ],
1676
+ { '#': msg || 'untyped', enum: sym.id, type: type || '' } );
1677
+ }
1678
+ }
1679
+ else if (symbols[sym.id]) {
1644
1680
  setLink( sym, '_artifact', symbols[sym.id] );
1645
1681
  }
1646
1682
  else {
@@ -1649,8 +1685,7 @@ function resolve( model ) {
1649
1685
  type = getOrigin( type );
1650
1686
  const err = message( 'ref-undefined-enum', [ sym.location, user ],
1651
1687
  { id: sym.id, type } );
1652
- if (options.newParser || options.newparser)
1653
- attachAndEmitValidNames( err, symbols );
1688
+ attachAndEmitValidNames( err, symbols );
1654
1689
  }
1655
1690
  }
1656
1691
 
@@ -1662,7 +1697,7 @@ function resolve( model ) {
1662
1697
  if ((step.where || step.cardinality) && variant) {
1663
1698
  const location = combinedLocation( step.where, step.cardinality );
1664
1699
  // XSN TODO: filter$location including […]
1665
- message( 'expr-unexpected-filter', [ location, user ], { '#': variant } );
1700
+ error( 'expr-unexpected-filter', [ location, user ], { '#': variant } );
1666
1701
  }
1667
1702
  return variant && traverseExpr.SKIP;
1668
1703
  }
@@ -775,8 +775,13 @@ function fns( model ) {
775
775
  if (head._artifact !== undefined)
776
776
  return head._artifact;
777
777
  let ruser = user._user || user; // TODO: nicer name if we keep this
778
- if (ruser.kind === '$annotation')
779
- ruser = ruser._outer;
778
+ // TODO: re-think _user link
779
+ if (ruser._outer && !semantics.isMainRef) {
780
+ if (ruser.kind === '$annotation')
781
+ ruser = ruser._outer; // for elem refs, use elem as real "user"
782
+ else if (ruser._outer.kind === '$annotation')
783
+ ruser = ruser._outer._outer;
784
+ }
780
785
 
781
786
  // Handle expand/inline, `type of`, :param, global (internally for CDL):
782
787
  if (user._columnParent && !semantics.isMainRef) { // in expand/inline
@@ -1002,7 +1007,8 @@ function fns( model ) {
1002
1007
  // TODO: remove again, should be easy enough in to-csn without.
1003
1008
  if (path.length === 1 && art.kind === '$tableAlias')
1004
1009
  (user._user || user).$noOrigin = true;
1005
- if (head.id === '$projection' && user.kind === '$annotation') {
1010
+ if (head.id === '$projection' &&
1011
+ (user.kind === '$annotation' || user._outer?.kind === '$annotation')) {
1006
1012
  error( 'ref-unsupported-projection', [ head.location, user ],
1007
1013
  { code: '$projection', newcode: '$self' },
1008
1014
  '$(CODE) is not supported in annotations; replace by $(NEWCODE)' );
@@ -1286,6 +1292,8 @@ function fns( model ) {
1286
1292
  if (!user.elements && !user.actions && !user.enum && !user.params &&
1287
1293
  couldBeDraftsEntity( item.id, valid, prev, path ))
1288
1294
  return;
1295
+ if (couldBeDraftAdminDataEntity( item ) )
1296
+ return;
1289
1297
  signalNotFound( (valid.length > 1 ? 'ext-undefined-art' : 'ext-undefined-def'),
1290
1298
  // TODO: ext-undefined-xyz
1291
1299
  [ item.location, user ], valid, { art } );
@@ -1293,11 +1301,15 @@ function fns( model ) {
1293
1301
 
1294
1302
  function couldBeDraftsEntity( id, valid, prev, path ) {
1295
1303
  const entity = prev
1296
- ? prev === path[path.length - 2]._artifact && prev
1304
+ ? prev === path[path.length - 2]._artifact && prev // TODO: Should check for '.drafts'?
1297
1305
  : path.length === 1 && id.endsWith( '.drafts' ) && model.definitions[id.slice( 0, -7 )];
1298
1306
  return entity?.kind === 'entity' && !!entity._service;
1299
1307
  }
1300
1308
 
1309
+ function couldBeDraftAdminDataEntity( item ) {
1310
+ return item.id === 'DraftAdministrativeData' && !item._artifact;
1311
+ }
1312
+
1301
1313
  function undefinedParam( user, head, valid, _dict, _art, _path, semantics ) {
1302
1314
  // TODO: text variant if there are no parameters, or in artifactParameters()
1303
1315
  // TODO: use prepared message variants
@@ -274,7 +274,7 @@ function tweakAssocs( model ) {
274
274
  // target -> avoid infloop ourselves with _status.
275
275
  // TODO: this should be good now
276
276
  const chain = [];
277
- while (!elem.on && !elem.foreignKeys) {
277
+ while (!elem.on && elem.foreignKeys == null) {
278
278
  chain.push( elem );
279
279
  if (elem._status === 'rewrite') { // circular dependency (already reported)
280
280
  for (const e of chain)
@@ -126,7 +126,7 @@ function proxyCopyMembers( art, dictProp, originDict, location, kind, tmpDepreca
126
126
  if (kind)
127
127
  member.kind = kind;
128
128
  else if (origin.key && !tmpDeprecated)
129
- // TODO(v6): remove tmpDeprecated once `noKeyPropagationWithExpansions` is removed
129
+ // TODO(v6): remove tmpDeprecated once `_noKeyPropagationWithExpansions` is removed
130
130
  member.key = Object.assign( { $inferred: 'expanded' }, origin.key );
131
131
  if (kind && origin.masked) // TODO: remove!
132
132
  member.masked = Object.assign( { $inferred: 'nav' }, origin.masked );
@@ -83,7 +83,7 @@ function xpr2edmJson( carrier, anno, location, options, messageFunctions ) {
83
83
  });
84
84
  delete parent[op];
85
85
  };
86
- const noOp = () => (true);
86
+ const noOp = () => {};
87
87
  //----------------------------------
88
88
  // Create the transformer dictionary
89
89
  const transform = {
@@ -96,7 +96,6 @@ function xpr2edmJson( carrier, anno, location, options, messageFunctions ) {
96
96
  isNull: (p, o) => notADynExpr(p, o, null, null, null, null, 'is null'),
97
97
  isNotNull: (p, o) => notADynExpr(p, o, null, null, null, null, 'is not null'),
98
98
  exists: notADynExpr,
99
- '#': notADynExpr,
100
99
  SELECT: notADynExpr,
101
100
  SET: (p, o) => notADynExpr(p, o, null, null, null, null, 'UNION'),
102
101
  like: notADynExpr,
@@ -312,8 +311,16 @@ function xpr2edmJson( carrier, anno, location, options, messageFunctions ) {
312
311
  else
313
312
  parentparent[parentprop] = xpr;
314
313
  };
314
+ transform['#'] = (parent, prop, xpr, csnPath, parentParent, parentprop, txt) => {
315
+ if (parent['#'] && parent.val) // enum reference that was resolved by the compiler
316
+ delete parent['#'];
317
+ else
318
+ notADynExpr(parent, prop, xpr, csnPath, parentParent, parentprop, txt);
319
+ };
315
320
  transform.ref = (parent, prop, xpr, csnPath, parentparent, parentprop) => {
316
- if (xpr.some(ps => ps.args || ps.where)) {
321
+ // until empty filter syntax is introduced for the annotation expressions,
322
+ // we ignore the filters in order to generate EDMX
323
+ if (xpr.some(ps => ps.args/* || ps.where */)) {
317
324
  error('odata-anno-xpr-ref', location, {
318
325
  anno, elemref: parent, '#': 'args',
319
326
  });
@@ -492,23 +499,21 @@ function xpr2edmJson( carrier, anno, location, options, messageFunctions ) {
492
499
  const td = EdmPrimitiveTypeMap[typeDef];
493
500
  if (td) {
494
501
  if (td.v2 !== options.isV2() && td.v4 !== options.isV4()) {
495
- message('odata-spec-violation-type', location,
502
+ message('odata-unexpected-edm-type', location,
496
503
  {
497
504
  anno,
498
505
  type: typeDef,
499
506
  version: (options.isV4() ? '4.0' : '2.0'),
500
- '#': 'incompatible_anno',
507
+ '#': 'anno',
501
508
  });
502
509
  }
503
510
  evalArgs(td, typeFacets, typeDef);
504
511
  EdmTypeFacetNames.forEach((facetName) => {
505
512
  const facetDef = EdmTypeFacetMap[facetName];
506
- const optional
507
- = (facetDef.optional !== undefined)
508
- ? (Array.isArray(facetDef.optional)
513
+ const optional = (facetDef.optional !== undefined) &&
514
+ (Array.isArray(facetDef.optional)
509
515
  ? facetDef.optional.includes(typeDef)
510
- : facetDef.optional)
511
- : false;
516
+ : facetDef.optional);
512
517
 
513
518
  if (td[facetName]) {
514
519
  // ignore facets that are not type relevant
@@ -516,13 +521,13 @@ function xpr2edmJson( carrier, anno, location, options, messageFunctions ) {
516
521
  const facetArgs = typeFacets.filter(arg => arg.func === facetName || arg.func === `$${ facetName }`);
517
522
 
518
523
  if (facetArgs.length === 0 && !optional && (options.isV2() === facetDef.v2 || options.isV4() === facetDef.v4)) {
519
- message('odata-spec-violation-type', location,
524
+ message('odata-unexpected-edm-facet', location,
520
525
  {
521
526
  anno,
522
527
  type: typeDef,
523
528
  name: facetName,
524
529
  version: (options.isV4() ? '4.0' : '2.0'),
525
- '#': 'facet_anno',
530
+ '#': 'anno',
526
531
  });
527
532
  }
528
533
  else if (facetArgs.length > 1) {
@@ -566,14 +571,12 @@ function xpr2edmJson( carrier, anno, location, options, messageFunctions ) {
566
571
  const precision = Number.parseInt(parent.$Precision, 10);
567
572
  const scale = Number.parseInt(parent.$Scale, 10);
568
573
  if (!Number.isNaN(precision) && !Number.isNaN(scale) && scale > precision) {
569
- message('odata-spec-violation-type', location,
570
- {
571
- anno,
572
- type: typeDef,
573
- number: scale,
574
- rawvalue: precision,
575
- '#': 'scale_anno',
576
- });
574
+ message('odata-invalid-scale', location, {
575
+ '#': 'anno',
576
+ anno,
577
+ number: scale,
578
+ rawvalue: precision,
579
+ });
577
580
  }
578
581
  }
579
582
  if (options.isV2() && parent.$Scale === 'variable') {
@@ -267,7 +267,8 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
267
267
 
268
268
  Object.entries(cObject.actions).forEach(([ n, action ]) => {
269
269
  setProp(action, '$isBound', true);
270
- const actionName = `${ serviceName }.${ isV2() ? `${ entityName }_` : '' }${ n }`;
270
+ const v2entity = isV2() ? `${ entityName }_` : '';
271
+ const actionName = `${ serviceName }.${ v2entity }${ n }`;
271
272
  handleAction(actionName, action, cObjectname, [ ...location, 'actions', n ]);
272
273
  });
273
274
  }
@@ -852,14 +853,13 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
852
853
 
853
854
  termNameWithoutQualifiers.split('.').forEach((id) => {
854
855
  if (!edmUtils.isODataSimpleIdentifier(id))
855
- message('odata-spec-violation-id', msg.location, { id });
856
+ message('odata-invalid-name', msg.location, { id });
856
857
  });
857
858
  newAnno = new Edm.Annotation(v, termNameWithoutQualifiers);
858
859
  if (qualifier?.length) {
859
- if (!edmUtils.isODataSimpleIdentifier(qualifier)) {
860
- message('odata-spec-violation-id', msg.location,
861
- { id: qualifier, '#': 'qualifier' });
862
- }
860
+ if (!edmUtils.isODataSimpleIdentifier(qualifier))
861
+ message('odata-invalid-qualifier', msg.location, { id: qualifier });
862
+
863
863
  newAnno.setEdmAttribute('Term', termNameWithoutQualifiers);
864
864
  newAnno.setEdmAttribute('Qualifier', qualifier);
865
865
  }
@@ -1428,7 +1428,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
1428
1428
  // in a record or term
1429
1429
  if (Array.isArray(value)) {
1430
1430
  message('odata-anno-value', msg.location,
1431
- { anno: msg.anno(), '#': 'nestedcollection' });
1431
+ { anno: msg.anno(), '#': 'nestedCollection' });
1432
1432
  }
1433
1433
  else if (value && typeof value === 'object') {
1434
1434
  if (value['=']) {
@@ -1439,7 +1439,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
1439
1439
  }
1440
1440
  else if (value['#']) {
1441
1441
  message('odata-anno-value', msg.location,
1442
- { anno: msg.anno(), '#': 'enumincollection' });
1442
+ { anno: msg.anno(), '#': 'enuminCollection' });
1443
1443
  }
1444
1444
  else if (value.$edmJson) {
1445
1445
  newCollection.append(handleEdmJson(value.$edmJson, msg));
@@ -1663,7 +1663,9 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
1663
1663
  message('odata-anno-dict', msg.location, { anno: msg.anno(), '#': 'experimental' });
1664
1664
  usedExperimentalTerms[termName] = true;
1665
1665
  }
1666
- if (dictTerm.$deprecated && !usedDeprecatedTerms[termName]) {
1666
+ // TODO: remove this part "&& termName !== 'Common.DraftNode'" once the annotation is not part
1667
+ // of the dictionaries
1668
+ if (dictTerm.$deprecated && !usedDeprecatedTerms[termName] && termName !== 'Common.DraftNode') {
1667
1669
  message('odata-anno-def', msg.location,
1668
1670
  { anno: msg.anno(), depr: dictTerm.$deprecationText, '#': 'deprecated' });
1669
1671
  usedDeprecatedTerms[termName] = true;
@@ -1774,7 +1776,7 @@ function mergeOdataVocabularies( options, message ) {
1774
1776
  defOk = false;
1775
1777
  }
1776
1778
  else if (name === 'Alias' && !edmUtils.isODataSimpleIdentifier(def[name])) {
1777
- message('odata-spec-violation-id', null, { id: name, value: def[name], '#': 'vocRefAlias' });
1779
+ message('odata-invalid-vocabulary-alias', null, { id: name, value: def[name] });
1778
1780
  defOk = false;
1779
1781
  }
1780
1782
  });