@sap/cds-compiler 5.9.2 → 6.0.10

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 (111) hide show
  1. package/CHANGELOG.md +109 -319
  2. package/README.md +1 -1
  3. package/bin/cds_update_identifiers.js +3 -5
  4. package/bin/cdsc.js +22 -8
  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 +190 -96
  13. package/lib/base/messages.js +29 -20
  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 +30 -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 +12 -9
  27. package/lib/compiler/checks.js +18 -50
  28. package/lib/compiler/define.js +6 -6
  29. package/lib/compiler/extend.js +2 -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 +35 -22
  34. package/lib/compiler/shared.js +7 -1
  35. package/lib/compiler/tweak-assocs.js +1 -1
  36. package/lib/compiler/utils.js +1 -1
  37. package/lib/edm/annotations/edmJson.js +20 -15
  38. package/lib/edm/annotations/genericTranslation.js +7 -8
  39. package/lib/edm/csn2edm.js +46 -50
  40. package/lib/edm/edm.js +8 -7
  41. package/lib/edm/edmPreprocessor.js +37 -85
  42. package/lib/edm/edmUtils.js +2 -2
  43. package/lib/gen/BaseParser.js +55 -44
  44. package/lib/gen/CdlGrammar.checksum +1 -1
  45. package/lib/gen/CdlParser.js +1133 -1150
  46. package/lib/json/from-csn.js +70 -43
  47. package/lib/json/to-csn.js +6 -8
  48. package/lib/language/multiLineStringParser.js +3 -2
  49. package/lib/main.d.ts +58 -24
  50. package/lib/model/csnUtils.js +28 -39
  51. package/lib/model/xprAsTree.js +23 -9
  52. package/lib/modelCompare/compare.js +5 -4
  53. package/lib/optionProcessor.js +21 -17
  54. package/lib/parsers/AstBuildingParser.js +63 -11
  55. package/lib/parsers/XprTree.js +57 -3
  56. package/lib/parsers/identifiers.js +1 -1
  57. package/lib/parsers/index.js +0 -3
  58. package/lib/render/manageConstraints.js +25 -25
  59. package/lib/render/toCdl.js +173 -170
  60. package/lib/render/toHdbcds.js +126 -128
  61. package/lib/render/toRename.js +7 -7
  62. package/lib/render/toSql.js +128 -125
  63. package/lib/render/utils/common.js +47 -22
  64. package/lib/render/utils/delta.js +25 -25
  65. package/lib/render/utils/operators.js +2 -2
  66. package/lib/render/utils/pretty.js +5 -5
  67. package/lib/render/utils/sql.js +13 -13
  68. package/lib/render/utils/standardDatabaseFunctions.js +115 -103
  69. package/lib/render/utils/unique.js +4 -4
  70. package/lib/transform/db/applyTransformations.js +1 -1
  71. package/lib/transform/db/assertUnique.js +2 -2
  72. package/lib/transform/db/associations.js +6 -7
  73. package/lib/transform/db/assocsToQueries/utils.js +4 -5
  74. package/lib/transform/db/backlinks.js +12 -9
  75. package/lib/transform/db/cdsPersistence.js +8 -7
  76. package/lib/transform/db/constraints.js +13 -10
  77. package/lib/transform/db/expansion.js +7 -3
  78. package/lib/transform/db/flattening.js +4 -14
  79. package/lib/transform/db/processSqlServices.js +2 -1
  80. package/lib/transform/db/temporal.js +5 -7
  81. package/lib/transform/db/views.js +2 -4
  82. package/lib/transform/draft/db.js +8 -8
  83. package/lib/transform/draft/odata.js +10 -7
  84. package/lib/transform/forOdata.js +10 -5
  85. package/lib/transform/forRelationalDB.js +5 -75
  86. package/lib/transform/localized.js +1 -1
  87. package/lib/transform/odata/createForeignKeys.js +11 -10
  88. package/lib/transform/odata/flattening.js +8 -4
  89. package/lib/transform/odata/foreignKeyRefsInXprAnnos.js +96 -0
  90. package/lib/transform/odata/typesExposure.js +3 -3
  91. package/lib/transform/transformUtils.js +4 -8
  92. package/lib/transform/translateAssocsToJoins.js +14 -7
  93. package/lib/transform/universalCsn/universalCsnEnricher.js +10 -4
  94. package/lib/utils/objectUtils.js +0 -17
  95. package/package.json +10 -13
  96. package/share/messages/def-upcoming-virtual-change.md +1 -1
  97. package/LICENSE +0 -37
  98. package/bin/cds_remove_invalid_whitespace.js +0 -138
  99. package/doc/CHANGELOG_ARCHIVE.md +0 -3604
  100. package/lib/gen/genericAntlrParser.js +0 -3
  101. package/lib/gen/language.checksum +0 -1
  102. package/lib/gen/language.interp +0 -456
  103. package/lib/gen/language.tokens +0 -180
  104. package/lib/gen/languageLexer.interp +0 -439
  105. package/lib/gen/languageLexer.js +0 -1483
  106. package/lib/gen/languageLexer.tokens +0 -167
  107. package/lib/gen/languageParser.js +0 -24941
  108. package/lib/language/antlrParser.js +0 -205
  109. package/lib/language/errorStrategy.js +0 -646
  110. package/lib/language/genericAntlrParser.js +0 -1572
  111. package/lib/parsers/CdlGrammar.g4 +0 -2070
