@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
@@ -5,8 +5,8 @@
5
5
  'use strict';
6
6
 
7
7
  const { term } = require('../utils/term');
8
- const { locationString } = require('./location');
9
- const { isDeprecatedEnabled } = require('./model');
8
+ const { Location, locationString } = require('./location');
9
+ const { isDeprecatedEnabled, isBetaEnabled } = require('./model');
10
10
  const { centralMessages, centralMessageTexts, oldMessageIds } = require('./message-registry');
11
11
  const _messageIdsWithExplanation = require('../../share/messages/message-explanations.json').messages;
12
12
  const { analyseCsnPath, traverseQuery } = require('../model/csnRefs');
@@ -17,7 +17,6 @@ const { cdlNewLineRegEx } = require('../language/textUtils');
17
17
  const fs = require('fs');
18
18
  const path = require('path');
19
19
  const { inspect } = require('util')
20
- const { CsnLocation } = require('../compiler/classes');
21
20
 
22
21
  // term instance for messages
23
22
  const colorTerm = term();
@@ -74,12 +73,32 @@ function isDowngradable( messageId, moduleName, options ) {
74
73
  return false;
75
74
  if (msg.severity !== 'Error')
76
75
  return true;
76
+ // v5 messages are downgradable (except if errorFor also contains the current module).
77
+ if (msg.errorFor && msg.errorFor.includes('v5'))
78
+ return true;
77
79
  const { configurableFor } = msg;
78
80
  return (Array.isArray( configurableFor ))
79
81
  ? configurableFor.includes( moduleName )
80
82
  : configurableFor && (configurableFor !== 'deprecated' || isDeprecatedEnabled( options, 'downgradableErrors' ));
81
83
  }
82
84
 
85
+ /**
86
+ * Returns a marker for messages strings indicating whether the message can be downgraded
87
+ * or whether it will be an error in the next cds-compiler release.
88
+ *
89
+ * @returns {string}
90
+ */
91
+ function severityChangeMarker(msg, config) {
92
+ const severity = msg.severity || 'Error';
93
+ if (config.moduleForMarker) {
94
+ if (severity === 'Error' && isDowngradable(msg.messageId, config.moduleForMarker, {}))
95
+ return '‹↓›';
96
+ if (msg.messageId && centralMessages[msg.messageId]?.errorFor?.includes('v5'))
97
+ return '‹↑›';
98
+ }
99
+ return '';
100
+ }
101
+
83
102
  /**
84
103
  * Class for combined compiler errors. Additional members:
85
104
  * - `messages`: array of compiler messages (CompileMessage)
@@ -88,17 +107,16 @@ function isDowngradable( messageId, moduleName, options ) {
88
107
  class CompilationError extends Error {
89
108
  /**
90
109
  * @param {CompileMessage[]} messages
110
+ * @param {boolean} [dontSerializeMessages] If true, compiler messages are NOT part of the errors message text.
91
111
  * @param {XSN.Model} [model] the XSN model, only to be set with options.attachValidNames
92
112
  */
