@sap/cds-compiler 2.15.8 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/CHANGELOG.md +102 -1590
  2. package/bin/.eslintrc.json +2 -1
  3. package/bin/cdsc.js +61 -46
  4. package/doc/API.md +11 -0
  5. package/doc/CHANGELOG_ARCHIVE.md +1592 -0
  6. package/doc/CHANGELOG_BETA.md +26 -5
  7. package/doc/CHANGELOG_DEPRECATED.md +55 -1
  8. package/doc/{DeprecatedOptions.md → DeprecatedOptions_v2.md} +3 -1
  9. package/doc/Versioning.md +20 -1
  10. package/lib/api/.eslintrc.json +2 -2
  11. package/lib/api/main.js +282 -156
  12. package/lib/api/options.js +17 -88
  13. package/lib/api/validate.js +6 -10
  14. package/lib/base/keywords.js +280 -110
  15. package/lib/base/message-registry.js +85 -25
  16. package/lib/base/messages.js +119 -89
  17. package/lib/base/model.js +46 -2
  18. package/lib/base/optionProcessorHelper.js +53 -21
  19. package/lib/checks/actionsFunctions.js +15 -12
  20. package/lib/checks/annotationsOData.js +1 -1
  21. package/lib/checks/cdsPersistence.js +1 -0
  22. package/lib/checks/elements.js +6 -6
  23. package/lib/checks/invalidTarget.js +1 -1
  24. package/lib/checks/nonexpandableStructured.js +1 -1
  25. package/lib/checks/queryNoDbArtifacts.js +2 -1
  26. package/lib/checks/selectItems.js +101 -15
  27. package/lib/checks/types.js +7 -8
  28. package/lib/checks/utils.js +2 -2
  29. package/lib/checks/validator.js +3 -3
  30. package/lib/compiler/assert-consistency.js +78 -21
  31. package/lib/compiler/base.js +6 -4
  32. package/lib/compiler/builtins.js +177 -10
  33. package/lib/compiler/checks.js +1 -1
  34. package/lib/compiler/define.js +28 -23
  35. package/lib/compiler/extend.js +75 -18
  36. package/lib/compiler/finalize-parse-cdl.js +25 -18
  37. package/lib/compiler/index.js +27 -11
  38. package/lib/compiler/moduleLayers.js +7 -0
  39. package/lib/compiler/populate.js +26 -39
  40. package/lib/compiler/propagator.js +12 -7
  41. package/lib/compiler/resolve.js +207 -236
  42. package/lib/compiler/shared.js +100 -93
  43. package/lib/compiler/tweak-assocs.js +13 -20
  44. package/lib/compiler/utils.js +20 -6
  45. package/lib/edm/annotations/preprocessAnnotations.js +12 -13
  46. package/lib/edm/csn2edm.js +35 -37
  47. package/lib/edm/edm.js +22 -13
  48. package/lib/edm/edmAnnoPreprocessor.js +349 -0
  49. package/lib/edm/edmInboundChecks.js +85 -0
  50. package/lib/edm/edmPreprocessor.js +338 -689
  51. package/lib/edm/edmUtils.js +97 -67
  52. package/lib/gen/Dictionary.json +29 -9
  53. package/lib/gen/language.checksum +1 -1
  54. package/lib/gen/language.interp +8 -31
  55. package/lib/gen/language.tokens +105 -114
  56. package/lib/gen/languageLexer.interp +1 -34
  57. package/lib/gen/languageLexer.js +892 -1007
  58. package/lib/gen/languageLexer.tokens +95 -106
  59. package/lib/gen/languageParser.js +20629 -22474
  60. package/lib/inspect/.eslintrc.json +4 -0
  61. package/lib/inspect/index.js +14 -0
  62. package/lib/inspect/inspectModelStatistics.js +81 -0
  63. package/lib/inspect/inspectPropagation.js +189 -0
  64. package/lib/inspect/inspectUtils.js +44 -0
  65. package/lib/json/from-csn.js +74 -69
  66. package/lib/json/to-csn.js +17 -14
  67. package/lib/language/antlrParser.js +2 -2
  68. package/lib/language/docCommentParser.js +61 -38
  69. package/lib/language/errorStrategy.js +52 -40
  70. package/lib/language/genericAntlrParser.js +424 -292
  71. package/lib/language/language.g4 +604 -687
  72. package/lib/language/multiLineStringParser.js +14 -42
  73. package/lib/language/textUtils.js +44 -0
  74. package/lib/main.d.ts +28 -42
  75. package/lib/main.js +104 -81
  76. package/lib/model/api.js +1 -1
  77. package/lib/model/csnRefs.js +57 -30
  78. package/lib/model/csnUtils.js +189 -287
  79. package/lib/model/revealInternalProperties.js +32 -10
  80. package/lib/model/sortViews.js +32 -31
  81. package/lib/modelCompare/compare.js +3 -0
  82. package/lib/optionProcessor.js +91 -57
  83. package/lib/render/.eslintrc.json +1 -1
  84. package/lib/render/DuplicateChecker.js +4 -7
  85. package/lib/render/manageConstraints.js +70 -2
  86. package/lib/render/toCdl.js +387 -367
  87. package/lib/render/toHdbcds.js +20 -16
  88. package/lib/render/toRename.js +44 -22
  89. package/lib/render/toSql.js +81 -59
  90. package/lib/render/utils/common.js +16 -3
  91. package/lib/render/utils/sql.js +20 -19
  92. package/lib/sql-identifier.js +6 -0
  93. package/lib/transform/db/.eslintrc.json +3 -2
  94. package/lib/transform/db/associations.js +43 -35
  95. package/lib/transform/db/cdsPersistence.js +5 -16
  96. package/lib/transform/db/constraints.js +1 -1
  97. package/lib/transform/db/expansion.js +7 -6
  98. package/lib/transform/db/flattening.js +16 -18
  99. package/lib/transform/db/transformExists.js +7 -5
  100. package/lib/transform/db/views.js +3 -3
  101. package/lib/transform/draft/.eslintrc.json +2 -2
  102. package/lib/transform/draft/db.js +6 -6
  103. package/lib/transform/draft/odata.js +6 -7
  104. package/lib/transform/forHanaNew.js +30 -24
  105. package/lib/transform/forOdataNew.js +14 -16
  106. package/lib/transform/localized.js +35 -25
  107. package/lib/transform/odata/toFinalBaseType.js +10 -10
  108. package/lib/transform/odata/typesExposure.js +17 -8
  109. package/lib/transform/odata/utils.js +1 -38
  110. package/lib/transform/transformUtilsNew.js +63 -77
  111. package/lib/transform/translateAssocsToJoins.js +2 -2
  112. package/lib/transform/universalCsn/.eslintrc.json +2 -2
  113. package/lib/transform/universalCsn/coreComputed.js +11 -6
  114. package/lib/transform/universalCsn/universalCsnEnricher.js +33 -5
  115. package/lib/utils/file.js +31 -21
  116. package/lib/utils/moduleResolve.js +0 -1
  117. package/lib/utils/timetrace.js +20 -21
  118. package/package.json +34 -4
  119. package/share/messages/syntax-expected-integer.md +9 -8
  120. package/doc/ApiMigration.md +0 -237
  121. package/doc/CommandLineMigration.md +0 -58
  122. package/doc/ErrorMessages.md +0 -175
  123. package/doc/FioriAnnotations.md +0 -94
  124. package/doc/ODataTransformation.md +0 -273
  125. package/lib/backends.js +0 -529
  126. package/lib/checks/unknownMagic.js +0 -41
  127. package/lib/fix_antlr4-8_warning.js +0 -56
