@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.
- package/CHANGELOG.md +63 -3
- package/bin/cds_remove_invalid_whitespace.js +135 -0
- package/bin/cds_update_annotations.js +180 -0
- package/bin/cds_update_identifiers.js +3 -4
- package/bin/cdsc.js +28 -1
- package/bin/cdshi.js +13 -3
- package/doc/CHANGELOG_BETA.md +24 -1
- package/lib/api/main.js +119 -46
- package/lib/api/options.js +51 -0
- package/lib/api/validate.js +1 -5
- package/lib/base/builtins.js +116 -0
- package/lib/base/keywords.js +5 -1
- package/lib/base/location.js +91 -14
- package/lib/base/message-registry.js +76 -46
- package/lib/base/messages.js +121 -35
- package/lib/base/model.js +4 -7
- package/lib/checks/actionsFunctions.js +3 -3
- package/lib/checks/annotationsOData.js +3 -0
- package/lib/checks/defaultValues.js +5 -2
- package/lib/checks/elements.js +2 -1
- package/lib/checks/enricher.js +2 -2
- package/lib/checks/queryNoDbArtifacts.js +5 -3
- package/lib/checks/utils.js +1 -1
- package/lib/checks/validator.js +8 -56
- package/lib/compiler/assert-consistency.js +11 -7
- package/lib/compiler/builtins.js +0 -74
- package/lib/compiler/checks.js +105 -29
- package/lib/compiler/define.js +37 -25
- package/lib/compiler/extend.js +35 -12
- package/lib/compiler/index.js +9 -10
- package/lib/compiler/lsp-api.js +5 -0
- package/lib/compiler/populate.js +13 -5
- package/lib/compiler/propagator.js +24 -18
- package/lib/compiler/resolve.js +47 -45
- package/lib/compiler/shared.js +61 -21
- package/lib/compiler/tweak-assocs.js +15 -90
- package/lib/compiler/utils.js +3 -3
- package/lib/compiler/xpr-rewrite.js +689 -0
- package/lib/compiler/{classes.js → xsn-model.js} +0 -16
- package/lib/edm/annotations/edmJson.js +7 -5
- package/lib/edm/annotations/genericTranslation.js +149 -71
- package/lib/edm/csn2edm.js +25 -9
- package/lib/edm/edm.js +7 -7
- package/lib/edm/edmInboundChecks.js +57 -5
- package/lib/edm/edmPreprocessor.js +54 -25
- package/lib/edm/edmUtils.js +3 -16
- package/lib/gen/Dictionary.json +138 -14
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +2085 -1989
- package/lib/json/csnVersion.js +7 -4
- package/lib/json/from-csn.js +21 -11
- package/lib/json/to-csn.js +8 -4
- package/lib/language/antlrParser.js +1 -1
- package/lib/language/genericAntlrParser.js +23 -16
- package/lib/language/multiLineStringParser.js +2 -2
- package/lib/language/textUtils.js +1 -1
- package/lib/main.d.ts +90 -14
- package/lib/main.js +9 -1
- package/lib/model/cloneCsn.js +21 -9
- package/lib/model/csnRefs.js +153 -42
- package/lib/model/csnUtils.js +14 -11
- package/lib/model/enrichCsn.js +4 -2
- package/lib/model/revealInternalProperties.js +2 -1
- package/lib/model/sortViews.js +14 -6
- package/lib/modelCompare/compare.js +135 -122
- package/lib/optionProcessor.js +49 -2
- package/lib/render/DuplicateChecker.js +6 -6
- package/lib/render/manageConstraints.js +1 -0
- package/lib/render/toCdl.js +6 -3
- package/lib/render/toHdbcds.js +4 -48
- package/lib/render/toSql.js +6 -3
- package/lib/transform/addTenantFields.js +58 -35
- package/lib/transform/db/applyTransformations.js +34 -1
- package/lib/transform/db/constraints.js +1 -1
- package/lib/transform/db/expansion.js +11 -3
- package/lib/transform/db/flattening.js +71 -46
- package/lib/transform/db/groupByOrderBy.js +2 -2
- package/lib/transform/db/temporal.js +6 -3
- package/lib/transform/db/transformExists.js +2 -2
- package/lib/transform/db/views.js +1 -4
- package/lib/transform/effective/annotations.js +194 -0
- package/lib/transform/effective/main.js +11 -10
- package/lib/transform/effective/misc.js +45 -14
- package/lib/transform/effective/types.js +4 -3
- package/lib/transform/forOdata.js +29 -12
- package/lib/transform/forRelationalDB.js +104 -113
- package/lib/transform/localized.js +7 -6
- package/lib/transform/odata/flattening.js +228 -107
- package/lib/transform/odata/toFinalBaseType.js +10 -26
- package/lib/transform/odata/typesExposure.js +41 -25
- package/lib/transform/parseExpr.js +4 -7
- package/lib/transform/transformUtils.js +50 -43
- package/lib/transform/translateAssocsToJoins.js +48 -48
- package/lib/transform/universalCsn/coreComputed.js +2 -1
- package/lib/transform/universalCsn/universalCsnEnricher.js +12 -16
- package/package.json +2 -2
- package/share/messages/README.md +4 -0
- package/share/messages/anno-duplicate-unrelated-layer.md +1 -1
- package/share/messages/anno-missing-rewrite.md +45 -0
- package/share/messages/check-proper-type-of.md +1 -1
- package/share/messages/def-duplicate-autoexposed.md +1 -1
- package/share/messages/extend-repeated-intralayer.md +3 -16
- package/share/messages/extend-unrelated-layer.md +1 -1
- package/share/messages/message-explanations.json +2 -0
- package/share/messages/redirected-to-ambiguous.md +1 -1
- package/share/messages/redirected-to-complex.md +1 -1
- package/share/messages/redirected-to-unrelated.md +1 -1
- package/share/messages/rewrite-not-supported.md +1 -1
- package/share/messages/syntax-expecting-unsigned-int.md +2 -2
- package/share/messages/type-missing-enum-value.md +59 -0
- package/share/messages/wildcard-excluding-one.md +1 -1
- package/bin/.eslintrc.json +0 -17
- package/lib/api/.eslintrc.json +0 -37
- package/lib/checks/.eslintrc.json +0 -31
- package/lib/compiler/.eslintrc.json +0 -8
- package/lib/edm/.eslintrc.json +0 -46
- package/lib/inspect/.eslintrc.json +0 -4
- package/lib/json/.eslintrc.json +0 -4
- package/lib/language/.eslintrc.json +0 -4
- package/lib/model/.eslintrc.json +0 -13
- package/lib/modelCompare/utils/.eslintrc.json +0 -22
- package/lib/render/.eslintrc.json +0 -22
- package/lib/transform/.eslintrc.json +0 -13
- package/lib/transform/db/.eslintrc.json +0 -41
- package/lib/transform/draft/.eslintrc.json +0 -4
- package/lib/transform/effective/.eslintrc.json +0 -4
- package/lib/transform/universalCsn/.eslintrc.json +0 -37
- package/lib/utils/.eslintrc.json +0 -7
package/lib/base/messages.js
CHANGED
|
@@ -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
|
-
|
|
95
|
-
super( `CDS compilation failed\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__:
|
|
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() {
|
|
156
|
-
|
|
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 )
|
|
193
|
-
|
|
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
|
|
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 ) ||
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
972
|
-
|
|
973
|
-
|
|
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.
|
|
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
|
|
1047
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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('../
|
|
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(
|
|
57
|
-
'Binding parameter is expected to appear
|
|
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(
|
|
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
|
/**
|
package/lib/checks/elements.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
|
-
forEachMember, forEachMemberRecursively,
|
|
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!
|
package/lib/checks/enricher.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
const { csnRefs } = require('../model/csnRefs');
|
|
8
8
|
const { setProp } = require('../base/model');
|
|
9
|
-
const {
|
|
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 (
|
|
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
|
|
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
|
|
174
|
-
abstract: 'Unexpected
|
|
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
|
}
|
package/lib/checks/utils.js
CHANGED
package/lib/checks/validator.js
CHANGED
|
@@ -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
|
-
|
|
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,
|
|
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
|
-
*
|
|
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
|
|
302
|
-
if (this.options.transformation !== 'effective')
|
|
303
|
-
|
|
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 };
|