93
- constructor(messages, model) {
94
- // TODO(v5): Don't store stringified messages.
95
- super( `CDS compilation failed\n${messages?.map( m => m.toString() ).join('\n') || ''}` );
113
+ constructor(messages, model, dontSerializeMessages) {
114
+ const msg = !dontSerializeMessages && messages?.map( m => m.toString() ).join('\n') || '';
115
+ super( `CDS compilation failed\n${msg}` );
96
116
  /** @since v4.0.0 */
97
117
  this.code = 'ERR_CDS_COMPILATION_FAILURE';
98
118
  this.messages = [ ...messages ].sort(compareMessageSeverityAware);
99
119
 
100
- // TODO: remove this bin/cdsc.js specifics
101
- Object.defineProperty( this, 'hasBeenReported', { value: false, configurable: true, writable: true, enumerable: false } );
102
120
  // property `model` is only set with options.attachValidNames:
103
121
  Object.defineProperty( this, 'model', { value: model || undefined, configurable: true } );
104
122
  }
@@ -113,6 +131,27 @@ class CompilationError extends Error {
113
131
  return this.stack || this.message;
114
132
  }
115
133
 
134
+ /**
135
+ * Called when the exception is printed, e.g. when it is not caught.
136
+ * To give users a bit of information what went wrong, return stringified
137
+ * error messages. But only errors to avoid spamming users.
138
+ *
139
+ * Compiler consumers should catch compilation errors and properly handle
140
+ * them by printing messages themselves.
141
+ *
142
+ * @returns {string}
143
+ */
144
+ toString() {
145
+ let messages = [ 'CDS compilation failed' ];
146
+ if (this.messages) {
147
+ messages = messages.concat(this.messages
148
+ .filter(msg => msg.severity === 'Error')
149
+ .map( m => m.toString())
150
+ );
151
+ }
152
+ return messages.join('\n');
153
+ }
154
+
116
155
  /**
117
156
  * @deprecated Use `.messages` instead.
118
157
  */
@@ -140,7 +179,7 @@ class CompileMessage {
140
179
  */
141
180
  constructor(location, msg, severity = 'Error', id = null, home = null, moduleName = null) {
142
181
  this.message = msg;
143
- this.$location = { __proto__: CsnLocation.prototype, ...location, address: undefined };
182
+ this.$location = { __proto__: Location.prototype, ...location, address: undefined };
144
183
  this.validNames = null;
145
184
  this.home = home; // semantic location, e.g. 'entity:"E"/element:"x"'
146
185
  this.severity = severity;
@@ -152,8 +191,14 @@ class CompileMessage {
152
191
  // this.error = null;
153
192
  }
154
193
 
155
- toString() { // should have no argument...
156
- return messageString( this, undefined, true ); // no message-id before finalization!
194
+ toString() {
195
+ // Used by cds-dk in their own `toString` wrapper.
196
+ return messageString( this, {
197
+ normalizeFilename: false,
198
+ noMessageId: true, // no message-id before finalization!
199
+ noHome: false,
200
+ module: null,
201
+ });
157
202
  }
158
203
  }
159
204
 
@@ -183,18 +228,28 @@ const severitySpecs = {
183
228
  */
184
229
  function reclassifiedSeverity( msg, options, moduleName ) {
185
230
  const spec = centralMessages[msg.messageId] || { severity: msg.severity, configurableFor: null, errorFor: null };
231
+ let severity = spec.severity;
232
+
186
233
  if (spec.severity === 'Error') {
187
234
  if (!isDowngradable(msg.messageId, moduleName, options))
188
235
  return 'Error';
189
236
  }
190
237
  else {
191
238
  const { errorFor } = spec;
192
- if (Array.isArray( errorFor ) && errorFor.includes( moduleName ))
193
- return 'Error';
239
+ if (Array.isArray( errorFor )) {
240
+ if (errorFor.includes(moduleName))
241
+ return 'Error';
242
+
243
+ if (errorFor.includes('v5') && isBetaEnabled(options, 'v5preview')) {
244
+ severity = 'Error';
245
+ if (!isDowngradable(msg.messageId, moduleName, options))
246
+ return severity;
247
+ }
248
+ }
194
249
  }
195
250
 
196
251
  if (!options.severities)
197
- return spec.severity;
252
+ return severity;
198
253
 
199
254
  let newSeverity = options.severities[msg.messageId];
200
255
  // The user could have specified a severity through an old message ID.
@@ -202,7 +257,7 @@ function reclassifiedSeverity( msg, options, moduleName ) {
202
257
  const oldName = spec.oldNames.find((name => options.severities[name]));
203
258
  newSeverity = options.severities[oldName];
204
259
  }
205
- return normalizedSeverity( newSeverity ) || spec.severity;
260
+ return normalizedSeverity( newSeverity ) || severity;
206
261
  }
207
262
 
208
263
  function normalizedSeverity( severity ) {
@@ -333,6 +388,7 @@ function makeMessageFunction( model, options, moduleName = null ) {
333
388
  callTransparently,
334
389
  moduleName,
335
390
  setModel,
391
+ setOptions,
336
392
  };
337
393
 
338
394
  function _message( id, location, textOrArguments, severity, texts = null ) {
@@ -352,7 +408,7 @@ function makeMessageFunction( model, options, moduleName = null ) {
352
408
  if (options.internalMsg)
353
409
  msg.error = new Error( 'stack' );
354
410
  if (definition)
355
- msg.$location.address = { definition };
411
+ msg.$location.address = { definition }; // TODO: remove
356
412
 
357
413
  if (id) {
358
414
  if (options.testMode && !options.$recompile)
@@ -406,6 +462,7 @@ function makeMessageFunction( model, options, moduleName = null ) {
406
462
  /**
407
463
  * Normalize the given location. Location may be a CSN path, XSN/CSN location or an
408
464
  * array of the form `[CSN.Location, XSN user, suffix]`.
465
+ * TODO: normalize to [ Location, SemanticLocation ]
409
466
  *
410
467
  * @param {any} location
411
468
  * @returns {[CSN.Location, string, string]} Location, semantic location and definition.
@@ -428,6 +485,9 @@ function makeMessageFunction( model, options, moduleName = null ) {
428
485
  ];
429
486
  }
430
487
 
488
+ if (location[1]?.mainKind)
489
+ return [ location[0], location[1].toString(), null ];
490
+
431
491
  let semanticLocation = location[1] ? homeName( location[1], false ) : null;
432
492
  if (location[2]) { // optional suffix, e.g. annotation
433
493
  semanticLocation += `/${ (typeof location[2] === 'string') ? location[2]: homeName(location[2]) }`;
@@ -494,8 +554,10 @@ function makeMessageFunction( model, options, moduleName = null ) {
494
554
  }
495
555
 
496
556
  function throwWithError() {
497
- if (hasNewError)
498
- throw new CompilationError( messages, options.attachValidNames && model );
557
+ if (hasNewError) {
558
+ const dontSerializeMessages = isBetaEnabled(options, 'v5preview');
559
+ throw new CompilationError(messages, options.attachValidNames && model, dontSerializeMessages);
560
+ }
499
561
  }
500
562
 
501
563
  /**
@@ -510,8 +572,10 @@ function makeMessageFunction( model, options, moduleName = null ) {
510
572
  if (!messages || !messages.length)
511
573
  return;
512
574
  const hasError = options.testMode ? hasNonDowngradableErrors : hasErrors;
513
- if (hasError( messages, moduleName, options ))
514
- throw new CompilationError( messages, options.attachValidNames && model );
575
+ if (hasError( messages, moduleName, options )) {
576
+ const dontSerializeMessages = isBetaEnabled(options, 'v5preview');
577
+ throw new CompilationError(messages, options.attachValidNames && model, dontSerializeMessages);
578
+ }
515
579
  }
516
580
 
517
581
  /**
@@ -561,6 +625,18 @@ function makeMessageFunction( model, options, moduleName = null ) {
561
625
  function setModel( _model ) {
562
626
  model = _model;
563
627
  }
628
+
629
+ /**
630
+ * Change the options used to determine message severities.
631
+ * This is necessary if you change `options.severities`, as otherwise they may not be picked up.
632
+ *
633
+ * @param {CSN.Model} _model
634
+ */
635
+ function setOptions( _options ) {
636
+ options = _options;
637
+ }
638
+
639
+
564
640
  }
565
641
 
566
642
  /**
@@ -942,12 +1018,17 @@ function replaceInString( text, params ) {
942
1018
  * @param {boolean} [config.noMessageId]
943
1019
  * If true, will _not_ show the message ID (+ explanation hint) in the output.
944
1020
  *
1021
+ * @param {boolean} [config.idInBrackets]
1022
+ * If true, the message ID (if there is one and noMessageId is falsey) will be put in brackets.
1023
+ * This will be the default in cds-compiler v5.
1024
+ *
945
1025
  * @param {boolean} [config.noHome]
946
1026
  * If true, will _not_ show message's semantic location.
947
1027
  *
948
- * @param {string} [config.module]
1028
+ * @param {string} [config.moduleForMarker]
949
1029
  * If set, downgradable error messages will get a '‹↓›' marker, depending on whether
950
- * the message can be downgraded for the given module.
1030
+ * the message can be downgraded for the given module. A `‹↑›` is used if the message
1031
+ * will be an error in the next major cds-compiler release.
951
1032
  *
952
1033
  * @returns {string}
953
1034
  */
@@ -958,19 +1039,22 @@ function messageString( err, config ) {
958
1039
  normalizeFilename: arguments[1],
959
1040
  noMessageId: arguments[2],
960
1041
  noHome: arguments[3],
961
- module: arguments[4],
1042
+ moduleForMarker: arguments[4],
962
1043
  };
963
1044
  }
1045
+ config.moduleForMarker ??= config.module; // v4.8.0 or earlier compatibility
964
1046
 
965
1047
  const location = (err.$location?.file ? `${ locationString( err.$location, config.normalizeFilename ) }: ` : '');
966
1048
  const severity = err.severity || 'Error';
967
- const downgradable = severity === 'Error' && config.module &&
968
- isDowngradable(err.messageId, config.module, {}) ? '‹↓›' : '';
1049
+ const downgradable = severityChangeMarker(err, config);
969
1050
  // even with noHome, print err.home if the location is weak
970
1051
  const home = !err.home || config.noHome && err.$location?.endLine ? '' : ` (in ${ err.home })`;
971
- // TODO: the plan was with brackets = `Error[ref-undefined-def]`
972
- const id = err.messageId && !config.noMessageId ? ` ${ err.messageId }` : '';
973
- return `${ location }${ severity }${ downgradable }${ id }: ${ err.message }${ home }`;
1052
+
1053
+ let msgId = ''; // TODO(v5): Use brackets only
1054
+ if (err.messageId && !config.noMessageId)
1055
+ msgId = (config.idInBrackets) ? `[${err.messageId}]` : ` ${err.messageId}`;
1056
+
1057
+ return `${ location }${ severity }${ downgradable }${ msgId }: ${ err.message }${ home }`;
974
1058
  }
975
1059
 
976
1060
  /**
@@ -1010,9 +1094,10 @@ function messageHash( msg ) {
1010
1094
  * @param {boolean} [config.hintExplanation]
1011
1095
  * If true, messages with explanations will get a "…" marker.
1012
1096
  *
1013
- * @param {string} [config.module]
1097
+ * @param {string} [config.moduleForMarker]
1014
1098
  * If set, downgradable error messages will get a '‹↓›' marker, depending on whether
1015
- * the message can be downgraded for the given module.
1099
+ * the message can be downgraded for the given module. A `‹↑›` is used if the message
1100
+ * will be an error in the next major cds-compiler release.
1016
1101
  *
1017
1102
  * @param {Record<string, string>} [config.sourceMap]
1018
1103
  * A dictionary of filename<->source-code entries. You can pass the `fileCache` that is used
@@ -1040,12 +1125,13 @@ function messageHash( msg ) {
1040
1125
  function messageStringMultiline( err, config = {} ) {
1041
1126
  colorTerm.changeColorMode(config ? config.color : 'auto');
1042
1127
 
1128
+ config.moduleForMarker ??= config.module; // v4.8.0 or earlier compatibility
1129
+
1043
1130
  const explainHelp = (config.hintExplanation && hasMessageExplanation(err.messageId)) ? '…' : '';
1044
1131
  const home = !err.home ? '' : (`at ${ err.home }`);
1045
1132
  const severity = err.severity || 'Error';
1046
- const downgradable = config.module && severity === 'Error' &&
1047
- isDowngradable(err.messageId, config.module, {}) ? '‹↓›' : '';
1048
- const msgId = (err.messageId && !config.noMessageId) ? `[${ err.messageId }${downgradable}${ explainHelp }]` : '';
1133
+ const downgradable = severityChangeMarker(err, config);
1134
+ const msgId = (err.messageId && !config.noMessageId) ? `${downgradable}[${ err.messageId }${ explainHelp }]` : '';
1049
1135
 
1050
1136
  let location = '';
1051
1137
  let context = '';
@@ -1535,7 +1621,7 @@ function constructSemanticLocationFromCsnPath( model, options, csnPath ) {
1535
1621
  if (!currentThing)
1536
1622
  return result;
1537
1623
 
1538
- let selectDepth = (csnPath[0] !== 'extensions') ? queryDepthForMessage(csnPath, model, currentThing) : null;
1624
+ const selectDepth = (csnPath[0] !== 'extensions') ? queryDepthForMessage(csnPath, model, currentThing) : null;
1539
1625
 
1540
1626
  // Artifact ref -------------------------------------
1541
1627
 
@@ -1704,7 +1790,7 @@ function constructSemanticLocationFromCsnPath( model, options, csnPath ) {
1704
1790
  if (index >= csnPath.length)
1705
1791
  continue; // no column name
1706
1792
 
1707
- let elementHierarchy = [];
1793
+ const elementHierarchy = [];
1708
1794
 
1709
1795
  // Concat column+expand/inline to get a name similar to elements.
1710
1796
  do {
package/lib/base/model.js CHANGED
@@ -26,10 +26,6 @@ const queryOps = {
26
26
  */
27
27
  const availableBetaFlags = {
28
28
  // enabled by --beta-mode
29
- annotationExpressions: true,
30
- odataPathsInAnnotationExpressions: true,
31
- odataAnnotationExpressions: true,
32
- assocsWithParams: true, // beta, because runtimes don't support it, yet.
33
29
  hanaAssocRealCardinality: true,
34
30
  mapAssocToJoinCardinality: true, // only SAP HANA HEX engine supports it
35
31
  enableUniversalCsn: true,
@@ -39,10 +35,11 @@ const availableBetaFlags = {
39
35
  effectiveCsn: true,
40
36
  tenantVariable: true,
41
37
  calcAssoc: true,
42
- vectorType: true,
43
38
  v5preview: true,
39
+ temporalRawProjection: true,
44
40
  // disabled by --beta-mode
45
41
  nestedServices: false,
42
+ rewriteAnnotationExpressionsViaType: false,
46
43
  };
47
44
 
48
45
  // Used by isDeprecatedEnabled() to check if any flag ist set.
@@ -83,7 +80,7 @@ const oldDeprecatedFlags_v2 = [
83
80
  *
84
81
  * A feature always needs to be provided - otherwise false will be returned.
85
82
  *
86
- * Please do not move this function to the "option processor" code.
83
+ * Do not move this function to the "option processor" code.
87
84
  *
88
85
  * @param {object} options Options
89
86
  * @param {string} feature Feature to check for
@@ -103,7 +100,7 @@ function isBetaEnabled( options, feature ) {
103
100
  * Useful for newer functionality which might not work with some
104
101
  * deprecated feature turned on.
105
102
  *
106
- * Please do not move this function to the "option processor" code.
103
+ * Do not move this function to the "option processor" code.
107
104
  *
108
105
  * @param {object} options Options
109
106
  * @param {string|null} [feature] Feature to check for
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { isBuiltinType } = require('../model/csnUtils');
3
+ const { isBuiltinType } = require('../base/builtins');
4
4
  const { isBetaEnabled } = require('../base/model');
5
5
 
6
6
  // Only to be used with validator.js - a correct this value needs to be provided!
@@ -53,8 +53,8 @@ function checkActionOrFunction( art, artName, prop, path ) {
53
53
  Object.entries(params).forEach(([ pn, p ], i) => {
54
54
  const type = p.items?.type || p.type;
55
55
  if (type === '$self' && !this.csn.definitions.$self && i > 0) {
56
- this.error(null, currPath.concat(pn),
57
- 'Binding parameter is expected to appear on first position only');
56
+ this.error('def-invalid-param', currPath.concat(pn),
57
+ 'Binding parameter is expected to appear in first position only');
58
58
  }
59
59
  });
60
60
  }
@@ -37,6 +37,7 @@ function checkCoreMediaTypeAllowance( member ) {
37
37
  function checkAnalytics( member ) {
38
38
  if (member['@Analytics.Measure'] && !member['@Aggregation.default']) {
39
39
  this.info(null, member.$path, {},
40
+ // eslint-disable-next-line cds-compiler/message-no-quotes
40
41
  'Annotation “@Analytics.Measure” expects “@Aggregation.default” to be assigned for the same element as well');
41
42
  }
42
43
  }
@@ -63,6 +64,7 @@ function checkReadOnlyAndInsertOnly( artifact, artifactName ) {
63
64
  if (!this.csnUtils.getServiceName(artifactName))
64
65
  return;
65
66
  if (artifact.kind === 'entity' && artifact['@readonly'] && artifact['@insertonly'])
67
+ // eslint-disable-next-line cds-compiler/message-no-quotes
66
68
  this.warning(null, artifact.$path, {}, 'Annotations “@readonly” and “@insertonly” can\'t be assigned in combination');
67
69
  }
68
70
 
@@ -93,6 +95,7 @@ function checkTemporalAnnotationsAssignment( artifact, artifactName ) {
93
95
 
94
96
  // if @cds.valid.key is defined, check whether @cds.valid.from and @cds.valid.to are also there
95
97
  if (valid.key.length && !(valid.from.length && valid.to.length))
98
+ // eslint-disable-next-line cds-compiler/message-no-quotes
96
99
  this.error(null, [ 'definitions', artifactName ], 'Annotation “@cds.valid.key” was used but “@cds.valid.from” and “@cds.valid.to” are missing');
97
100
 
98
101
  /**
@@ -23,6 +23,7 @@ function validateDefaultValues( member, memberName, prop, path ) {
23
23
  // TODO: This check only counts the number of leading signs, not inbetween (e.g. 1 - - 1).
24
24
  // The message also needs to be improved.
25
25
  if (i > 1)
26
+ // eslint-disable-next-line cds-compiler/message-no-quotes
26
27
  this.error(null, path, {}, 'Illegal number of unary ‘+’/‘-’ operators');
27
28
  }
28
29
  }
@@ -37,8 +38,10 @@ function validateDefaultValues( member, memberName, prop, path ) {
37
38
  * @param {CSN.Path} path Path to the member
38
39
  */
39
40
  function rejectParamDefaultsInHanaCds( member, memberName, prop, path ) {
40
- if (member.default && prop === 'params' && this.options.transformation === 'hdbcds')
41
- this.error(null, path, {}, 'Parameter default values are not supported in SAP HANA CDS');
41
+ if (member.default && prop === 'params' && this.options.transformation === 'hdbcds') {
42
+ this.error('def-unsupported-param', path, {},
43
+ 'Parameter default values are not supported in SAP HANA CDS');
44
+ }
42
45
  }
43
46
 
44
47
  /**
@@ -1,8 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  const {
4
- forEachMember, forEachMemberRecursively, isBuiltinType, cardinality2str,
4
+ forEachMember, forEachMemberRecursively, cardinality2str,
5
5
  } = require('../model/csnUtils');
6
+ const { isBuiltinType } = require('../base/builtins');
6
7
  const { isGeoTypeName } = require('../compiler/builtins');
7
8
  const { setProp } = require('../base/model');
8
9
  // Only to be used with validator.js - a correct `this` value needs to be provided!
@@ -6,7 +6,7 @@
6
6
 
7
7
  const { csnRefs } = require('../model/csnRefs');
8
8
  const { setProp } = require('../base/model');
9
- const { xprInAnnoProperties } = require('../compiler/builtins');
9
+ const { isAnnotationExpression } = require('../base/builtins');
10
10
 
11
11
  /**
12
12
  * The following properties are attached as non-enumerable where appropriate:
@@ -96,7 +96,7 @@ function enrichCsn( csn, options ) {
96
96
  */
97
97
  function annotation( _parent, _prop, node ) {
98
98
  if (options.enrichAnnotations) {
99
- if (node?.['='] !== undefined && xprInAnnoProperties.some(xProp => node[xProp] !== undefined)) {
99
+ if (isAnnotationExpression(node)) {
100
100
  standard(_parent, _prop, node);
101
101
  }
102
102
  else if (node && typeof node === 'object') {
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
- const { hasAnnotationValue, isPersistedOnDatabase, isBuiltinType } = require('../model/csnUtils');
3
+ const { hasAnnotationValue, isPersistedOnDatabase } = require('../model/csnUtils');
4
+ const { isBuiltinType } = require('../base/builtins');
4
5
  const { requireForeignKeyAccess } = require('./onConditions');
5
6
  const { pathId } = require('../model/csnRefs');
6
7
 
@@ -166,12 +167,13 @@ function _checkRef( ref, _links, $path, inColumns ) {
166
167
  const cdsPersistenceSkipped = hasAnnotationValue(targetArt, '@cds.persistence.skip');
167
168
  this.error( null, $path, {
168
169
  '#': cdsPersistenceSkipped ? 'std' : 'abstract',
170
+ anno: '@cds.persistence.skip',
169
171
  id: nonPersistedTarget.pathStep,
170
172
  elemref: { ref },
171
173
  name: nonPersistedTarget.name,
172
174
  }, {
173
- std: 'Unexpected “@cds.persistence.skip” annotation on association target $(NAME) of $(ID) in path $(ELEMREF)',
174
- abstract: 'Unexpected abstract association target $(NAME) of $(ID) in path $(ELEMREF)',
175
+ std: 'Unexpected $(ANNO) annotation on association target $(NAME) of $(ID) in path $(ELEMREF)',
176
+ abstract: 'Unexpected abstract association target $(NAME) of $(ID) in path $(ELEMREF)',
175
177
  } );
176
178
  break; // only one error per path
177
179
  }
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { isBuiltinType } = require('../model/csnUtils');
3
+ const { isBuiltinType } = require('../base/builtins');
4
4
  const { RelationalOperators } = require('../transform/transformUtils');
5
5
  /**
6
6
  * Prepare the ref steps so that they are loggable
@@ -3,7 +3,7 @@
3
3
  const {
4
4
  forEachDefinition, forEachMemberRecursively, forAllQueries,
5
5
  forEachMember, getNormalizedQuery, hasAnnotationValue,
6
- applyTransformations, functionList,
6
+ applyTransformations, functionList, mergeTransformers,
7
7
  } = require('../model/csnUtils');
8
8
  const enrichCsn = require('./enricher');
9
9
 
@@ -75,7 +75,7 @@ const forRelationalDBArtifactValidators = [
75
75
  // sql.prepend/append
76
76
  checkSqlAnnotationOnArtifact,
77
77
  // strip down CSN to reduce it's size by removing non-sql relevant parts
78
- stripNonDbRelevant,
78
+ deleteBoundActions,
79
79
  ];
80
80
 
81
81
  const forRelationalDBCsnValidators = [
@@ -156,7 +156,7 @@ function _validate( csn, that,
156
156
  // TODO: Don't know if that's feasible? Do we really need to enrich annotations always?
157
157
  // const { cleanup } = enrich(csn, { processAnnotations: that.options.tranformation === 'odata' });
158
158
 
159
- applyTransformations(csn, mergeCsnValidators(csnValidators, that), [], { drillRef: true });
159
+ applyTransformations(csn, mergeTransformers(csnValidators, that), [], { drillRef: true });
160
160
 
161
161
  forEachDefinition(csn, (artifact, artifactName, prop, path) => {
162
162
  artifactValidators.forEach((artifactValidator) => {
@@ -180,38 +180,6 @@ function _validate( csn, that,
180
180
  return cleanup;
181
181
  }
182
182
 
183
- /**
184
- * Ensure the CSN validators adhere to the applyTransformation format - also, supply correct this value for each subfunction
185
- *
186
- * @param {object[]} csnValidators Validators
187
- * @param {object} that Value for this
188
- * @returns {object} Remapped validators.
189
- */
190
- function mergeCsnValidators( csnValidators, that ) {
191
- const remapped = {};
192
- for (const validator of csnValidators) {
193
- for (const [ n, fns ] of Object.entries(validator)) {
194
- if (!remapped[n])
195
- remapped[n] = [];
196
-
197
- if (Array.isArray(fns)) {
198
- remapped[n].push((parent, name, prop, path) => fns.forEach(
199
- fn => fn.bind(that)(parent, name, prop, path)
200
- ));
201
- }
202
- else {
203
- remapped[n].push((parent, name, prop, path) => fns.bind(that)(parent, name, prop, path));
204
- }
205
- }
206
- }
207
-
208
- for (const [ n, fns ] of Object.entries(remapped))
209
- remapped[n] = (parent, name, prop, path) => fns.forEach(fn => fn.bind(that)(parent, name, prop, path));
210
-
211
-
212
- return remapped;
213
- }
214
-
215
183
  /**
216
184
  * Depending on the dialect we need to run different validations.
217
185
  *
@@ -282,33 +250,17 @@ function forOdata( csn, that ) {
282
250
  });
283
251
  }
284
252
 
285
- const dbRelevantKinds = {
286
- entity: true,
287
- type: true,
288
- aspect: true,
289
- service: true,
290
- context: true,
291
- };
292
-
293
253
  /**
294
254
  * Shrink the CSN by
295
255
  * - deleting bound actions
296
- * - turning all non-entity/type/aspect/service/context entities into dummies
256
+ *
257
+ * Artifacts can only be shrunk later, when types are resolved
297
258
  *
298
259
  * @param {CSN.Artifact} artifact
299
- * @param {string} artifactName
300
260
  */
301
- function stripNonDbRelevant( artifact, artifactName ) {
302
- if (this.options.transformation !== 'effective') {
303
- if ( !dbRelevantKinds[artifact.kind] ) {
304
- this.csn.definitions[artifactName] = {
305
- kind: 'action',
306
- };
307
- }
308
- else if (artifact.actions) {
309
- delete artifact.actions;
310
- }
311
- }
261
+ function deleteBoundActions( artifact ) {
262
+ if (this.options.transformation !== 'effective')
263
+ delete artifact.actions;
312
264
  }
313
265
 
314
266
  module.exports = { forRelationalDB, forOdata };