@@ -88,6 +88,7 @@
88
88
  */
89
89
 
90
90
  const { dictAdd } = require('../base/dictionaries');
91
+ const { quotedLiteralPatterns } = require('../compiler/builtins');
91
92
 
92
93
  const $location = Symbol.for('cds.$location');
93
94
 
@@ -136,7 +137,7 @@ const schemaClasses = {
136
137
  condition: {
137
138
  arrayOf: exprOrString,
138
139
  type: condition,
139
- msgId: 'syntax-csn-expected-term',
140
+ msgId: 'syntax-expected-term',
140
141
  // TODO: also specify requires here, and adapt onlyWith()
141
142
  optional: exprProperties,
142
143
  },
@@ -146,11 +147,11 @@ const schemaClasses = {
146
147
  },
147
148
  natnumOrStar: {
148
149
  type: natnumOrStar,
149
- msgId: 'syntax-csn-expected-cardinality',
150
+ msgId: 'syntax-expected-cardinality',
150
151
  },
151
152
  columns: {
152
153
  arrayOf: selectItem,
153
- msgId: 'syntax-csn-expected-column',
154
+ msgId: 'syntax-expected-column',
154
155
  defaultKind: '$column',
155
156
  validKinds: [], // pseudo kind '$column'
156
157
  // A column with only as+cast.type is a new association
@@ -228,7 +229,7 @@ const schema = compileSchema( {
228
229
  dictionaryOf: definition,
229
230
  defaultKind: 'action',
230
231
  validKinds: [ 'action', 'function' ],
231
- inKind: [ 'entity', 'annotate', 'extend' ],
232
+ inKind: [ 'entity', 'aspect', 'annotate', 'extend' ],
232
233
  },
233
234
  params: {
234
235
  dictionaryOf: definition,
@@ -291,7 +292,7 @@ const schema = compileSchema( {
291
292
  // type properties (except: elements, enum, keys, on): ---------------------
292
293
  type: {
293
294
  type: artifactRef,
294
- msgId: 'syntax-csn-expected-reference',
295
+ msgId: 'syntax-expected-reference',
295
296
  optional: [ 'ref', 'global' ],
296
297
  inKind: [ 'element', 'type', 'param', 'mixin', 'event', 'annotation' ],
297
298
  },
@@ -367,7 +368,7 @@ const schema = compileSchema( {
367
368
  ref: {
368
369
  arrayOf: refItem,
369
370
  type: renameTo( 'path', arrayOf( refItem ) ),
370
- msgId: 'syntax-csn-expected-reference',
371
+ msgId: 'syntax-expected-reference',
371
372
  minLength: 1,
372
373
  requires: 'id',
373
374
  optional: [ 'id', 'args', 'cardinality', 'where' ],
@@ -583,7 +584,7 @@ const schema = compileSchema( {
583
584
  inKind: [ 'element', '$column' ],
584
585
  },
585
586
  masked: {
586
- type: boolOrNull,
587
+ type: masked,
587
588
  inKind: [ 'element' ],
588
589
  },
589
590
  notNull: {
@@ -683,15 +684,6 @@ const topLevelSpec = {
683
684
  schema,
684
685
  };
685
686
 
686
- const validLiteralsExtra = Object.assign( Object.create(null), {
687
- // TODO: should we use quotedLiteralPatterns from genericAntlrParser?
688
- number: 'string',
689
- x: 'string',
690
- time: 'string',
691
- date: 'string',
692
- timestamp: 'string',
693
- } );
694
-
695
687
  // Module variables, schema compilation, and functors ------------------------
696
688
 
697
689
  /** @type {(id, location, textOrArguments, texts?) => void} */
@@ -780,7 +772,7 @@ function arrayOf( fn, filter = undefined ) {
780
772
  } );
781
773
  const minLength = spec.minLength || 0;
782
774
  if (minLength > val.length) {
783
- message( 'syntax-csn-expected-length', location(true),
775
+ message( 'syntax-expected-length', location(true),
784
776
  { prop: spec.prop, n: minLength, '#': minLength === 1 ? 'one' : 'std' });
785
777
  }
786
778
  if (val.length)
@@ -850,7 +842,7 @@ function object( obj, spec ) {
850
842
  if (requires === undefined || requires === true) {
851
843
  // console.log(csnProps,JSON.stringify(spec))
852
844
  if (!relevantProps) {
853
- error( 'syntax-csn-required-subproperty', location(true),
845
+ error( 'syntax-required-subproperty', location(true),
854
846
  {
855
847
  prop: spec.msgProp,
856
848
  '#': (
@@ -876,7 +868,7 @@ function object( obj, spec ) {
876
868
 
877
869
  function vZeroDelete( o, spec ) { // for old-CSN property 'origin'
878
870
  if (!csnVersionZero) {
879
- warning( 'syntax-csn-zero-delete', location(true), { prop: spec.msgProp },
871
+ warning( 'syntax-zero-delete', location(true), { prop: spec.msgProp },
880
872
  'Delete/inline CSN v0.1.0 property $(PROP)' );
881
873
  }
882
874
  string( o, spec );
@@ -961,7 +953,7 @@ function definition( def, spec, xsn, csn, name ) {
961
953
  function dictionaryOf( elementFct ) {
962
954
  return function dictionary( dict, spec ) {
963
955
  if (!dict || typeof dict !== 'object' || Array.isArray( dict )) {
964
- error( 'syntax-csn-expected-object', location(true),
956
+ error( 'syntax-expected-object', location(true),
965
957
  { prop: spec.prop }); // spec.prop, not spec.msgProp!
966
958
  return ignore( dict );
967
959
  }
@@ -973,7 +965,7 @@ function dictionaryOf( elementFct ) {
973
965
  ++virtualLine;
974
966
  for (const name of allNames) {
975
967
  if (!name) {
976
- warning( 'syntax-csn-empty-name', location(true),
968
+ warning( 'syntax-empty-name', location(true),
977
969
  { prop: spec.prop }, // TODO: Error
978
970
  'Property names in dictionary $(PROP) must not be empty' );
979
971
  }
@@ -1050,11 +1042,11 @@ function validKind( val, spec, xsn ) {
1050
1042
  if (val === xsn.kind) // has been set in definition - the same = ok!
1051
1043
  return undefined; // already set in definition
1052
1044
  if (val === 'view' && xsn.kind === 'entity') {
1053
- warning( 'syntax-csn-zero-value', location(true), { prop: spec.msgProp },
1045
+ warning( 'syntax-zero-value', location(true), { prop: spec.msgProp },
1054
1046
  'Replace CSN v0.1.0 value in $(PROP) by something specified' );
1055
1047
  }
1056
1048
  else if ((val === 'entity' || val === 'type') && xsn.kind === 'aspect') {
1057
- info( 'syntax-csn-aspect', location(true), { kind: 'aspect', '#': val },
1049
+ info( 'syntax-aspect', location(true), { kind: 'aspect', '#': val },
1058
1050
  {
1059
1051
  std: 'Use the dedicated kind $(KIND) for aspect definitions',
1060
1052
  // eslint-disable-next-line max-len
@@ -1062,7 +1054,7 @@ function validKind( val, spec, xsn ) {
1062
1054
  } );
1063
1055
  }
1064
1056
  else {
1065
- error( 'syntax-csn-expected-valid', location(true), { prop: spec.msgProp },
1057
+ error( 'syntax-expected-valid', location(true), { prop: spec.msgProp },
1066
1058
  'Expected valid string for property $(PROP)' );
1067
1059
  }
1068
1060
  return ignore( val );
@@ -1104,7 +1096,7 @@ function vZeroRef( name, spec, xsn ) {
1104
1096
  return;
1105
1097
  const path = name.split('.');
1106
1098
  if (!path.every( id => id)) {
1107
- warning( 'syntax-csn-expected-name', location(true), { prop: spec.msgProp },
1099
+ warning( 'syntax-expected-name', location(true), { prop: spec.msgProp },
1108
1100
  'Expected correct name for property $(PROP)' );
1109
1101
  }
1110
1102
  xsn.path = path.map( id => ({ id, location: location() }) );
@@ -1115,7 +1107,7 @@ function vZeroRef( name, spec, xsn ) {
1115
1107
  function boolOrNull( val, spec ) {
1116
1108
  if ([ true, false, null ].includes( val ))
1117
1109
  return { val, location: location() };
1118
- warning( 'syntax-csn-expected-boolean', location(true), { prop: spec.msgProp },
1110
+ warning( 'syntax-expected-boolean', location(true), { prop: spec.msgProp },
1119
1111
  'Expected boolean or null for property $(PROP)' );
1120
1112
  ignore( val );
1121
1113
  return { val: !!val, location: location() };
@@ -1125,7 +1117,7 @@ function string( val, spec ) {
1125
1117
  if (typeof val === 'string' && val)
1126
1118
  // XSN TODO: do not require literal
1127
1119
  return val;
1128
- error( 'syntax-csn-expected-string', location(true), { prop: spec.msgProp },
1120
+ error( 'syntax-expected-string', location(true), { prop: spec.msgProp },
1129
1121
  'Expected non-empty string for property $(PROP)' );
1130
1122
  return ignore( val );
1131
1123
  }
@@ -1134,7 +1126,7 @@ function stringVal( val, spec ) {
1134
1126
  if (typeof val === 'string' && val)
1135
1127
  // XSN TODO: do not require literal
1136
1128
  return { val, literal: 'string', location: location() };
1137
- error( 'syntax-csn-expected-string', location(true), { prop: spec.msgProp },
1129
+ error( 'syntax-expected-string', location(true), { prop: spec.msgProp },
1138
1130
  'Expected non-empty string for property $(PROP)' );
1139
1131
  return ignore( val );
1140
1132
  }
@@ -1156,7 +1148,7 @@ function natnum( val, spec ) {
1156
1148
  if (typeof val === 'number' && val >= 0)
1157
1149
  // XSN TODO: do not require literal
1158
1150
  return { val, literal: 'number', location: location() };
1159
- error( spec.msgId || 'syntax-csn-expected-natnum', location(true),
1151
+ error( spec.msgId || 'syntax-expected-natnum', location(true),
1160
1152
  { prop: spec.msgProp } );
1161
1153
  return ignore( val );
1162
1154
  }
@@ -1191,10 +1183,8 @@ function annoValue( val, spec ) {
1191
1183
  /** @type {string|boolean} */
1192
1184
  let seenEllipsis = false;
1193
1185
  if (arrayLevelCount > 0) { // TODO: also inside structure (possible in CSN!)
1194
- if (val.some( isEllipsis )) {
1195
- error( 'syntax-csn-unexpected-ellipsis', location(true), { code: '...' },
1196
- 'Unexpected $(CODE) in nested array' );
1197
- }
1186
+ if (val.some( isEllipsis ))
1187
+ error( 'syntax-unexpected-ellipsis', location(true), { '#': 'nested-array', code: '...' } );
1198
1188
  }
1199
1189
  else {
1200
1190
  for (const item of val) {
@@ -1203,7 +1193,7 @@ function annoValue( val, spec ) {
1203
1193
  }
1204
1194
  else if (isEllipsis( item )) { // with or without UP TO
1205
1195
  // error position at the beginning of the array, but that is fine
1206
- error( 'syntax-csn-duplicate-ellipsis', location(true), { code: '...' },
1196
+ error( 'syntax-duplicate-ellipsis', location(true), { code: '...' },
1207
1197
  'Expected no more than one $(CODE)' );
1208
1198
  break;
1209
1199
  }
@@ -1217,7 +1207,7 @@ function annoValue( val, spec ) {
1217
1207
  };
1218
1208
  arrayLevelCount--;
1219
1209
  if (seenEllipsis === 'upTo') {
1220
- error( 'syntax-csn-expecting-ellipsis', location(true), // at closing bracket
1210
+ error( 'syntax-expecting-ellipsis', location(true), // at closing bracket
1221
1211
  { code: '... up to', newcode: '...' },
1222
1212
  // TODO: should we be more CSN specific in the message?
1223
1213
  'Expecting an array item $(NEWCODE) after an item with $(CODE)' );
@@ -1264,11 +1254,14 @@ function annoValue( val, spec ) {
1264
1254
  }
1265
1255
 
1266
1256
  function annotation( val, spec, xsn, csn, name ) {
1267
- const variantIndex = name.indexOf('#') + 1 || name.length;
1268
- const n = refSplit( name.substring( (xsn ? 1 : 0), variantIndex ), spec.msgProp );
1257
+ const absolute = (xsn ? name.substring(1) : name);
1258
+ // TODO: really care about variant (qualifier parts)?
1259
+ const variantIndex = absolute.indexOf('#') + 1 || absolute.length;
1260
+ const n = refSplit( absolute.substring( 0, variantIndex ), spec.msgProp );
1269
1261
  if (!n)
1270
1262
  return undefined;
1271
- if (variantIndex < name.length)
1263
+ n.absolute = absolute;
1264
+ if (variantIndex < absolute.length)
1272
1265
  n.variant = { id: name.substring( variantIndex ), location: location() };
1273
1266
  const r = annoValue( val, spec );
1274
1267
  r.name = n;
@@ -1283,21 +1276,27 @@ function value( val, spec, xsn ) { // for CSN property 'val'
1283
1276
  xsn.literal = (val === null) ? 'null' : typeof val;
1284
1277
  return val;
1285
1278
  }
1286
- error( 'syntax-csn-expected-scalar', location(true), { prop: spec.msgProp },
1279
+ error( 'syntax-expected-scalar', location(true), { prop: spec.msgProp },
1287
1280
  'Only scalar values are supported for property $(PROP)' );
1288
1281
  return ignore( val );
1289
1282
  }
1290
1283
 
1291
- function literal( val, spec, xsn, csn ) {
1284
+ function literal( lit, spec, xsn, csn ) {
1292
1285
  // TODO: general: requires other property (here: 'val')
1293
1286
  const type = (csn.val == null) ? 'null' : typeof csn.val;
1294
- if (val === type) // also for 'object' which is an error for 'val'
1295
- return val;
1296
- if (typeof val === 'string' && validLiteralsExtra[val] === type)
1297
- return val;
1298
- error( 'syntax-csn-expected-valid', location(true), { prop: spec.msgProp },
1287
+ if (lit === type) // also for 'object' which is an error for 'val'
1288
+ return lit;
1289
+ if (typeof lit === 'string' && quotedLiteralPatterns[lit]?.json_type === type) {
1290
+ const p = quotedLiteralPatterns[lit];
1291
+ if (p && p.test_fn && !p.test_fn(csn.val))
1292
+ warning( 'syntax-invalid-literal', location(), { '#': p.test_variant } );
1293
+ return lit;
1294
+ }
1295
+ if (lit === 'number' && type === 'string') // special case, not a quoted literal in CDL
1296
+ return lit;
1297
+ error( 'syntax-expected-valid', location(true), { prop: spec.msgProp },
1299
1298
  'Expected valid string for property $(PROP)' );
1300
- return ignore( val );
1299
+ return ignore( lit );
1301
1300
  }
1302
1301
 
1303
1302
  function func( val, spec, xsn ) {
@@ -1310,7 +1309,7 @@ function func( val, spec, xsn ) {
1310
1309
  function xpr( exprs, spec, xsn, csn ) {
1311
1310
  if (csn.func) {
1312
1311
  if (!exprs.length) {
1313
- message( 'syntax-csn-expected-length', location(true),
1312
+ message( 'syntax-expected-length', location(true),
1314
1313
  { prop: 'xpr', otherprop: 'func', '#': 'suffix' });
1315
1314
  }
1316
1315
  xsn.suffix = exprArgs( exprs, spec );
@@ -1343,7 +1342,7 @@ function args( exprs, spec ) {
1343
1342
  return arrayOf( exprOrString )( exprs, spec );
1344
1343
  }
1345
1344
  else if (!exprs || typeof exprs !== 'object') {
1346
- error( 'syntax-csn-expected-args', location(true),
1345
+ error( 'syntax-expected-args', location(true),
1347
1346
  { prop: spec.prop }, // spec.prop, not spec.msgProp!
1348
1347
  'Expected array or object for property $(PROP)' );
1349
1348
  return ignore( exprs );
@@ -1406,12 +1405,12 @@ function condition( cond, spec ) {
1406
1405
  function vZeroValue( obj, spec, xsn ) {
1407
1406
  if (xsn.value) {
1408
1407
  // TODO: also "sign" xsn.value created by inValue to complain about both 'value' and 'ref' etc
1409
- warning( 'syntax-csn-unexpected-property', location(true), { prop: spec.msgProp },
1408
+ warning( 'syntax-unexpected-property', location(true), { prop: spec.msgProp },
1410
1409
  'Unexpected CSN property $(PROP)' );
1411
1410
  return undefined;
1412
1411
  }
1413
1412
  if (!csnVersionZero) {
1414
- warning( 'syntax-csn-zero-delete', location(true), { prop: spec.msgProp },
1413
+ warning( 'syntax-zero-delete', location(true), { prop: spec.msgProp },
1415
1414
  'Delete/inline CSN v0.1.0 property $(PROP)' );
1416
1415
  }
1417
1416
  return expr( obj, spec );
@@ -1458,6 +1457,12 @@ function excluding( array, spec, xsn ) {
1458
1457
  xsn.excludingDict = r;
1459
1458
  }
1460
1459
 
1460
+ function masked( val, spec ) {
1461
+ message('syntax-invalid-masked', location(), { keyword: 'masked' },
1462
+ 'Keyword $(KEYWORD) not supported');
1463
+ return boolOrNull( val, spec );
1464
+ }
1465
+
1461
1466
  function duplicateExcluding( name, loc ) {
1462
1467
  error( 'duplicate-excluding', loc, { name, keyword: 'excluding' },
1463
1468
  'Duplicate $(NAME) in the $(KEYWORD) clause' );
@@ -1478,7 +1483,7 @@ function join( val, spec, xsn ) {
1478
1483
 
1479
1484
  function queryArgs( val, spec, xsn, csn ) {
1480
1485
  if (Array.isArray( val ) && val.length > 1 && !csn.op) {
1481
- warning( 'syntax-csn-expected-property', location(true),
1486
+ warning( 'syntax-expected-property', location(true),
1482
1487
  { prop: 'args', otherprop: 'op' },
1483
1488
  'CSN property $(PROP) expects property $(OTHERPROP) to be specified' );
1484
1489
  xsn.op = { val: 'union', location: location() };
@@ -1497,7 +1502,7 @@ function i18nLang( val, spec, xsn, csn, langKey ) {
1497
1502
  function translations( keyVal, spec, xsn, csn, textKey ) {
1498
1503
  if (typeof keyVal === 'string') // allow empty string
1499
1504
  return { val: keyVal, literal: 'string', location: location() };
1500
- error( 'syntax-csn-expected-translation', location(true),
1505
+ error( 'syntax-expected-translation', location(true),
1501
1506
  { prop: textKey, otherprop: spec.prop },
1502
1507
  'Expected string for text key $(PROP) of language $(OTHERPROP)' );
1503
1508
  return ignore( keyVal );
@@ -1511,7 +1516,7 @@ function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
1511
1516
  if (!s || s.noPrefix && prop !== p0 ) {
1512
1517
  if (ourpropsRegex.test( prop )) {
1513
1518
  // TODO v2: Warning only with --sloppy
1514
- warning( 'syntax-csn-unknown-property', location(true), { prop },
1519
+ warning( 'syntax-unknown-property', location(true), { prop },
1515
1520
  'Unknown CSN property $(PROP)' );
1516
1521
  }
1517
1522
  else { // TODO v2: always (i.e. also with message) add to $extra
@@ -1522,14 +1527,14 @@ function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
1522
1527
  if (s.ignore)
1523
1528
  return { type: ignore };
1524
1529
  if (s.vZeroIgnore && s.vZeroIgnore === csn[prop]) { // for "op": "call"
1525
- warning( 'syntax-csn-zero-delete', location(true), { prop },
1530
+ warning( 'syntax-zero-delete', location(true), { prop },
1526
1531
  'Delete/inline CSN v0.1.0 property $(PROP)' );
1527
1532
  return { type: ignore };
1528
1533
  }
1529
1534
  const zero = s.vZeroFor;
1530
1535
  if (zero) { // (potential) CSN v0.1.0 property
1531
1536
  const group = s.xorGroup;
1532
- if (zero && expected( zero, schema[zero] ) && !(group && xor[group])) {
1537
+ if (expected( zero, schema[zero] ) && !(group && xor[group])) {
1533
1538
  replaceZeroProp( prop, zero );
1534
1539
  if (group)
1535
1540
  xor[group] = prop;
@@ -1541,7 +1546,7 @@ function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
1541
1546
  const variant = kind && s.inKind
1542
1547
  ? ([ 'extend', 'annotate' ].includes(kind) ? kind : 'def')
1543
1548
  : (parentSpec.msgProp ? 'std' : 'top');
1544
- message( 'syntax-csn-unexpected-property', location(true),
1549
+ message( 'syntax-unexpected-property', location(true),
1545
1550
  {
1546
1551
  prop, otherprop: parentSpec.msgProp, kind, '#': variant,
1547
1552
  },
@@ -1549,7 +1554,7 @@ function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
1549
1554
  std: 'CSN property $(PROP) is not expected in $(OTHERPROP)',
1550
1555
  top: 'CSN property $(PROP) is not expected top-level',
1551
1556
  def: 'CSN property $(PROP) is not expected by a definition of kind $(KIND)',
1552
- extend: 'CSN property $(PROP) is not expected by an extend in $(OTHERPROP))',
1557
+ extend: 'CSN property $(PROP) is not expected by an extend in $(OTHERPROP)',
1553
1558
  annotate: 'CSN property $(PROP) is not expected by an annotate in $(OTHERPROP)',
1554
1559
  } );
1555
1560
  // TODO: or still augment it? (but then also handle xorGroup)
@@ -1599,13 +1604,13 @@ function onlyWith( spec, need, csn, prop, xor, expected ) {
1599
1604
  need = allowed.find( p => !xor[schema[p].xorGroup] ) || allowed[0];
1600
1605
  }
1601
1606
  if (prop) {
1602
- error( 'syntax-csn-dependent-property', location(true),
1607
+ error( 'syntax-dependent-property', location(true),
1603
1608
  { prop, otherprop: need },
1604
1609
  'CSN property $(PROP) can only be used in combination with $(OTHERPROP)');
1605
1610
  xor['no:req'] = prop;
1606
1611
  }
1607
1612
  else if (!xor['no:req']) {
1608
- error( 'syntax-csn-required-property', location(true),
1613
+ error( 'syntax-required-property', location(true),
1609
1614
  { prop: need, otherprop: spec.msgProp, '#': spec.prop },
1610
1615
  { // TODO $(PARENT), TODO: do not use prop===0 hack
1611
1616
  std: 'Object in $(OTHERPROP) must have the property $(PROP)',
@@ -1627,7 +1632,7 @@ function checkAndSetXorGroup( group, prop, xor ) {
1627
1632
  if (prop === 'func' && xor[group] === 'xpr' ||
1628
1633
  prop === 'xpr' && xor[group] === 'func')
1629
1634
  return true; // hack for window function: both func and xpr is allowed
1630
- error( 'syntax-csn-excluded-property', location(true),
1635
+ error( 'syntax-excluded-property', location(true),
1631
1636
  { prop, otherprop: xor[group] },
1632
1637
  'CSN property $(PROP) can only be used alternatively to $(OTHERPROP)');
1633
1638
  return false;
@@ -1642,7 +1647,7 @@ function implicitName( ref ) {
1642
1647
  function replaceZeroProp( otherprop, prop ) {
1643
1648
  if (csnVersionZero)
1644
1649
  return;
1645
- warning( 'syntax-csn-zero-prop', location(true), { prop, otherprop },
1650
+ warning( 'syntax-zero-prop', location(true), { prop, otherprop },
1646
1651
  'Replace CSN v0.1.0 property $(OTHERPROP) by $(PROP)' );
1647
1652
  }
1648
1653
 
@@ -1651,7 +1656,7 @@ function replaceZeroProp( otherprop, prop ) {
1651
1656
  function isArray( array, spec ) {
1652
1657
  if (Array.isArray( array ))
1653
1658
  return array;
1654
- error( 'syntax-csn-expected-array', location(true), { prop: spec.prop },
1659
+ error( 'syntax-expected-array', location(true), { prop: spec.prop },
1655
1660
  'Expected array for property $(PROP)' );
1656
1661
  return ignore( array );
1657
1662
  }
@@ -1659,7 +1664,7 @@ function isArray( array, spec ) {
1659
1664
  function isObject( obj, spec ) {
1660
1665
  if (obj && typeof obj === 'object' && !Array.isArray( obj ))
1661
1666
  return obj;
1662
- error( spec.msgId || 'syntax-csn-expected-object', location(true),
1667
+ error( spec.msgId || 'syntax-expected-object', location(true),
1663
1668
  { prop: spec.msgProp });
1664
1669
  return ignore( obj );
1665
1670
  }
@@ -1667,7 +1672,7 @@ function isObject( obj, spec ) {
1667
1672
  function refSplit( name, prop ) {
1668
1673
  const path = name.split('.');
1669
1674
  if (!path.every( id => id)) {
1670
- warning( 'syntax-csn-expected-name', location(true), { prop },
1675
+ warning( 'syntax-expected-name', location(true), { prop },
1671
1676
  'Expected correct name for property $(PROP)' );
1672
1677
  }
1673
1678
  return { path: path.map( id => ({ id, location: location() }) ), location: location() };
@@ -1675,7 +1680,7 @@ function refSplit( name, prop ) {
1675
1680
 
1676
1681
  function replaceZeroValue( spec ) {
1677
1682
  if (!csnVersionZero && spec.vZeroFor == null) { // but 0 does not match!
1678
- warning( 'syntax-csn-zero-value', location(true), { prop: spec.msgProp },
1683
+ warning( 'syntax-zero-value', location(true), { prop: spec.msgProp },
1679
1684
  'Replace CSN v0.1.0 value in $(PROP) by something specified' );
1680
1685
  }
1681
1686
  }
@@ -1705,7 +1710,7 @@ function pushLocation( obj ) {
1705
1710
  else if (!loc || typeof loc !== 'string') {
1706
1711
  if (loc)
1707
1712
  dollarLocations.push( null ); // must match with popLocation()
1708
- error( 'syntax-csn-expected-object', location(true), { prop: '$location' } );
1713
+ error( 'syntax-expected-object', location(true), { prop: '$location' } );
1709
1714
  }
1710
1715
  // hidden feature: string $location
1711
1716
  const m = /:(\d+)(?::(\d+))?$/.exec( loc ); // extra '^'s at end deliberately left out
@@ -1777,7 +1782,7 @@ function toXsn( csn, filename, options, messageFunctions ) {
1777
1782
  }
1778
1783
 
1779
1784
 
1780
- function augment( csn, filename = 'csn.json', options = {}, messageFunctions ) {
1785
+ function augment( csn, filename = 'csn.json', options = {}, messageFunctions = {} ) {
1781
1786
  try {
1782
1787
  return toXsn( csn, filename, options, messageFunctions );
1783
1788
  }
@@ -1787,7 +1792,7 @@ function augment( csn, filename = 'csn.json', options = {}, messageFunctions ) {
1787
1792
  }
1788
1793
  }
1789
1794
 
1790
- function parse( source, filename = 'csn.json', options = {}, messageFunctions ) {
1795
+ function parse( source, filename = 'csn.json', options = {}, messageFunctions = {} ) {
1791
1796
  try {
1792
1797
  return augment( JSON.parse(source), filename, options, messageFunctions );
1793
1798
  }
@@ -1818,7 +1823,7 @@ function parse( source, filename = 'csn.json', options = {}, messageFunctions )
1818
1823
  line,
1819
1824
  col: column,
1820
1825
  };
1821
- messageFunctions.error( 'syntax-csn-illegal-json', loc, { msg }, 'Illegal JSON: $(MSG)' );
1826
+ messageFunctions.error( 'syntax-illegal-json', loc, { msg }, 'Illegal JSON: $(MSG)' );
1822
1827
  return xsn;
1823
1828
  }
1824
1829
  }
@@ -13,6 +13,7 @@
13
13
 
14
14
  const { locationString } = require('../base/messages');
15
15
  const { isBetaEnabled, isDeprecatedEnabled } = require('../base/model');
16
+ const { pathName } = require('../compiler/utils');
16
17
 
17
18
  const compilerVersion = require('../../package.json').version;
18
19
  const creator = `CDS Compiler v${ compilerVersion }`;
@@ -126,9 +127,6 @@ const transformers = {
126
127
  // location is not renamed to $location as the name is well established in
127
128
  // XSN and too many places (also outside the compiler) had to be adapted
128
129
  location, // non-enumerable $location in CSN
129
- $a2j: (e, csn) => { // on artifact level
130
- Object.assign( csn, e );
131
- },
132
130
  $extra: (e, csn) => {
133
131
  Object.assign( csn, e );
134
132
  },
@@ -224,7 +222,7 @@ const operators = {
224
222
  unboundedFollowing: [ 'unbounded', 'following' ],
225
223
  following: postfix( [ 'following' ] ),
226
224
  frameBetween: exprs => [ 'between', ...exprs[0], 'and', ...exprs[1] ],
227
- // xpr: (exprs) => [].concat( ...exprs ), see below - handled extra
225
+ ixpr: exprs => [].concat( ...exprs ), // xpr extra, due to extra parentheses
228
226
  };
229
227
 
230
228
  const csnDictionaries = [
@@ -727,7 +725,8 @@ function annotationsAndDocComment( node, annotated ) {
727
725
  const val = node[prop];
728
726
  // val.$priority isn't set for computed annotations like @Core.Computed
729
727
  // and @odata.containment.ignore
730
- if (val.$priority && (val.$priority !== 'define') === annotated) {
728
+ // TODO: use $inferred instead special $priority value
729
+ if (val.$priority !== undefined && (!!val.$priority) === annotated) {
731
730
  // transformer (= value) takes care to exclude $inferred annotation assignments
732
731
  const sub = transformer( val );
733
732
  // As value() just has one value, so we do not provide ( val, csn, node, prop )
@@ -1219,8 +1218,8 @@ function value( node ) {
1219
1218
  if (node.$inferred && gensrcFlavor)
1220
1219
  return undefined;
1221
1220
  if (node.path) {
1222
- const ref = node.path.map( id => id.id ).join('.');
1223
- return extra( { '=': node.variant ? `${ ref }#${ node.variant.id }` : ref }, node );
1221
+ const ref = pathName( node.path );
1222
+ return extra( { '=': node.variant ? `${ ref }#${ pathName(node.variant.path) }` : ref }, node );
1224
1223
  }
1225
1224
  if (node.literal === 'enum')
1226
1225
  return extra( { '#': node.sym.id }, node );
@@ -1276,8 +1275,11 @@ function expression( node, dollarExtra ) {
1276
1275
  return { ref: [ node.param.val ], param: true }; // CDL rule for runtimes
1277
1276
  }
1278
1277
  if (node.path) {
1278
+ const ref = node.path.map( pathItem );
1279
+ if (node.path.$prefix)
1280
+ ref.unshift( node.path.$prefix );
1279
1281
  // we would need to consider node.global here if we introduce that
1280
- return extra( { ref: node.path.map( pathItem ) }, dollarExtraNode );
1282
+ return extra( { ref }, dollarExtraNode );
1281
1283
  }
1282
1284
  if (node.literal) {
1283
1285
  if (typeof node.val === node.literal || node.val === null)
@@ -1590,10 +1592,11 @@ function compactExpr( e ) { // TODO: options
1590
1592
  */
1591
1593
  function initModuleVars( options = { csnFlavor: 'gensrc' } ) {
1592
1594
  gensrcFlavor = options.parseCdl || options.csnFlavor === 'gensrc' ||
1593
- options.toCsn && options.toCsn.flavor === 'gensrc';
1594
- universalCsn = (options.csnFlavor === 'universal' ||
1595
- options.toCsn && options.toCsn.flavor === 'universal' ) &&
1596
- isBetaEnabled( options, 'enableUniversalCsn' ) && !options.parseCdl;
1595
+ ( options.toCsn && options.toCsn.flavor === 'gensrc');
1596
+ universalCsn = ( options.csnFlavor === 'universal' ||
1597
+ ( options.toCsn && options.toCsn.flavor === 'universal') ) &&
1598
+ isBetaEnabled( options, 'enableUniversalCsn' ) &&
1599
+ !options.parseCdl;
1597
1600
  strictMode = options.testMode;
1598
1601
  const proto = options.dictionaryPrototype;
1599
1602
  // eslint-disable-next-line no-nested-ternary
@@ -1601,8 +1604,8 @@ function initModuleVars( options = { csnFlavor: 'gensrc' } ) {
1601
1604
  ? proto
1602
1605
  : (proto) ? Object.prototype : null;
1603
1606
  withLocations = options.withLocations;
1604
- parensAsStrings = isDeprecatedEnabled( options, 'parensAsStrings' );
1605
- projectionAsQuery = isDeprecatedEnabled( options, 'projectionAsQuery' );
1607
+ parensAsStrings = isDeprecatedEnabled( options, '_parensAsStrings' );
1608
+ projectionAsQuery = isDeprecatedEnabled( options, '_projectionAsQuery' );
1606
1609
  }
1607
1610
 
1608
1611
  module.exports = {
@@ -13,8 +13,8 @@ const antlr4 = require('antlr4');
13
13
  const { CompileMessage } = require('../base/messages');
14
14
  const errorStrategy = require('./errorStrategy');
15
15
 
16
- const Parser = require('../gen/languageParser').languageParser;
17
- const Lexer = require('../gen/languageLexer').languageLexer;
16
+ const Parser = require('../gen/languageParser').default;
17
+ const Lexer = require('../gen/languageLexer').default;
18
18
 
19
19
  // Error listener used for ANTLR4-generated parser
20
20
  class ErrorListener extends antlr4.error.ErrorListener {