@@ -89,9 +89,6 @@
89
89
  * of the xorGroup may be set, e.g. if target is set, elements may not.
90
90
  * If you are looking for a `notWith` (which should be symmetric), this is your property.
91
91
  *
92
- * @property {string} [xsnOp]
93
- * Defines the operator to be used for XSN. Used for SET and SELECT. See queryTerm().
94
- *
95
92
  * @property {string} [vZeroFor]
96
93
  * Marks the property as a CSN 0.1.0 property. It is replaced by this CSN 1.0
97
94
  * property (value of vZeroFor).
@@ -124,7 +121,7 @@ const { isAnnotationExpression } = require('../base/builtins');
124
121
  const { CompilerAssertion } = require('../base/error');
125
122
  const { Location } = require('../base/location');
126
123
  const { XsnSource } = require('../compiler/xsn-model');
127
- const { xprAsTree } = require('../parsers/XprTree');
124
+ const { xsnAsTree, splitClauses } = require('../parsers/XprTree');
128
125
 
129
126
  const $location = Symbol.for('cds.$location');
130
127
 
@@ -202,7 +199,8 @@ const schemaClasses = {
202
199
  defaultKind: '$column',
203
200
  validKinds: [], // pseudo kind '$column'
204
201
  // A column with only as+cast.type is a new association
205
- requires: [ 'ref', 'cast', 'xpr', 'val', '#', 'func', 'list', 'SELECT', 'SET', 'expand' ],
202
+ requires: [ 'ref', 'cast', 'xpr', 'val', '#', 'func', 'list',
203
+ 'SELECT', 'SET', 'expand', 'virtual' ],
206
204
  schema: {
207
205
  xpr: {
208
206
  class: 'condition',
@@ -211,6 +209,13 @@ const schemaClasses = {
211
209
  inKind: [ '$column' ],
212
210
  inValue: true,
213
211
  },
212
+ cast: { // CDL-style type cast
213
+ // see “global” `cast` schema for SQL `cast` function
214
+ type: embed,
215
+ inValue: false,
216
+ optional: typeProperties,
217
+ inKind: [ '$column' ],
218
+ },
214
219
  '=': {
215
220
  // by not setting `vZeroFor`, we disallow `=` in `columns`.
216
221
  // CSN v0.1 didn't have columns, so this isn't breaking v0.1 compatibility.
@@ -524,7 +529,6 @@ const schema = compileSchema( {
524
529
  },
525
530
  projection: {
526
531
  type: queryTerm,
527
- xsnOp: 'SELECT',
528
532
  requires: 'from',
529
533
  optional: [
530
534
  'from', 'all', 'distinct', 'columns', 'excluding', // no 'mixin'
@@ -534,7 +538,6 @@ const schema = compileSchema( {
534
538
  },
535
539
  SELECT: {
536
540
  type: queryTerm,
537
- xsnOp: 'SELECT',
538
541
  requires: 'from',
539
542
  optional: [
540
543
  'from', 'mixin', 'all', 'distinct', 'columns', 'excluding',
@@ -553,15 +556,14 @@ const schema = compileSchema( {
553
556
  },
554
557
  },
555
558
  SET: {
556
- type: queryTerm,
557
- xsnOp: '$query', // might be overwritten by 'op'
559
+ type: querySet,
558
560
  requires: 'args',
559
561
  optional: [ 'op', 'all', 'distinct', 'args', 'orderBy', 'limit' ],
560
562
  schema: {
561
563
  args: {
562
564
  arrayOf: embed, // like query
563
565
  type: queryArgs,
564
- minLength: 1,
566
+ minLength: csn => (csn.op ? 2 : 1),
565
567
  optional: [ 'SELECT', 'SET' ],
566
568
  },
567
569
  },
@@ -692,16 +694,12 @@ const schema = compileSchema( {
692
694
  type: boolOrNull,
693
695
  inKind: [ 'element', '$column' ],
694
696
  },
695
- cast: {
697
+ cast: { // SQL `cast` function
698
+ // see `cast` sub schema inside `columns` for CDL-style type cast
696
699
  type: embed,
697
- // cast can be:
698
- // 1. Inside "columns" => not in value
699
- // 2. Inside "xpr" => inside expressions
700
- // Because of (1) we have to set this property to false.
701
- inValue: false,
702
- optional: typeProperties,
703
- // TODO v6: only in CDL-style cast, otherwise just length,…
704
- inKind: [ '$column' ],
700
+ // see also call of eventualCast() for every (expression) object
701
+ inValue: false, // should have no relevance
702
+ optional: [ 'type', 'length', 'precision', 'scale', 'srid' ],
705
703
  },
706
704
  default: {
707
705
  class: 'expression',
@@ -888,13 +886,15 @@ function arrayOf( fn, filter = undefined ) {
888
886
  ++virtualLine;
889
887
  return fn( v, spec, xsn, csn ) || { location: location() };
890
888
  } );
891
- const minLength = spec.minLength || 0;
889
+ if (val.length)
890
+ ++virtualLine; // [] in one JSON line
891
+ const minLength = (typeof spec.minLength === 'function')
892
+ ? spec.minLength( csn )
893
+ : spec.minLength || 0;
892
894
  if (minLength > val.length) {
893
895
  error( 'syntax-incomplete-array', location(true),
894
896
  { prop: spec.prop, n: minLength, '#': minLength === 1 ? 'one' : 'std' });
895
897
  }
896
- if (val.length)
897
- ++virtualLine; // [] in one JSON line
898
898
  if (filter)
899
899
  return r.filter(filter);
900
900
  return r;
@@ -1581,7 +1581,9 @@ function xpr( exprs, spec, xsn, csn ) {
1581
1581
  }
1582
1582
  xsn.suffix = exprArgs( exprs, spec );
1583
1583
  if (exprs.length > 2)
1584
- xsn.suffix = xprAsTree( exprs, xsn.suffix, xsn.op.location ).args;
1584
+ xsn.suffix = xsnAsTree( exprs, xsn.suffix, xsn.op.location ).args;
1585
+ else if (exprs.length === 2 && exprs[0] === 'over' && exprs[1]?.xpr && !exprs[1].func)
1586
+ xsn.suffix[1].args = splitClauses( xsn.suffix[1].args );
1585
1587
  }
1586
1588
  else {
1587
1589
  // setting $parens here would not always be correct; thus, keep distinction
@@ -1589,7 +1591,7 @@ function xpr( exprs, spec, xsn, csn ) {
1589
1591
  xsn.op = { val: 'xpr', location: location() };
1590
1592
  xsn.args = exprArgs( exprs, spec );
1591
1593
  if (exprs.length > 2)
1592
- xsn.args = xprAsTree( exprs, xsn.args, xsn.op.location ).args;
1594
+ xsn.args = xsnAsTree( exprs, xsn.args, xsn.op.location ).args;
1593
1595
  }
1594
1596
  }
1595
1597
 
@@ -1612,7 +1614,13 @@ function xprInValue( exprs, spec, xsn, csn ) {
1612
1614
 
1613
1615
  function args( exprs, spec ) {
1614
1616
  if (Array.isArray( exprs )) {
1615
- return arrayOf( exprOrString )( exprs, spec );
1617
+ const xsn = arrayOf( exprOrString )( exprs, spec );
1618
+ if (xsn.length) {
1619
+ const last = xsn.at( -1 );
1620
+ if (last?.op?.val === 'xpr' && last.args.length > 4) // `order by` in last arg?
1621
+ last.args = splitClauses( last.args );
1622
+ }
1623
+ return xsn;
1616
1624
  }
1617
1625
  else if (!exprs || typeof exprs !== 'object') {
1618
1626
  error( 'syntax-expecting-args', location(true),
@@ -1641,7 +1649,7 @@ function expr( e, spec ) {
1641
1649
  const xsn = exprArgs( e, spec );
1642
1650
  return (e.length < 3) // optimization
1643
1651
  ? { op: { val: 'ixpr', location: loc }, args: xsn, location: loc }
1644
- : xprAsTree( e, xsn, loc );
1652
+ : xsnAsTree( e, xsn, loc );
1645
1653
  }
1646
1654
  else if (e.length === 1) { // CSN v.0.1.0 way for parentheses
1647
1655
  const loc = location();
@@ -1693,33 +1701,54 @@ function condition( cond, spec ) {
1693
1701
  const xsn = exprArgs( cond, spec );
1694
1702
  // TODO sql-like backends: with the commented `return`, test3 generated sql
1695
1703
  // files will not have the unnecessary `(…)` around `on` anymore → extra PR
1696
- const tree = (cond.length < 3) ? xsn : xprAsTree( cond, xsn, loc ).args;
1704
+ const tree = (cond.length < 3) ? xsn : xsnAsTree( cond, xsn, loc ).args;
1697
1705
  return { op: { val: 'xpr', location: loc }, args: tree, location: loc };
1698
1706
  // return (cond.length < 3) // optimization
1699
1707
  // ? { op: { val: 'ixpr', location: loc }, args: xsn, location: loc }
1700
- // : xprAsTree( cond, xsn, loc );
1708
+ // : xsnAsTree( cond, xsn, loc );
1701
1709
  }
1702
1710
 
1703
1711
  // Queries (std signature) ---------------------------------------------------
1704
1712
 
1705
- function queryTerm( term, spec, xsn ) { // for CSN properties 'SELECT' and 'SET'
1713
+ function queryTerm( term, spec, xsn ) { // for CSN properties 'SELECT' and 'projection'
1706
1714
  // TODO: re-check $location: pushLocation( term ) / popLocation( term )
1707
1715
  xsn.query = object( term, spec );
1708
1716
  if (!xsn.query)
1709
1717
  return;
1710
- // XSN TODO: remove op query and subquery?
1711
- if (!xsn.query.op) {
1712
- xsn.query.op = {
1713
- val: (spec.prop !== 'SET' ? 'SELECT' : '$query'),
1714
- location: location(), // XSN TODO: work without location everywhere
1715
- };
1716
- }
1717
- if (spec.prop !== 'SET' && !xsn.query.from)
1718
- xsn.query.from = null; // make it clear that SELECT is used with parse error
1718
+ xsn.query.op = { val: 'SELECT', location: location() }; // XSN TODO: without location
1719
+ if (!xsn.query.from)
1720
+ xsn.query.from = null; // make it clear that SELECT is used with parse error
1719
1721
  if (spec.prop === 'projection')
1720
1722
  xsn.$syntax = 'projection';
1721
1723
  }
1722
1724
 
1725
+ function querySet( term, spec, xsn ) { // for CSN property 'SET'
1726
+ // TODO: re-check $location: pushLocation( term ) / popLocation( term )
1727
+ xsn.query = object( term, spec );
1728
+ if (!xsn.query || xsn.query.op) // TODO: check for args.length === 1 ?
1729
+ return;
1730
+ const setArgs = xsn.query.args;
1731
+ if (setArgs?.length !== 1)
1732
+ return;
1733
+ const { orderBy, limit } = xsn.query;
1734
+ xsn.query = setArgs[0];
1735
+ if (!orderBy && !limit)
1736
+ return;
1737
+ if (xsn.query.orderBy || xsn.query.limit) {
1738
+ // giving this error at the exact location would be far more work → not worth
1739
+ error( 'syntax-duplicate-clause', location(true), {
1740
+ '#': 'setForCsn',
1741
+ prop: 'orderBy',
1742
+ siblingprop: 'limit',
1743
+ parentprop: 'args[]',
1744
+ } );
1745
+ }
1746
+ else {
1747
+ xsn.query.orderBy = orderBy;
1748
+ xsn.query.limit = limit;
1749
+ }
1750
+ }
1751
+
1723
1752
  function asQuantifier( quantifier, spec, xsn ) {
1724
1753
  if (quantifier)
1725
1754
  xsn.quantifier = { val: spec.prop, location: location() };
@@ -1766,13 +1795,11 @@ function join( val, spec, xsn ) {
1766
1795
 
1767
1796
  function queryArgs( val, spec, xsn, csn ) {
1768
1797
  if (Array.isArray( val ) && val.length > 1 && !csn.op) {
1769
- // Make it error 'syntax-missing-property#sibling' in v6:
1770
- message( 'syntax-deprecated-auto-union', location(true),
1771
- { siblingprop: 'args', prop: 'op' },
1772
- 'Object with property $(SIBLINGPROP) must also have a property $(PROP)' );
1798
+ error( 'syntax-missing-property', location(true),
1799
+ { '#': 'sibling', siblingprop: 'args', prop: 'op' } );
1773
1800
  xsn.op = { val: 'union', location: location() };
1774
1801
  }
1775
- return arrayOf( object )( val, spec ).map( q => q.query );
1802
+ return arrayOf( object )( val, spec, xsn, csn ).map( q => q.query );
1776
1803
  }
1777
1804
 
1778
1805
  // i18n ------------------------------
@@ -12,7 +12,7 @@
12
12
  'use strict';
13
13
 
14
14
  const { locationString } = require('../base/messages');
15
- const { isBetaEnabled, isDeprecatedEnabled } = require('../base/model');
15
+ const { isBetaEnabled } = require('../base/model');
16
16
  const { pathName } = require('../compiler/utils');
17
17
  const { CompilerAssertion } = require('../base/error');
18
18
 
@@ -31,7 +31,6 @@ const normalizedKind = {
31
31
  let gensrcFlavor = true; // good enough here...
32
32
  let universalCsn = false;
33
33
  let strictMode = false; // whether to dump with unknown properties (in standard)
34
- let projectionAsQuery = false;
35
34
  let withLocations = false;
36
35
  let withDocComments = false;
37
36
  let structXpr = false;
@@ -580,8 +579,6 @@ function dollarSyntax( node, csn ) {
580
579
  // eslint-disable-next-line no-prototype-builtins
581
580
  if (specialDollarValues.hasOwnProperty( node ))
582
581
  return specialDollarValues[node];
583
- if (projectionAsQuery)
584
- return node;
585
582
  setHidden( csn, '$syntax', node );
586
583
  return undefined;
587
584
  }
@@ -650,7 +647,9 @@ function dictionary( dict, keys, prop ) {
650
647
  }
651
648
 
652
649
  function foreignKeys( dict, csn, node ) {
653
- if (universalCsn && dict[$inferred] === 'keys' || !target( node.target, csn, node ) )
650
+ if (!dict || // `Association to many Target` without specified keys
651
+ universalCsn && dict[$inferred] === 'keys' ||
652
+ !target( node.target, csn, node ) )
654
653
  return;
655
654
 
656
655
  if (gensrcFlavor) {
@@ -1286,7 +1285,7 @@ function exprInternal( node, xprParens ) {
1286
1285
 
1287
1286
  const naryOperators = {
1288
1287
  __proto__: null,
1289
- // not '.'
1288
+ '.': true,
1290
1289
  '*': true,
1291
1290
  '/': true,
1292
1291
  '+': true,
@@ -1334,7 +1333,7 @@ function ternaryOperator( node ) {
1334
1333
  function query( node, csn, xsn, _prop, expectedParens = 0 ) {
1335
1334
  if (node.op.val === 'SELECT') {
1336
1335
  if (xsn && xsn.query === node && xsn.$syntax === 'projection' &&
1337
- node.from && node.from.path && !projectionAsQuery) {
1336
+ node.from && node.from.path) {
1338
1337
  csn.projection = addLocation( node.location, standard( node ) );
1339
1338
  return undefined;
1340
1339
  }
@@ -1560,7 +1559,6 @@ function initModuleVars( options = { csnFlavor: 'gensrc' } ) {
1560
1559
  withLocations = options.withLocations;
1561
1560
  withDocComments = options.docComment !== false;
1562
1561
  structXpr = options.structXpr;
1563
- projectionAsQuery = isDeprecatedEnabled( options, '_projectionAsQuery' );
1564
1562
  }
1565
1563
 
1566
1564
  module.exports = {
@@ -71,8 +71,8 @@ function stripIndentation( str ) {
71
71
  }
72
72
 
73
73
  class MultiLineStringParser {
74
- constructor(antlrParser, token) {
75
- this.parser = antlrParser; // for message functions
74
+ constructor(cdsParser, token) {
75
+ this.parser = cdsParser; // for message functions
76
76
  this.token = token;
77
77
  this.str = token.text; // Copy because .text is a getter
78
78
 
@@ -377,6 +377,7 @@ class MultiLineStringParser {
377
377
  */
378
378
  _matchLineBreakAtCurrentChar() {
379
379
  // Only increase line number for \n, because ANTLR does the same
380
+ // TODO: Is this still the case with redepage?
380
381
  switch (this._current()) {
381
382
  case '\r':
382
383
  if (this._lookahead() === '\n') {
package/lib/main.d.ts CHANGED
@@ -126,6 +126,18 @@ declare namespace compiler {
126
126
  * The CDL equivalent of the CSN value `doc: null`, is an empty doc comment.
127
127
  */
128
128
  docComment?: boolean
129
+ /**
130
+ * If this option is `true`, doc comments are propagated just like annotations.
131
+ * If `false`, they won't be propagated at all.
132
+ *
133
+ * See option 'docComment'.
134
+ *
135
+ * Until @sap/cds-compiler v6.0, doc comments were always propagated.
136
+ *
137
+ * @default `false`
138
+ * @since v6.0
139
+ */
140
+ propagateDocComments?: boolean
129
141
  /**
130
142
  * When set to `true`, and the model contains an entity `sap.common.Languages`
131
143
  * with an element `code`, all generated texts entities additionally contain
@@ -135,15 +147,6 @@ declare namespace compiler {
135
147
  * @since v2.8.0
136
148
  */
137
149
  addTextsLanguageAssoc?: boolean
138
- /**
139
- * If set to `true`, add named aspects to the list of 'includes' of the generated entity.
140
- * This will cause propagation of actions from aspect to generated entity.
141
- *
142
- * Will become default in v6.
143
- *
144
- * @since v5.9.0
145
- */
146
- compositionIncludes?: boolean
147
150
  /**
148
151
  * An array of directory names that are used for CDS module lookups.
149
152
  * Lookup directory `node_modules/` is appended if not set explicitly.
@@ -179,12 +182,6 @@ declare namespace compiler {
179
182
  * of the _name_ of the artifact.
180
183
  */
181
184
  withLocations?: boolean|string
182
- /**
183
- * Use the new non-ANTLR based parser for compilation.
184
- *
185
- * @since v5.2.0
186
- */
187
- newParser?: boolean
188
185
  /**
189
186
  * Internal option for LSP only!
190
187
  * If set, each AST gets a `tokenStream` property containing all lexed tokens.
@@ -441,7 +438,7 @@ declare namespace compiler {
441
438
  * Only works with sqlDialect 'sqlite'! Otherwise, it has no effect.
442
439
  *
443
440
  * @since 3.9.0
444
- * @beta
441
+ * @default true (since v5)
445
442
  */
446
443
  betterSqliteSessionVariables?: boolean
447
444
  /**
@@ -454,12 +451,33 @@ declare namespace compiler {
454
451
  * three-valued logic, on databases that support it.
455
452
  * - `==` is still treated as two-valued logic operator.
456
453
  *
457
- * This option will become the default in cds-compiler v6.
454
+ * This option is the default since cds-compiler v6.
458
455
  *
459
456
  * @since 5.9.0
460
- * @default false
457
+ * @default true (since v6.0)
461
458
  */
462
459
  booleanEquality?: boolean
460
+ /**
461
+ * If set to true, a specified set of functions - inspired by OData and SAP HANA -
462
+ * are translated to database-specific variants.
463
+ *
464
+ * See <https://cap.cloud.sap/docs/guides/databases>
465
+ *
466
+ * @since 5.9.2
467
+ * @default true (since v6.0)
468
+ */
469
+ standardDatabaseFunctions?: boolean
470
+ /**
471
+ * If set to true, variable `$now` will be rendered as 'CURRENT_TIMESTAMP' in
472
+ * SQL, instead of `SESSION_CONTEXT('$now')` (or an equivalent clause in other SQL dialects).
473
+ *
474
+ * In cds-compiler <6, `$now` was always rendered as `CURRENT_TIMESTAMP`.
475
+ * Since v6, it is a session variable, except for DEFAULT clauses.
476
+ *
477
+ * @since 6.0
478
+ * @default false
479
+ */
480
+ dollarNowAsTimestamp?: boolean
463
481
  }
464
482
 
465
483
  /**
@@ -536,6 +554,17 @@ declare namespace compiler {
536
554
  * @default false
537
555
  */
538
556
  allowCsnDowngrade?: boolean
557
+ /**
558
+ * If set to true, variable `$now` will be rendered as 'CURRENT_TIMESTAMP'
559
+ * instead of `SESSION_CONTEXT('$now')`.
560
+ *
561
+ * In cds-compiler <6, `$now` was always rendered as `CURRENT_TIMESTAMP`.
562
+ * Since v6, it is a session variable, except for DEFAULT clauses.
563
+ *
564
+ * @since 6.0
565
+ * @default false
566
+ */
567
+ dollarNowAsTimestamp?: boolean
539
568
  }
540
569
 
541
570
  /**
@@ -579,7 +608,7 @@ declare namespace compiler {
579
608
  * entity S.S.Base as projection on S.Base as Base;
580
609
  * ```
581
610
  *
582
- * @default false
611
+ * @default true (since v6)
583
612
  */
584
613
  renderCdlDefinitionNesting?: boolean
585
614
  /**
@@ -587,6 +616,8 @@ declare namespace compiler {
587
616
  * as a `namespace` statement.
588
617
  *
589
618
  * Only usable in combination with `renderCdlDefinitionNesting: true`.
619
+ *
620
+ * @default true (since v6)
590
621
  */
591
622
  renderCdlCommonNamespace?: boolean
592
623
  }
@@ -1257,6 +1288,9 @@ declare namespace compiler {
1257
1288
  /**
1258
1289
  * Renders the given CSN into HDBCDS artifacts.
1259
1290
  *
1291
+ * DEPRECATED! This backend is deprecated and will be removed with cds-compiler v7!
1292
+ *
1293
+ * @deprecated
1260
1294
  * @returns A map of `{ '<artifactName>.hdbcds|hdbconstraint>': '<content>' }` entries.
1261
1295
  */
1262
1296
  function hdbcds(csn: CSN, options?: HdbcdsOptions): Record<string, string>;
@@ -1264,6 +1298,8 @@ declare namespace compiler {
1264
1298
  /**
1265
1299
  * Immutable list of SAP HANA CDS keywords, used for smart quoting in
1266
1300
  * {@link to.hdbcds} with option `sqlMapping: 'plain'`.
1301
+ *
1302
+ * @deprecated
1267
1303
  */
1268
1304
  const keywords: string[];
1269
1305
  }
@@ -1304,11 +1340,6 @@ declare namespace compiler {
1304
1340
  * Rendered model, including extensions.
1305
1341
  */
1306
1342
  model?: string
1307
- /**
1308
- * Rendered `csn.namespace` property + using directives.
1309
- * Useful to keep the `csn.namespace` property when re-compiling the to.cdl() result.
1310
- */
1311
- namespace?: string
1312
1343
  }
1313
1344
 
1314
1345
  /**
@@ -1581,6 +1612,9 @@ declare namespace compiler {
1581
1612
  * Columns and lines are 1-based, i.e. value `0` is an invalid value and
1582
1613
  * indicates absence of the property.
1583
1614
  *
1615
+ * Note that the columns are UTF-16 _code unit_ offsets in a line.
1616
+ * A column is neither the number of _graphemes_ nor _code points_!
1617
+ *
1584
1618
  * All properties are optional, even `file`.
1585
1619
  */
1586
1620
  export type Location = {
@@ -63,7 +63,6 @@ function getUtils( model, universalReady ) {
63
63
  getContextOfArtifact,
64
64
  addStringAnnotationTo,
65
65
  getServiceName,
66
- hasAnnotationValue,
67
66
  getFinalTypeInfo,
68
67
  get$combined,
69
68
  getQueryPrimarySource,
@@ -238,7 +237,8 @@ function getUtils( model, universalReady ) {
238
237
  // Return true if 'node' is a managed association element
239
238
  // TODO: what about elements having a type, which (finally) is an assoc?
240
239
  function isManagedAssociation( node ) {
241
- return node.target !== undefined && node.on === undefined && node.keys;
240
+ // Since v6, managed to-many associations don't get any keys, hence don't require it.
241
+ return node.target !== undefined && node.on === undefined;
242
242
  }
243
243
 
244
244
  /**
@@ -631,34 +631,15 @@ function traverseFrom( from, queryCallback, path = [] ) {
631
631
  }
632
632
  }
633
633
 
634
-
635
634
  /**
636
- * Compare a given annotation value with an expectation value and return
637
- *
638
- * | Expected
639
- * | true | false | null | arb val
640
- * Anno Val |-------|-------|-------|--------
641
- * true | true | false | false | false
642
- * false | false | true | false | false
643
- * null | false | true | true | false
644
- * arb val | false | false | false | true/false
635
+ * Returns true if the artifact should be skipped during persistence.
636
+ * Respects special value `if-unused` by Node runtime.
645
637
  *
646
- * If the annotation value is 'null', 'true' is returned for the expectation values
647
- * 'null' and 'false'. Expecting 'null' for an annotation value 'false' returns
648
- * 'false'.
649
- *
650
- * @param {CSN.Artifact} artifact
651
- * @param {string} annotationName Name of the annotation (including the at-sign)
652
- * @param {any} expected
653
- * @param {boolean} caseInsensitive
638
+ * @param {CSN.Artifact} art
654
639
  * @returns {boolean}
655
640
  */
656
- function hasAnnotationValue( artifact, annotationName, expected = true, caseInsensitive = false ) {
657
- if (expected === false)
658
- return artifact[annotationName] === expected || artifact[annotationName] === null;
659
- else if (typeof artifact[annotationName] === 'string' && caseInsensitive === true)
660
- return artifact[annotationName].toLowerCase() === expected.toLowerCase();
661
- return artifact[annotationName] === expected;
641
+ function hasPersistenceSkipAnnotation( art ) {
642
+ return art['@cds.persistence.skip'] && art['@cds.persistence.skip'] !== 'if-unused';
662
643
  }
663
644
 
664
645
  /**
@@ -682,8 +663,7 @@ function isEdmPropertyRendered( elementCsn, options ) {
682
663
  const isNotIgnored = !elementCsn.target ? !elementCsn['@cds.api.ignore'] : true;
683
664
  const isNavigable = elementCsn.target
684
665
  ? (elementCsn['@odata.navigable'] === undefined ||
685
- elementCsn['@odata.navigable'] !== undefined &&
686
- (elementCsn['@odata.navigable'] === null || elementCsn['@odata.navigable'] === true)) : true;
666
+ (elementCsn['@odata.navigable'] === null || !!elementCsn['@odata.navigable'])) : true;
687
667
  // Foreign Keys can be ignored
688
668
  if (elementCsn['@odata.foreignKey4'])
689
669
  return isNotIgnored && renderForeignKey;
@@ -920,7 +900,7 @@ function setDependencies( csn, refs = csnRefs(csn) ) {
920
900
  * @returns {boolean}
921
901
  */
922
902
  function isPersistedOnDatabase( art ) {
923
- return !(art.kind === 'entity' && (art.abstract || hasAnnotationValue(art, '@cds.persistence.skip')));
903
+ return !(art.kind === 'entity' && (art.abstract || hasPersistenceSkipAnnotation(art)));
924
904
  }
925
905
  /**
926
906
  * Check if the given artifact will be persisted on the database via `CREATE VIEW`
@@ -932,9 +912,9 @@ function isPersistedAsView( artifact ) {
932
912
  return artifact && artifact.kind === 'entity' &&
933
913
  !artifact.$ignore &&
934
914
  !artifact.abstract &&
935
- ((artifact.query || artifact.projection) && !hasAnnotationValue(artifact, '@cds.persistence.table')) &&
936
- !hasAnnotationValue(artifact, '@cds.persistence.skip') &&
937
- !hasAnnotationValue(artifact, '@cds.persistence.exists');
915
+ ((artifact.query || artifact.projection) && !artifact['@cds.persistence.table']) &&
916
+ !hasPersistenceSkipAnnotation(artifact) &&
917
+ !artifact['@cds.persistence.exists'];
938
918
  }
939
919
  /**
940
920
  * Check if the given artifact will be persisted on the database via `CREATE TABLE`
@@ -946,9 +926,9 @@ function isPersistedAsTable( artifact ) {
946
926
  return artifact.kind === 'entity' &&
947
927
  !artifact.$ignore &&
948
928
  !artifact.abstract &&
949
- (!artifact.query && !artifact.projection || hasAnnotationValue(artifact, '@cds.persistence.table')) &&
950
- !hasAnnotationValue(artifact, '@cds.persistence.skip') &&
951
- !hasAnnotationValue(artifact, '@cds.persistence.exists');
929
+ (!artifact.query && !artifact.projection || artifact['@cds.persistence.table']) &&
930
+ !hasPersistenceSkipAnnotation(artifact) &&
931
+ !artifact['@cds.persistence.exists'];
952
932
  }
953
933
 
954
934
  /**
@@ -1127,8 +1107,9 @@ function moveAnnotationsAndDoc( sourceNode, targetNode, overwrite = false ) {
1127
1107
  * filter: Positive filter. If it returns true, annotations for the referenced artifact
1128
1108
  * will be applied.
1129
1109
  * applyToElements: Whether to apply annotations to elements or only to artifacts
1110
+ * @param {Function} error The error function
1130
1111
  */
1131
- function applyAnnotationsFromExtensions( csn, config ) {
1112
+ function applyAnnotationsFromExtensions( csn, config, error ) {
1132
1113
  if (!csn.extensions)
1133
1114
  return;
1134
1115
 
@@ -1137,6 +1118,8 @@ function applyAnnotationsFromExtensions( csn, config ) {
1137
1118
  for (let i = 0; i < csn.extensions.length; ++i) {
1138
1119
  const ext = csn.extensions[i];
1139
1120
  const name = ext.annotate || ext.extend;
1121
+ if (isAnnotateDraftAdminDataWithTenantIndependent(ext))
1122
+ error(null, [ 'extensions', i ], { name }, '$(NAME) can\'t be tenant independent');
1140
1123
  if (name && filter(name)) {
1141
1124
  const def = csn.definitions[name];
1142
1125
  if (def) {
@@ -1153,6 +1136,8 @@ function applyAnnotationsFromExtensions( csn, config ) {
1153
1136
  }
1154
1137
 
1155
1138
  csn.extensions = csn.extensions.filter(ext => ext);
1139
+ if (!csn.extensions.length)
1140
+ delete csn.extensions;
1156
1141
 
1157
1142
  function applyAnnotationsToElements( ext, def ) {
1158
1143
  // Only the definition is arrayed but the extension is not since
@@ -1177,6 +1162,10 @@ function applyAnnotationsFromExtensions( csn, config ) {
1177
1162
  if (Object.keys(ext.elements).length === 0)
1178
1163
  delete ext.elements;
1179
1164
  }
1165
+
1166
+ function isAnnotateDraftAdminDataWithTenantIndependent( ext ) {
1167
+ return ext.annotate && ext.annotate.endsWith('.DraftAdministrativeData') && ext['@cds.tenant.independent'];
1168
+ }
1180
1169
  }
1181
1170
 
1182
1171
  /**
@@ -1187,8 +1176,8 @@ function applyAnnotationsFromExtensions( csn, config ) {
1187
1176
  */
1188
1177
  function hasValidSkipOrExists( artifact ) {
1189
1178
  return artifact.kind === 'entity' &&
1190
- (hasAnnotationValue(artifact, '@cds.persistence.exists', true) ||
1191
- hasAnnotationValue(artifact, '@cds.persistence.skip', true));
1179
+ (artifact['@cds.persistence.exists'] ||
1180
+ hasPersistenceSkipAnnotation(artifact));
1192
1181
  }
1193
1182
 
1194
1183
  /**
@@ -1419,7 +1408,7 @@ module.exports = {
1419
1408
  forEachMember,
1420
1409
  forEachMemberRecursively,
1421
1410
  forAllQueries,
1422
- hasAnnotationValue,
1411
+ hasPersistenceSkipAnnotation,
1423
1412
  isEdmPropertyRendered,
1424
1413
  getArtifactDatabaseNameOf,
1425
1414
  getResultingName,