@sap/cds-compiler 2.7.0 → 2.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/CHANGELOG.md +167 -0
  2. package/bin/cdsc.js +42 -25
  3. package/bin/cdsse.js +1 -0
  4. package/doc/CHANGELOG_BETA.md +10 -0
  5. package/lib/api/.eslintrc.json +2 -0
  6. package/lib/api/main.js +17 -33
  7. package/lib/api/options.js +25 -13
  8. package/lib/api/validate.js +33 -9
  9. package/lib/backends.js +9 -8
  10. package/lib/base/dictionaries.js +2 -1
  11. package/lib/base/keywords.js +32 -2
  12. package/lib/base/message-registry.js +26 -2
  13. package/lib/base/messages.js +25 -9
  14. package/lib/base/model.js +5 -3
  15. package/lib/base/optionProcessorHelper.js +56 -22
  16. package/lib/checks/onConditions.js +5 -0
  17. package/lib/checks/selectItems.js +4 -0
  18. package/lib/checks/types.js +26 -2
  19. package/lib/checks/unknownMagic.js +41 -0
  20. package/lib/checks/validator.js +7 -2
  21. package/lib/compiler/assert-consistency.js +18 -5
  22. package/lib/compiler/base.js +65 -0
  23. package/lib/compiler/builtins.js +30 -1
  24. package/lib/compiler/checks.js +5 -2
  25. package/lib/compiler/definer.js +145 -120
  26. package/lib/compiler/index.js +16 -4
  27. package/lib/compiler/propagator.js +5 -2
  28. package/lib/compiler/resolver.js +207 -47
  29. package/lib/compiler/shared.js +47 -200
  30. package/lib/compiler/utils.js +173 -0
  31. package/lib/edm/annotations/genericTranslation.js +183 -187
  32. package/lib/edm/csn2edm.js +94 -98
  33. package/lib/edm/edm.js +16 -20
  34. package/lib/edm/edmPreprocessor.js +302 -115
  35. package/lib/edm/edmUtils.js +31 -12
  36. package/lib/gen/language.checksum +1 -1
  37. package/lib/gen/language.interp +28 -1
  38. package/lib/gen/language.tokens +79 -69
  39. package/lib/gen/languageLexer.interp +28 -1
  40. package/lib/gen/languageLexer.js +879 -805
  41. package/lib/gen/languageLexer.tokens +71 -62
  42. package/lib/gen/languageParser.js +5308 -4308
  43. package/lib/json/from-csn.js +59 -30
  44. package/lib/json/to-csn.js +354 -105
  45. package/lib/language/antlrParser.js +11 -0
  46. package/lib/language/errorStrategy.js +1 -0
  47. package/lib/language/genericAntlrParser.js +81 -14
  48. package/lib/language/language.g4 +163 -31
  49. package/lib/main.d.ts +136 -17
  50. package/lib/main.js +7 -1
  51. package/lib/model/api.js +78 -0
  52. package/lib/model/csnRefs.js +115 -32
  53. package/lib/model/csnUtils.js +71 -33
  54. package/lib/model/enrichCsn.js +36 -9
  55. package/lib/model/revealInternalProperties.js +20 -4
  56. package/lib/modelCompare/compare.js +2 -1
  57. package/lib/optionProcessor.js +33 -16
  58. package/lib/render/.eslintrc.json +3 -1
  59. package/lib/render/DuplicateChecker.js +1 -1
  60. package/lib/render/toCdl.js +60 -17
  61. package/lib/render/toHdbcds.js +122 -74
  62. package/lib/render/toSql.js +57 -32
  63. package/lib/render/utils/common.js +6 -10
  64. package/lib/sql-identifier.js +6 -1
  65. package/lib/transform/db/constraints.js +273 -119
  66. package/lib/transform/db/draft.js +9 -6
  67. package/lib/transform/db/expansion.js +19 -7
  68. package/lib/transform/db/flattening.js +31 -7
  69. package/lib/transform/db/transformExists.js +344 -66
  70. package/lib/transform/db/views.js +438 -0
  71. package/lib/transform/forHanaNew.js +65 -436
  72. package/lib/transform/forOdataNew.js +21 -10
  73. package/lib/transform/localized.js +2 -0
  74. package/lib/transform/odata/attachPath.js +19 -4
  75. package/lib/transform/odata/generateForeignKeyElements.js +11 -10
  76. package/lib/transform/odata/referenceFlattener.js +44 -38
  77. package/lib/transform/odata/sortByAssociationDependency.js +2 -2
  78. package/lib/transform/odata/structuralPath.js +72 -0
  79. package/lib/transform/odata/structureFlattener.js +13 -10
  80. package/lib/transform/odata/typesExposure.js +22 -12
  81. package/lib/transform/transformUtilsNew.js +55 -9
  82. package/lib/transform/translateAssocsToJoins.js +11 -17
  83. package/lib/transform/universalCsnEnricher.js +67 -0
  84. package/lib/utils/file.js +5 -3
  85. package/lib/utils/term.js +65 -42
  86. package/lib/utils/timetrace.js +48 -26
  87. package/package.json +1 -1
