@sap/cds-compiler 4.7.6 → 4.9.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 (129) hide show
  1. package/CHANGELOG.md +63 -3
  2. package/bin/cds_remove_invalid_whitespace.js +135 -0
  3. package/bin/cds_update_annotations.js +180 -0
  4. package/bin/cds_update_identifiers.js +3 -4
  5. package/bin/cdsc.js +28 -1
  6. package/bin/cdshi.js +13 -3
  7. package/doc/CHANGELOG_BETA.md +24 -1
  8. package/lib/api/main.js +119 -46
  9. package/lib/api/options.js +51 -0
  10. package/lib/api/validate.js +1 -5
  11. package/lib/base/builtins.js +116 -0
  12. package/lib/base/keywords.js +5 -1
  13. package/lib/base/location.js +91 -14
  14. package/lib/base/message-registry.js +76 -46
  15. package/lib/base/messages.js +121 -35
  16. package/lib/base/model.js +4 -7
  17. package/lib/checks/actionsFunctions.js +3 -3
  18. package/lib/checks/annotationsOData.js +3 -0
  19. package/lib/checks/defaultValues.js +5 -2
  20. package/lib/checks/elements.js +2 -1
  21. package/lib/checks/enricher.js +2 -2
  22. package/lib/checks/queryNoDbArtifacts.js +5 -3
  23. package/lib/checks/utils.js +1 -1
  24. package/lib/checks/validator.js +8 -56
  25. package/lib/compiler/assert-consistency.js +11 -7
  26. package/lib/compiler/builtins.js +0 -74
  27. package/lib/compiler/checks.js +105 -29
  28. package/lib/compiler/define.js +37 -25
  29. package/lib/compiler/extend.js +35 -12
  30. package/lib/compiler/index.js +9 -10
  31. package/lib/compiler/lsp-api.js +5 -0
  32. package/lib/compiler/populate.js +13 -5
  33. package/lib/compiler/propagator.js +24 -18
  34. package/lib/compiler/resolve.js +47 -45
  35. package/lib/compiler/shared.js +61 -21
  36. package/lib/compiler/tweak-assocs.js +15 -90
  37. package/lib/compiler/utils.js +3 -3
  38. package/lib/compiler/xpr-rewrite.js +689 -0
  39. package/lib/compiler/{classes.js → xsn-model.js} +0 -16
  40. package/lib/edm/annotations/edmJson.js +7 -5
  41. package/lib/edm/annotations/genericTranslation.js +149 -71
  42. package/lib/edm/csn2edm.js +25 -9
  43. package/lib/edm/edm.js +7 -7
  44. package/lib/edm/edmInboundChecks.js +57 -5
  45. package/lib/edm/edmPreprocessor.js +54 -25
  46. package/lib/edm/edmUtils.js +3 -16
  47. package/lib/gen/Dictionary.json +138 -14
  48. package/lib/gen/language.checksum +1 -1
  49. package/lib/gen/language.interp +1 -1
  50. package/lib/gen/languageParser.js +2085 -1989
  51. package/lib/json/csnVersion.js +7 -4
  52. package/lib/json/from-csn.js +21 -11
  53. package/lib/json/to-csn.js +8 -4
  54. package/lib/language/antlrParser.js +1 -1
  55. package/lib/language/genericAntlrParser.js +23 -16
  56. package/lib/language/multiLineStringParser.js +2 -2
  57. package/lib/language/textUtils.js +1 -1
  58. package/lib/main.d.ts +90 -14
  59. package/lib/main.js +9 -1
  60. package/lib/model/cloneCsn.js +21 -9
  61. package/lib/model/csnRefs.js +153 -42
  62. package/lib/model/csnUtils.js +14 -11
  63. package/lib/model/enrichCsn.js +4 -2
  64. package/lib/model/revealInternalProperties.js +2 -1
  65. package/lib/model/sortViews.js +14 -6
  66. package/lib/modelCompare/compare.js +135 -122
  67. package/lib/optionProcessor.js +49 -2
  68. package/lib/render/DuplicateChecker.js +6 -6
  69. package/lib/render/manageConstraints.js +1 -0
  70. package/lib/render/toCdl.js +6 -3
  71. package/lib/render/toHdbcds.js +4 -48
  72. package/lib/render/toSql.js +6 -3
  73. package/lib/transform/addTenantFields.js +58 -35
  74. package/lib/transform/db/applyTransformations.js +34 -1
  75. package/lib/transform/db/constraints.js +1 -1
  76. package/lib/transform/db/expansion.js +11 -3
  77. package/lib/transform/db/flattening.js +71 -46
  78. package/lib/transform/db/groupByOrderBy.js +2 -2
  79. package/lib/transform/db/temporal.js +6 -3
  80. package/lib/transform/db/transformExists.js +2 -2
  81. package/lib/transform/db/views.js +1 -4
  82. package/lib/transform/effective/annotations.js +194 -0
  83. package/lib/transform/effective/main.js +11 -10
  84. package/lib/transform/effective/misc.js +45 -14
  85. package/lib/transform/effective/types.js +4 -3
  86. package/lib/transform/forOdata.js +29 -12
  87. package/lib/transform/forRelationalDB.js +104 -113
  88. package/lib/transform/localized.js +7 -6
  89. package/lib/transform/odata/flattening.js +228 -107
  90. package/lib/transform/odata/toFinalBaseType.js +10 -26
  91. package/lib/transform/odata/typesExposure.js +41 -25
  92. package/lib/transform/parseExpr.js +4 -7
  93. package/lib/transform/transformUtils.js +50 -43
  94. package/lib/transform/translateAssocsToJoins.js +48 -48
  95. package/lib/transform/universalCsn/coreComputed.js +2 -1
  96. package/lib/transform/universalCsn/universalCsnEnricher.js +12 -16
  97. package/package.json +2 -2
  98. package/share/messages/README.md +4 -0
  99. package/share/messages/anno-duplicate-unrelated-layer.md +1 -1
  100. package/share/messages/anno-missing-rewrite.md +45 -0
  101. package/share/messages/check-proper-type-of.md +1 -1
  102. package/share/messages/def-duplicate-autoexposed.md +1 -1
  103. package/share/messages/extend-repeated-intralayer.md +3 -16
  104. package/share/messages/extend-unrelated-layer.md +1 -1
  105. package/share/messages/message-explanations.json +2 -0
  106. package/share/messages/redirected-to-ambiguous.md +1 -1
  107. package/share/messages/redirected-to-complex.md +1 -1
  108. package/share/messages/redirected-to-unrelated.md +1 -1
  109. package/share/messages/rewrite-not-supported.md +1 -1
  110. package/share/messages/syntax-expecting-unsigned-int.md +2 -2
  111. package/share/messages/type-missing-enum-value.md +59 -0
  112. package/share/messages/wildcard-excluding-one.md +1 -1
  113. package/bin/.eslintrc.json +0 -17
  114. package/lib/api/.eslintrc.json +0 -37
  115. package/lib/checks/.eslintrc.json +0 -31
  116. package/lib/compiler/.eslintrc.json +0 -8
  117. package/lib/edm/.eslintrc.json +0 -46
  118. package/lib/inspect/.eslintrc.json +0 -4
  119. package/lib/json/.eslintrc.json +0 -4
  120. package/lib/language/.eslintrc.json +0 -4
  121. package/lib/model/.eslintrc.json +0 -13
  122. package/lib/modelCompare/utils/.eslintrc.json +0 -22
  123. package/lib/render/.eslintrc.json +0 -22
  124. package/lib/transform/.eslintrc.json +0 -13
  125. package/lib/transform/db/.eslintrc.json +0 -41
  126. package/lib/transform/draft/.eslintrc.json +0 -4
  127. package/lib/transform/effective/.eslintrc.json +0 -4
  128. package/lib/transform/universalCsn/.eslintrc.json +0 -37
  129. package/lib/utils/.eslintrc.json +0 -7