@@ -145,7 +145,7 @@ const schemaClasses = {
145
145
  type: natnumOrStar,
146
146
  msgId: 'syntax-csn-expected-cardinality',
147
147
  },
148
- column: {
148
+ columns: {
149
149
  arrayOf: selectItem,
150
150
  msgId: 'syntax-csn-expected-column',
151
151
  defaultKind: '$column',
@@ -238,15 +238,15 @@ const schema = compileSchema( {
238
238
  validKinds: [],
239
239
  },
240
240
  columns: {
241
- class: 'column',
241
+ class: 'columns',
242
242
  inKind: [ 'extend' ], // only valid in extend and SELECT/projection
243
243
  },
244
244
  expand: {
245
- class: 'column',
245
+ class: 'columns',
246
246
  inKind: [ '$column' ], // only valid in $column
247
247
  },
248
248
  inline: {
249
- class: 'column',
249
+ class: 'columns',
250
250
  inKind: [ '$column' ], // only valid in $column
251
251
  },
252
252
  keys: {
@@ -272,7 +272,7 @@ const schema = compileSchema( {
272
272
  },
273
273
  annotate: {
274
274
  type: kindAndName,
275
- inKind: (kind => kind === 'annotate'), // using array would test 'entity' for extensions[]
275
+ inKind: [ 'annotate' ],
276
276
  },
277
277
  extend: {
278
278
  type: kindAndName,
@@ -326,7 +326,7 @@ const schema = compileSchema( {
326
326
  inKind: [ 'element', 'type', 'param', 'annotation' ],
327
327
  },
328
328
  scale: {
329
- type: natnum,
329
+ type: scalenum,
330
330
  inKind: [ 'element', 'type', 'param', 'annotation' ],
331
331
  },
332
332
  srid: {
@@ -609,10 +609,10 @@ const schema = compileSchema( {
609
609
  inKind: [ 'entity', 'type', 'aspect', 'event', 'extend' ],
610
610
  },
611
611
  returns: {
612
- type: definition,
612
+ type: returnsDefinition,
613
613
  defaultKind: 'param',
614
614
  validKinds: [ 'param' ],
615
- inKind: [ 'action', 'function' ],
615
+ inKind: [ 'action', 'function', 'annotate' ],
616
616
  },
617
617
  technicalConfig: { // treat it like external_property
618
618
  type: extra,
@@ -739,14 +739,15 @@ function compileSchema( specs, proto = null) {
739
739
  throw new Error( `Missing type specification for property "${ p }"` );
740
740
  }
741
741
  }
742
- if (proto)
743
- return r;
742
+ // Set property 'xorGroup' in main and sub schema:
744
743
  for (const group in xorGroups) {
745
744
  for (const prop of xorGroups[group]) {
746
745
  if (r[prop].xorGroup === undefined)
747
746
  r[prop].xorGroup = group;
748
747
  }
749
748
  }
749
+ if (proto)
750
+ return r;
750
751
  for (const prop of exprProperties) {
751
752
  if (r[prop].inValue === undefined)
752
753
  r[prop].inValue = true;
@@ -772,12 +773,8 @@ function arrayOf( fn, filter = undefined ) {
772
773
  } );
773
774
  const minLength = spec.minLength || 0;
774
775
  if (minLength > val.length) {
775
- error( 'syntax-csn-expected-length', location(true),
776
- { prop: spec.prop, n: minLength, '#': minLength === 1 ? 'one' : 'std' },
777
- {
778
- std: 'Expected array in $(PROP) to have at least $(N) items',
779
- one: 'Expected array in $(PROP) to have at least one item',
780
- } );
776
+ message( 'syntax-csn-expected-length', location(true),
777
+ { prop: spec.prop, n: minLength, '#': minLength === 1 ? 'one' : 'std' });
781
778
  }
782
779
  if (val.length)
783
780
  ++virtualLine; // [] in one JSON line
@@ -912,7 +909,7 @@ function definition( def, spec, xsn, csn, name ) {
912
909
  ++virtualLine;
913
910
  }
914
911
  }
915
- if (!r.name && name) {
912
+ if (!r.name && name != null) {
916
913
  r.name = { id: name, location: r.location };
917
914
  if (prop === 'columns' || prop === 'keys' || prop === 'foreignKeys')
918
915
  r.name.$inferred = 'as';
@@ -944,7 +941,10 @@ function definition( def, spec, xsn, csn, name ) {
944
941
  return s.inKind && s.inKind( kind, spec );
945
942
  return s.inKind.includes( kind ) &&
946
943
  // for an 'annotate', both 'annotate' and the "host" kind must be expected
947
- (!inExtensions || s.inKind.includes( inExtensions ));
944
+ (!inExtensions || s.inKind.includes( inExtensions ) ||
945
+ // extending elements in returns can be without 'returns' in CSN
946
+ // TODO: with warning/info?
947
+ inExtensions === 'action' && p === 'elements');
948
948
  }
949
949
  }
950
950
 
@@ -992,12 +992,23 @@ function keys( array, spec, xsn ) {
992
992
  }
993
993
 
994
994
  function selectItem( def, spec, xsn, csn ) {
995
- if (def === '*')
995
+ if (def === '*') // compile() will complain about repeated '*'s
996
996
  return { val: '*', location: location() };
997
997
 
998
998
  return definition( def, spec, xsn, csn, null ); // definer sets name
999
999
  }
1000
1000
 
1001
+ function returnsDefinition( def, spec, xsn, csn ) {
1002
+ // TODO: be stricter in what is allowed inside returns
1003
+ if (!inExtensions)
1004
+ return definition( def, spec, xsn, csn, '' );
1005
+ // for the moment, flatten elements in returns in an annotate
1006
+ // TODO: bigger Core Compiler changes would have to be done otherwise
1007
+ xsn.elements = definition( def, spec, xsn, csn, '' ).elements;
1008
+ xsn.$syntax = 'returns';
1009
+ return undefined;
1010
+ }
1011
+
1001
1012
  // For v1 CSNs with annotation definitions
1002
1013
  function attachVocabInDefinitions( csn ) {
1003
1014
  if (!csn.vocabularies) {
@@ -1124,6 +1135,12 @@ function stringValOrNull( val, spec ) {
1124
1135
  return stringVal(val, spec);
1125
1136
  }
1126
1137
 
1138
+ function scalenum( val, spec ) {
1139
+ if ([ 'floating', 'variable' ].includes(val))
1140
+ return { val, literal: 'string', location: location() };
1141
+ return natnum(val, spec );
1142
+ }
1143
+
1127
1144
  function natnum( val, spec ) {
1128
1145
  if (typeof val === 'number' && val >= 0)
1129
1146
  // XSN TODO: do not require literal
@@ -1248,9 +1265,18 @@ function func( val, spec, xsn ) {
1248
1265
  return { path: [ { id: val, location: location() } ], location: location() };
1249
1266
  }
1250
1267
 
1251
- function xpr( exprs, spec, xsn ) {
1252
- xsn.op = { val: 'xpr', location: location() };
1253
- xsn.args = exists( exprs, spec, xsn );
1268
+ function xpr( exprs, spec, xsn, csn ) {
1269
+ if (csn.func) {
1270
+ if (!exprs.length) {
1271
+ message( 'syntax-csn-expected-length', location(true),
1272
+ { prop: 'xpr', otherprop: 'func', '#': 'suffix' });
1273
+ }
1274
+ xsn.suffix = exprArgs( exprs, spec );
1275
+ }
1276
+ else {
1277
+ xsn.op = { val: 'xpr', location: location() };
1278
+ xsn.args = exprArgs( exprs, spec, xsn );
1279
+ }
1254
1280
  }
1255
1281
 
1256
1282
  function list( exprs, spec, xsn ) {
@@ -1258,15 +1284,15 @@ function list( exprs, spec, xsn ) {
1258
1284
  xsn.args = arrayOf( exprOrString )( exprs, spec, xsn );
1259
1285
  }
1260
1286
 
1261
- function xprInValue( exprs, spec, xsn ) {
1287
+ function xprInValue( exprs, spec, xsn, csn ) {
1262
1288
  // if the top-level xpr is just for a cast:
1263
1289
  if (exprs.length === 1 && exprs[0].cast) {
1264
1290
  const x = {};
1265
- xpr( exprs, spec, x );
1291
+ xpr( exprs, spec, x, csn );
1266
1292
  Object.assign( xsn, x.args[0] );
1267
1293
  }
1268
1294
  else {
1269
- xpr( exprs, spec, xsn );
1295
+ xpr( exprs, spec, xsn, csn );
1270
1296
  }
1271
1297
  }
1272
1298
 
@@ -1315,9 +1341,9 @@ function exprOrString( e, spec ) {
1315
1341
  }
1316
1342
 
1317
1343
  // mark path argument of 'exits' predicate with $expected:'exists'
1318
- function exists( cond, spec, xsn, csn ) {
1319
- const rxsn = arrayOf( exprOrString )(cond, spec, xsn, csn);
1320
- if (Array.isArray(rxsn) && rxsn.some(x => x === 'exists')) {
1344
+ function exprArgs( cond, spec, xsn, csn ) {
1345
+ const rxsn = arrayOf( exprOrString )( cond, spec, xsn, csn );
1346
+ if (Array.isArray( rxsn ) && rxsn.some( x => x === 'exists' )) {
1321
1347
  for (let i = 0; i < rxsn.length - 1; i++) {
1322
1348
  if (rxsn[i] === 'exists' && rxsn[i + 1].path)
1323
1349
  rxsn[++i].$expected = 'exists';
@@ -1330,7 +1356,7 @@ function condition( cond, spec ) {
1330
1356
  const loc = location();
1331
1357
  const x = {
1332
1358
  op: { val: 'xpr', location: loc },
1333
- args: exists( cond, spec ),
1359
+ args: exprArgs( cond, spec ),
1334
1360
  location: loc,
1335
1361
  };
1336
1362
  return x;
@@ -1500,7 +1526,7 @@ function calculateKind( def, spec ) {
1500
1526
  return 'annotate';
1501
1527
  }
1502
1528
  if (spec.prop === 'extensions') {
1503
- inExtensions = (def.extend) ? '' : 'entity';
1529
+ inExtensions = (def.extend) ? '' : 'annotate';
1504
1530
  return (def.extend) ? 'extend' : 'annotate';
1505
1531
  }
1506
1532
  const kind = (def.kind === 'view') ? 'entity' : def.kind; // 'view' is CSN v0.1.0
@@ -1556,6 +1582,9 @@ function checkAndSetXorGroup( group, prop, xor ) {
1556
1582
  xor[group] = prop;
1557
1583
  return true;
1558
1584
  }
1585
+ if (prop === 'func' && xor[group] === 'xpr' ||
1586
+ prop === 'xpr' && xor[group] === 'func')
1587
+ return true; // hack for window function: both func and xpr is allowed
1559
1588
  error( 'syntax-csn-excluded-property', location(true),
1560
1589
  { prop, otherprop: xor[group] },
1561
1590
  'CSN property $(PROP) can only be used alternatively to $(OTHERPROP)');