@@ -8,8 +8,10 @@
8
8
  // (Note: the SQL name mapping mode is not reflected in the content of the csn, the version only
9
9
  // signals which default name mapping a backend has to use)
10
10
  // Historic versions:
11
- // 0.0.1 : Used by HANA CDS for its CSN output (incomplete, not well defined, quite different from CDX ...)
12
- // 0.0.2 : CDX in the initial versions with old-style CSN, default for SQL name mapping is 'quoted'
11
+ // 0.0.1 : Used by SAP HANA CDS for its CSN output
12
+ // (incomplete, not well defined, quite different from CDX ...)
13
+ // 0.0.2 : CDX in the initial versions with old-style CSN, default for SQL
14
+ // name mapping is 'quoted'
13
15
  // 0.0.99 : Like 0.0.2, but with new-style CSN
14
16
  // Versions that are currently produced by compiler:
15
17
  // 0.1.0 : Like 0.0.2, default for SQL name mapping is 'plain'
@@ -21,15 +23,16 @@
21
23
  const newCSNVersions = [ '0.1.99', '0.2', '0.2.0', '1.0', '2.0' ];
22
24
 
23
25
  // Check if new-style CSN is requested, i.e. versions >= 0.1.99
24
- function isNewCSN(csn, options) {
26
+ function isNewCSN( csn, options ) {
25
27
  return !( options?.newCsn === false ||
26
28
  (csn.version && !newCSNVersions.includes(csn.version.csn)) ||
27
29
  (csn.$version && !newCSNVersions.includes(csn.$version)));
28
30
  }
29
31
 
30
- function checkCSNVersion(csn, options) {
32
+ function checkCSNVersion( csn, options ) {
31
33
  if (!isNewCSN(csn, options)) {
32
34
  // the new transformer works only with new CSN
35
+ // eslint-disable-next-line global-require
33
36
  const { makeMessageFunction } = require('../base/messages');
34
37
  const { error, throwWithAnyError } = makeMessageFunction(csn, options);
35
38
 
@@ -119,10 +119,11 @@
119
119
  */
120
120
 
121
121
  const { dictAdd } = require('../base/dictionaries');
122
- // TODO: move parts of lib/compiler/builtins to some lib/base/…:
123
- const { isAnnotationExpression, quotedLiteralPatterns } = require('../compiler/builtins');
122
+ const { quotedLiteralPatterns } = require('../compiler/builtins');
123
+ const { isAnnotationExpression } = require('../base/builtins');
124
124
  const { CompilerAssertion } = require('../base/error');
125
- const { XsnSource, CsnLocation } = require('../compiler/classes');
125
+ const { Location } = require('../base/location');
126
+ const { XsnSource } = require('../compiler/xsn-model');
126
127
 
127
128
  const $location = Symbol.for('cds.$location');
128
129
 
@@ -648,7 +649,8 @@ const schema = compileSchema( {
648
649
  noPrefix: false, // just '@' is no CSN property
649
650
  prop: '@‹anno›', // which property name do messages use for annotation assignments?
650
651
  type: annotation,
651
- inKind: () => true, // allowed in all definitions (including columns and extensions)
652
+ // allowed in all definitions except mixins (including columns and extensions)
653
+ inKind: _kind => true, // TODO(v5): (kind !== 'mixin')
652
654
  schema: {
653
655
  '-expr': { // '-expr' and '-' must not exist top-level
654
656
  prop: '@‹anno›',
@@ -744,7 +746,7 @@ const schema = compileSchema( {
744
746
  ignore: true, type: ignore, // TODO: do we need to do something?
745
747
  },
746
748
  namespace: {
747
- type: stringRef,
749
+ type: namespace,
748
750
  },
749
751
  meta: { // meta information
750
752
  type: ignore, // TODO: should we test s/th here?
@@ -1042,6 +1044,11 @@ function definition( def, spec, xsn, csn, name ) {
1042
1044
  }
1043
1045
  }
1044
1046
 
1047
+ function namespace( ref, spec ) {
1048
+ const ns = stringRef(ref, spec);
1049
+ return ns ? { kind: 'namespace', name: ns } : null;
1050
+ }
1051
+
1045
1052
  function couldNotBeEnumProperty( prop ) {
1046
1053
  // returns true for `value` (which we allow with warning when extending an enum with `elements`)
1047
1054
  const inKind = schema[prop]?.inKind; // undefined for annotations, $location, …
@@ -1485,9 +1492,12 @@ function annoValue( val, spec ) {
1485
1492
  function annotation( val, spec, xsn, csn, name ) {
1486
1493
  // not used for the value
1487
1494
  const id = (xsn ? name.substring(1) : name);
1488
- if (!id) { // `"@": …` is already syntax-unknown-property
1495
+ if (!id) // `"@": …` is already syntax-unknown-property
1489
1496
  message( 'syntax-invalid-name', location(true), { '#': '{}' } );
1490
- }
1497
+
1498
+ if (xsn && xsn.kind === 'mixin') // TODO(v5): Remove, adapt spec['@'].inKind
1499
+ message('anno-unexpected-mixin', location(true));
1500
+
1491
1501
  const n = { id, location: location() };
1492
1502
  const r = annoValue( val, spec );
1493
1503
  r.name = n;
@@ -1997,7 +2007,7 @@ function replaceZeroValue( spec, msgVariant, newValue ) {
1997
2007
  function location( enforceJsonPos ) {
1998
2008
  return !enforceJsonPos && dollarLocations.length &&
1999
2009
  dollarLocations[dollarLocations.length - 1] || {
2000
- __proto__: CsnLocation.prototype,
2010
+ __proto__: Location.prototype,
2001
2011
  file: csnFilename,
2002
2012
  line: virtualLine,
2003
2013
  col: 0,
@@ -2010,7 +2020,7 @@ function pushLocation( obj ) {
2010
2020
  if (loc === undefined)
2011
2021
  return;
2012
2022
  if (loc && typeof loc === 'object' && !Array.isArray( loc )) {
2013
- dollarLocations.push( loc.line ? { __proto__: CsnLocation.prototype, ...loc } : null );
2023
+ dollarLocations.push( loc.line ? { __proto__: Location.prototype, ...loc } : null );
2014
2024
  return;
2015
2025
  }
2016
2026
  else if (!loc || typeof loc !== 'string') {
@@ -2028,7 +2038,7 @@ function pushLocation( obj ) {
2028
2038
  const column = m[2] && Number( m[2] ) || 0;
2029
2039
  const file = loc.substring( 0, m.index );
2030
2040
  dollarLocations.push({
2031
- __proto__: CsnLocation.prototype, file, line, col: column,
2041
+ __proto__: Location.prototype, file, line, col: column,
2032
2042
  } );
2033
2043
  }
2034
2044
  }
@@ -2123,7 +2133,7 @@ function parse( source, filename = 'csn.json', options = {}, messageFunctions =
2123
2133
  }
2124
2134
  column = end - eol + 1;
2125
2135
  }
2126
- const loc = new CsnLocation(
2136
+ const loc = new Location(
2127
2137
  filename,
2128
2138
  line,
2129
2139
  column
@@ -236,8 +236,8 @@ function compactModel( model, options = model.options || {} ) {
236
236
  // (not a really useful property at all, avoids XSN inspection by Umbrella)
237
237
  for (const first in srcDict) {
238
238
  const { namespace } = srcDict[first];
239
- if (namespace && namespace.path)
240
- csn.namespace = pathName( namespace.path );
239
+ if (namespace?.name?.path)
240
+ csn.namespace = pathName( namespace.name.path );
241
241
  break;
242
242
  }
243
243
  set( 'definitions', csn, model );
@@ -1008,8 +1008,9 @@ function artifactRef( node, terse ) {
1008
1008
  return undefined;
1009
1009
  // Works also on XSN directly coming from parser and with XSN from CDL->CSN transformation
1010
1010
  // Shortcut for many cases:
1011
- if (terse && node._artifact && !node._artifact._main && terse !== '.path')
1012
- return node._artifact.name.id;
1011
+ const art = node._artifact;
1012
+ if (art && (!art._main || art.kind === '$self') && terse && terse !== '.path')
1013
+ return art.name.id;
1013
1014
  let { path } = node;
1014
1015
  if (!path)
1015
1016
  return undefined; // TODO: complain with strict
@@ -1408,6 +1409,9 @@ function addElementAsColumn( elem, cols ) {
1408
1409
  setHidden( col, '$parens', parens.length );
1409
1410
  addLocation( (parens ? parens[parens.length - 1] : elem.value.location), col );
1410
1411
  }
1412
+ else if (elem.name && !elem.name.$inferred) {
1413
+ addLocation( elem.name.location, col );
1414
+ }
1411
1415
  cols.push( extra( col, elem ) );
1412
1416
  }
1413
1417
 
@@ -12,7 +12,7 @@ const antlr4 = require('antlr4');
12
12
 
13
13
  const { CompileMessage } = require('../base/messages');
14
14
  const errorStrategy = require('./errorStrategy');
15
- const { XsnSource } = require('../compiler/classes');
15
+ const { XsnSource } = require('../compiler/xsn-model');
16
16
 
17
17
  const Parser = require('../gen/languageParser').default;
18
18
  const Lexer = require('../gen/languageLexer').default;
@@ -14,14 +14,13 @@ const locUtils = require('../base/location');
14
14
  const { parseDocComment } = require('./docCommentParser');
15
15
  const { parseMultiLineStringLiteral } = require('./multiLineStringParser');
16
16
  const {
17
- functionsWithoutParens,
18
17
  specialFunctions,
19
18
  quotedLiteralPatterns,
20
19
  } = require('../compiler/builtins');
20
+ const { functionsWithoutParens } = require('../base/builtins');
21
+ const { Location } = require('../base/location');
21
22
  const { pathName } = require('../compiler/utils');
22
- const {
23
- XsnArtifact, XsnName, CsnLocation, XsnSource,
24
- } = require('../compiler/classes');
23
+ const { XsnArtifact, XsnName, XsnSource } = require('../compiler/xsn-model');
25
24
  const { isBetaEnabled } = require('../base/model');
26
25
  const { weakLocation } = require('../base/location');
27
26
  const { normalizeNewLine, normalizeNumberString } = require('./textUtils');
@@ -500,10 +499,10 @@ function handleDuplicateExtension( ext, name, numDefines ) {
500
499
  * Return start location of `token`, or the first token matched by the current
501
500
  * rule if `token` is undefined
502
501
  *
503
- * @returns {CsnLocation}
502
+ * @returns {Location}
504
503
  */
505
504
  function startLocation( token = this._ctx.start ) {
506
- return new CsnLocation(
505
+ return new Location(
507
506
  this.filename,
508
507
  token.line,
509
508
  token.column + 1
@@ -516,7 +515,7 @@ function startLocation( token = this._ctx.start ) {
516
515
  *
517
516
  * @param {object} token
518
517
  * @param {object} endToken
519
- * @return {CsnLocation}
518
+ * @return {Location}
520
519
  */
521
520
  function tokenLocation( token, endToken = null ) {
522
521
  if (!token)
@@ -528,7 +527,7 @@ function tokenLocation( token, endToken = null ) {
528
527
  const endLine = endToken.line;
529
528
  // after the last char (special for EOF?)
530
529
  const endCol = endToken.stop - endToken.start + endToken.column + 2;
531
- const loc = new CsnLocation( this.filename, token.line, token.column + 1, endLine, endCol );
530
+ const loc = new Location( this.filename, token.line, token.column + 1, endLine, endCol );
532
531
 
533
532
  // This check is done for performance reason. No need to access a token's
534
533
  // data if we know that it spans only one single line.
@@ -629,7 +628,7 @@ function secureParens( expr ) {
629
628
  return {
630
629
  op: { val: 'xpr', location: this.startLocation() },
631
630
  args: [ expr ],
632
- location: { __proto__: CsnLocation.prototype, ...expr.location },
631
+ location: { __proto__: Location.prototype, ...expr.location },
633
632
  $parens,
634
633
  };
635
634
  }
@@ -725,11 +724,11 @@ function fragileAlias( ast, safe = false ) {
725
724
  return ast;
726
725
  if (safe || ast.$delimited || !/^[a-zA-Z][a-zA-Z_]+$/.test( ast.id )) {
727
726
  this.warning( 'syntax-deprecated-auto-as', ast.location, { keyword: 'as' },
728
- 'Please add the keyword $(KEYWORD) in front of the alias name' );
727
+ 'Add keyword $(KEYWORD) in front of the alias name' );
729
728
  }
730
729
  else { // configurable error
731
730
  this.message( 'syntax-missing-as', ast.location, { keyword: 'as' },
732
- 'Please add the keyword $(KEYWORD) in front of the alias name' );
731
+ 'Add keyword $(KEYWORD) in front of the alias name' );
733
732
  }
734
733
  return ast;
735
734
  }
@@ -760,10 +759,16 @@ function identAst( token, category, noTokenTypeCheck = false ) {
760
759
 
761
760
  // $delimited is used to complain about ![$self] and other magic vars usage;
762
761
  // we might complain about that already here via @arg{category}
763
- return { id, $delimited: true, location: this.tokenLocation( token ) };
762
+
763
+ const ast = { id, $delimited: true, location: this.tokenLocation( token ) };
764
+ ast.location.tokenIndex = token.tokenIndex;
765
+ return ast;
766
+ }
767
+ if (token.text[0] !== '"') {
768
+ const ast = { id, location: this.tokenLocation(token) };
769
+ ast.location.tokenIndex = token.tokenIndex;
770
+ return ast;
764
771
  }
765
- if (token.text[0] !== '"')
766
- return { id, location: this.tokenLocation( token ) };
767
772
  // delimited:
768
773
  id = id.slice( 1, -1 ).replace( /""/g, '"' );
769
774
  if (!id) {
@@ -774,7 +779,9 @@ function identAst( token, category, noTokenTypeCheck = false ) {
774
779
  // eslint-disable-next-line max-len
775
780
  'Deprecated delimited identifier syntax, use $(DELIMITED) - strings are delimited by single quotes' );
776
781
  }
777
- return { id, $delimited: true, location: this.tokenLocation( token ) };
782
+ const ast = { id, $delimited: true, location: this.tokenLocation( token ) };
783
+ ast.location.tokenIndex = token.tokenIndex;
784
+ return ast;
778
785
  }
779
786
 
780
787
  function pushXprToken( args ) {
@@ -1346,7 +1353,7 @@ function argsExpression( args, nary ) {
1346
1353
  return args[0];
1347
1354
  const $parens = args[0]?.$parens;
1348
1355
  const loc = ($parens) ? $parens[$parens.length - 1] : args[0]?.location;
1349
- const location = loc ? { __proto__: CsnLocation.prototype, ...loc } : this.startLocation();
1356
+ const location = loc ? { __proto__: Location.prototype, ...loc } : this.startLocation();
1350
1357
  // console.log('AE:',args);
1351
1358
  const op = {
1352
1359
  // eslint-disable-next-line no-nested-ternary
@@ -6,7 +6,7 @@ const {
6
6
  cdlNewLineRegEx,
7
7
  } = require('./textUtils');
8
8
  const { CompilerAssertion } = require('../base/error');
9
- const { CsnLocation } = require('../compiler/classes');
9
+ const { Location } = require('../base/location');
10
10
 
11
11
  /**
12
12
  * Strips and counts the indentation from the given string.
@@ -463,7 +463,7 @@ class MultiLineStringParser {
463
463
  */
464
464
  _locationForCharacters(i, width) {
465
465
  return {
466
- __proto__: CsnLocation.prototype,
466
+ __proto__: Location.prototype,
467
467
  file: this.parser.filename,
468
468
  line: this.token.line + this._lineInString,
469
469
  endLine: this.token.line + this._lineInString,
@@ -45,7 +45,7 @@ function isWhitespaceCharacterNoNewline( char ) {
45
45
  * @return {string}
46
46
  */
47
47
  function normalizeNewLine( str ) {
48
- // Note: cdlNewLineRegEx does not have `g` flag and we can't use replaceAll in Node 14.
48
+ // Note: cdlNewLineRegEx does not have `g`.
49
49
  return str.replace(new RegExp(cdlNewLineRegEx, 'ug'), '\n');
50
50
  }
51
51
 
package/lib/main.d.ts CHANGED
@@ -150,6 +150,22 @@ declare namespace compiler {
150
150
  * @since v2.12.1
151
151
  */
152
152
  $xsnObjects?: boolean
153
+ /**
154
+ * Internal option for LSP only!
155
+ * If set, each AST gets a `tokenStream` property containing all lexed tokens.
156
+ *
157
+ * @private
158
+ */
159
+ attachTokens?: boolean
160
+ /**
161
+ * Internal option for LSP only!
162
+ * If set, enables some extra checks/work for the CDS LSP.
163
+ * May be implicitly set by `$lsp.<api>` functions.
164
+ *
165
+ * @private
166
+ * @since v4.9
167
+ */
168
+ lspMode?: boolean
153
169
  }
154
170
 
155
171
  /**
@@ -246,18 +262,48 @@ declare namespace compiler {
246
262
  * @see service
247
263
  */
248
264
  serviceNames?: string[]
265
+ /**
266
+ * If set, certain OData errors that are not relevant for OpenAPI generation
267
+ * are downgraded to warnings when generating EDM JSON.
268
+ *
269
+ * @default true
270
+ * @since v4.8.0
271
+ * @private
272
+ */
273
+ edm4OpenAPI?: boolean
249
274
  }
250
275
 
251
276
  /**
252
277
  * Options used by the `for.effective()` CSN transformation.
253
278
  *
254
- * WORK IN PROGRESS
255
- *
256
279
  * @internal
257
280
  * @see _for.effective()
258
281
  */
259
282
  export interface EffectiveCsnOptions extends SqlOptions {
260
- // TODO
283
+ /**
284
+ * If true, resolve simple type references to their simple base type.
285
+ *
286
+ * @default true
287
+ */
288
+ resolveSimpleTypes?: boolean
289
+ /**
290
+ * If true, transform projections into ordinary views with SELECT.
291
+ *
292
+ * @default true
293
+ */
294
+ resolveProjections?: boolean
295
+ /**
296
+ * If true, remap OData annotations to ABAP annotations.
297
+ *
298
+ * @default false
299
+ */
300
+ remapOdataAnnotations?: boolean
301
+ /**
302
+ * If true, keep '.localized' property in the CSN.
303
+ *
304
+ * @default false
305
+ */
306
+ keepLocalized?: boolean
261
307
  }
262
308
 
263
309
  /**
@@ -538,11 +584,6 @@ declare namespace compiler {
538
584
  * @internal
539
585
  */
540
586
  model?: CSN;
541
- /**
542
- * Used by `cdsc` to indicate whether the message was already printed to stderr.
543
- * @private
544
- */
545
- hasBeenReported: boolean;
546
587
  }
547
588
 
548
589
  /**
@@ -657,16 +698,23 @@ declare namespace compiler {
657
698
  * @param config.noMessageId
658
699
  * If true, will _not_ show the message ID (+ explanation hint) in the output.
659
700
  *
701
+ * @param config.idInBrackets
702
+ * If true, the message ID (if there is one and noMessageId is falsey) will be put in brackets.
703
+ * This will be the default in cds-compiler v5.
704
+ *
660
705
  * @param config.noHome
661
706
  * If true, will _not_ show message's semantic location.
662
707
  *
663
- * @param config.module
708
+ * @param config.moduleForMarker
664
709
  * If set, downgradable error messages will get a '‹↓›' marker, depending on whether
665
- * the message can be downgraded for the given module.
710
+ * the message can be downgraded for the given module. A `‹↑›` is used if the message
711
+ * will be an error in the next major cds-compiler release.
712
+ * Was called `module` in v4.8.0 and earlier.
666
713
  */
667
714
  export function messageString(msg: CompileMessage, config?: {
668
715
  normalizeFilename?: boolean
669
716
  noMessageId?: boolean
717
+ idInBrackets?: boolean
670
718
  noHome?: boolean
671
719
  module?: string
672
720
  }): string;
@@ -704,9 +752,11 @@ declare namespace compiler {
704
752
  * @param config.hintExplanation
705
753
  * If true, messages with explanations will get a "…" marker, see {@link hasMessageExplanation}.
706
754
  *
707
- * @param config.module
755
+ * @param config.moduleForMarker
708
756
  * If set, downgradable error messages will get a '‹↓›' marker, depending on whether
709
- * the message can be downgraded for the given module.
757
+ * the message can be downgraded for the given module. A `‹↑›` is used if the message
758
+ * will be an error in the next major cds-compiler release.
759
+ * Was called `module` in v4.8.0 and earlier.
710
760
  *
711
761
  * @param config.sourceMap
712
762
  * A dictionary of filename<->source-code entries. You can pass the fileCache that is used
@@ -733,7 +783,7 @@ declare namespace compiler {
733
783
  normalizeFilename?: boolean
734
784
  noMessageId?: boolean
735
785
  hintExplanation?: boolean
736
- module?: string
786
+ moduleForMarker?: string
737
787
  sourceMap?: Record<string, string>
738
788
  sourceLineMap?: Record<string, number[]>
739
789
  cwd?: string
@@ -848,6 +898,12 @@ declare namespace compiler {
848
898
  * @internal
849
899
  */
850
900
  function effective(csn: CSN, options?: EffectiveCsnOptions): CSN;
901
+ /**
902
+ * Transform the given CSN into one that has the properties required for SEAL
903
+ *
904
+ * @internal
905
+ */
906
+ function seal(csn: CSN, options?: EffectiveCsnOptions): CSN;
851
907
  }
852
908
 
853
909
  export { _for as for };
@@ -951,6 +1007,20 @@ declare namespace compiler {
951
1007
  */
952
1008
  const keywords: string[];
953
1009
  }
1010
+ namespace h2 {
1011
+ /**
1012
+ * Immutable list of reserved keywords for H2. The list is used by {@link to.sql}.
1013
+ * Taken from <http://www.h2database.com/html/advanced.html#keywords>.
1014
+ */
1015
+ const keywords: string[];
1016
+ }
1017
+ namespace postgres {
1018
+ /**
1019
+ * Immutable list of reserved keywords for PostgreSQL. The list is used by {@link to.sql}.
1020
+ * Taken from <https://www.postgresql.org/docs/current/sql-keywords-appendix.html>.
1021
+ */
1022
+ const keywords: string[];
1023
+ }
954
1024
 
955
1025
  /**
956
1026
  * If the given `name` requires quoting for SQL dialect `dialect`,
@@ -1246,7 +1316,13 @@ declare namespace compiler {
1246
1316
  * The functions in `userFunctions` are usually transformer functions, which
1247
1317
  * change the input CSN destructively.
1248
1318
  */
1249
- export function traverseCsn(userFunctions: Record<string, Function>, csn: object|any[]): void;
1319
+ export function traverseCsn(userFunctions: Record<string, TraverseCsnCallback>, csn: object|any[]): void;
1320
+ export type TraverseCsnCallback = (
1321
+ userFunctions: Record<string, TraverseCsnCallback>,
1322
+ value: any,
1323
+ csn: any,
1324
+ prop: string
1325
+ ) => any;
1250
1326
 
1251
1327
  /**
1252
1328
  * CSN Model related functions.
package/lib/main.js CHANGED
@@ -26,7 +26,7 @@ const parseLanguage = lazyload('./language/antlrParser');
26
26
  const compiler = lazyload('./compiler');
27
27
  const shared = lazyload('./compiler/shared');
28
28
  const define = lazyload('./compiler/define');
29
- const builtins = lazyload('./compiler/builtins');
29
+ const builtins = lazyload('./base/builtins');
30
30
  const base = lazyload('./compiler/base');
31
31
  const finalizeParseCdl = lazyload('./compiler/finalize-parse-cdl');
32
32
 
@@ -126,7 +126,9 @@ module.exports = {
126
126
  // SNAPI
127
127
  for: {
128
128
  odata: (...args) => snapi.odata(...args),
129
+ java: (...args) => snapi.java(...args),
129
130
  effective: (...args) => snapi.for_effective(...args),
131
+ seal: (...args) => snapi.for_seal(...args),
130
132
  },
131
133
  to: {
132
134
  cdl: Object.assign((...args) => snapi.cdl(...args), {
@@ -141,6 +143,12 @@ module.exports = {
141
143
  sqlite: {
142
144
  keywords: Object.freeze([ ...keywords.sqlite ] )
143
145
  },
146
+ postgres: {
147
+ keywords: Object.freeze([ ...keywords.postgres ] )
148
+ },
149
+ h2: {
150
+ keywords: Object.freeze([ ...keywords.h2 ] )
151
+ },
144
152
  smartId: (...args) => sqlIdentifier.smartId(...args),
145
153
  smartFunctionId: (...args) => sqlIdentifier.smartFuncId(...args),
146
154
  delimitedId: (...args) => sqlIdentifier.delimitedId(...args),
@@ -3,7 +3,7 @@
3
3
  const { csnPropertyOrder } = require('../json/to-csn');
4
4
  const { ModelError } = require('../base/error');
5
5
  const { setHidden } = require('../utils/objectUtils');
6
- const { isAnnotationExpression } = require('../compiler/builtins');
6
+ const { isAnnotationExpression } = require('../base/builtins');
7
7
 
8
8
  const csnDictionaries = [
9
9
  'args',
@@ -21,16 +21,22 @@ function shallowCopy( val, _options, _sort ) {
21
21
  }
22
22
 
23
23
  const internalCsnProps = {
24
+ __proto__: null,
24
25
  $sources: shallowCopy,
25
26
  $location: shallowCopy,
26
27
  $path: shallowCopy,
27
28
  $paths: shallowCopy,
28
29
  elements: cloneCsnDict,
29
30
  $tableConstraints: shallowCopy,
31
+ $default: shallowCopy, // used for HANA CSN migrations
32
+ $notNull: shallowCopy, // used for HANA CSN migrations
33
+ };
34
+ const internalEnumerableCsnProps = {
35
+ __proto__: null,
36
+ $tableConstraints: shallowCopy, // enumerable for HANA CSN for migrations
30
37
  };
31
38
  const internalCsnPropertyNames = Object.keys(internalCsnProps);
32
39
 
33
-
34
40
  /**
35
41
  * Deeply clone the given CSN model and return it.
36
42
  * In testMode (or with testSortCsn), definitions are sorted.
@@ -41,9 +47,12 @@ const internalCsnPropertyNames = Object.keys(internalCsnProps);
41
47
  * @see cloneAnnotationValue()
42
48
  * @see cloneCsnDict()
43
49
  *
44
- * @param {object} csn Top-level CSN. You can pass non-dictionary values.
45
- * @param {CSN.Options} options CSN Options, only used for `dictionaryPrototype`, `testMode`, and `testSortCsn`.
46
- * @param {boolean} sort Whether to sort CSN properties.
50
+ * @param {object} csn
51
+ * Top-level CSN. You can pass non-dictionary values.
52
+ * @param {CSN.Options} options
53
+ * CSN Options, only used for `dictionaryPrototype`, `testMode`, and `testSortCsn`.
54
+ * @param {boolean} sort
55
+ * Whether to sort CSN properties.
47
56
  */
48
57
  function cloneCsn( csn, options, sort ) {
49
58
  if (!csn || typeof csn !== 'object')
@@ -58,18 +67,21 @@ function cloneCsn( csn, options, sort ) {
58
67
  const r = {};
59
68
  for (const n of keys) {
60
69
  const val = csn[n];
61
- if (!val || typeof val !== 'object') {
62
- r[n] = val;
63
- }
64
- else if (n.charAt(0) === '@') {
70
+ if (n.charAt(0) === '@') {
65
71
  r[n] = cloneAnnotationValue(val, options, false); // TODO: pass 'sort'
66
72
  }
73
+ else if (!val || typeof val !== 'object') {
74
+ r[n] = val;
75
+ }
67
76
  else if (csnDictionaries.includes(n) && !Array.isArray(val)) {
68
77
  const sortDict = n === 'definitions' &&
69
78
  (!options || options.testMode || options.testSortCsn);
70
79
  // Array check for property `args` which may either be a dictionary or an array.
71
80
  r[n] = cloneCsnDict(val, options, sort, sortDict);
72
81
  }
82
+ else if (n in internalEnumerableCsnProps) {
83
+ r[n] = internalEnumerableCsnProps[n](val, options, sort);
84
+ }
73
85
  else {
74
86
  r[n] = cloneCsn(val, options, sort);
75
87
  }