@sap/cds-compiler 4.8.0 → 4.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -4
- 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 +30 -17
- package/doc/CHANGELOG_BETA.md +19 -0
- package/lib/api/main.js +59 -24
- package/lib/api/options.js +12 -1
- package/lib/api/validate.js +1 -5
- package/lib/base/builtins.js +27 -0
- package/lib/base/message-registry.js +38 -21
- package/lib/base/messages.js +51 -20
- package/lib/base/model.js +4 -5
- package/lib/checks/actionsFunctions.js +2 -2
- package/lib/checks/annotationsOData.js +3 -0
- package/lib/checks/defaultValues.js +5 -2
- package/lib/checks/queryNoDbArtifacts.js +3 -2
- package/lib/checks/validator.js +2 -34
- package/lib/compiler/assert-consistency.js +10 -3
- package/lib/compiler/checks.js +44 -18
- package/lib/compiler/define.js +38 -30
- package/lib/compiler/extend.js +33 -10
- package/lib/compiler/index.js +0 -1
- package/lib/compiler/lsp-api.js +5 -0
- package/lib/compiler/populate.js +0 -2
- package/lib/compiler/propagator.js +23 -19
- package/lib/compiler/resolve.js +48 -29
- package/lib/compiler/shared.js +60 -20
- package/lib/compiler/tweak-assocs.js +72 -116
- package/lib/compiler/xpr-rewrite.js +762 -0
- package/lib/edm/annotations/edmJson.js +24 -7
- package/lib/edm/annotations/genericTranslation.js +81 -61
- package/lib/edm/edm.js +4 -4
- package/lib/edm/edmInboundChecks.js +33 -0
- package/lib/edm/edmPreprocessor.js +9 -6
- package/lib/gen/Dictionary.json +129 -14
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +1523 -1518
- package/lib/json/from-csn.js +13 -4
- package/lib/json/to-csn.js +12 -12
- package/lib/language/genericAntlrParser.js +14 -6
- package/lib/main.d.ts +67 -14
- package/lib/main.js +1 -0
- package/lib/model/cloneCsn.js +6 -3
- package/lib/model/csnRefs.js +23 -11
- package/lib/model/csnUtils.js +13 -7
- package/lib/model/enrichCsn.js +3 -1
- package/lib/model/revealInternalProperties.js +2 -1
- package/lib/model/sortViews.js +14 -6
- package/lib/modelCompare/compare.js +33 -34
- package/lib/optionProcessor.js +27 -2
- package/lib/render/DuplicateChecker.js +6 -6
- package/lib/render/manageConstraints.js +1 -0
- package/lib/render/toCdl.js +3 -1
- package/lib/transform/db/applyTransformations.js +33 -0
- package/lib/transform/db/constraints.js +75 -28
- package/lib/transform/db/expansion.js +8 -3
- package/lib/transform/db/flattening.js +2 -2
- 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/effective/annotations.js +194 -0
- package/lib/transform/effective/main.js +6 -8
- package/lib/transform/effective/misc.js +31 -10
- package/lib/transform/forOdata.js +23 -7
- package/lib/transform/forRelationalDB.js +3 -3
- package/lib/transform/localized.js +7 -6
- package/lib/transform/odata/flattening.js +221 -124
- package/lib/transform/odata/toFinalBaseType.js +1 -1
- package/lib/transform/odata/typesExposure.js +15 -12
- package/lib/transform/parseExpr.js +4 -4
- package/lib/transform/transformUtils.js +47 -42
- package/lib/transform/translateAssocsToJoins.js +47 -47
- package/lib/transform/universalCsn/universalCsnEnricher.js +16 -19
- package/package.json +1 -1
- package/share/messages/anno-missing-rewrite.md +45 -0
- package/share/messages/message-explanations.json +1 -0
- 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/api/main.js
CHANGED
|
@@ -26,10 +26,7 @@ const baseError = lazyload('../base/error');
|
|
|
26
26
|
const csnToEdm = lazyload('../edm/csn2edm');
|
|
27
27
|
const trace = lazyload('./trace');
|
|
28
28
|
const cloneCsn = lazyload('../model/cloneCsn');
|
|
29
|
-
|
|
30
|
-
const { forEach, forEachKey } = require('../utils/objectUtils');
|
|
31
|
-
const { makeMessageFunction } = require('../base/messages');
|
|
32
|
-
const { sortCsnForTests } = require('../model/cloneCsn');
|
|
29
|
+
const objectUtils = lazyload('../utils/objectUtils');
|
|
33
30
|
|
|
34
31
|
/**
|
|
35
32
|
* Return the artifact name for use for the hdbresult object
|
|
@@ -59,18 +56,18 @@ const warnAboutMismatchOdata = [ 'odataVersion' ];
|
|
|
59
56
|
function attachTransformerCharacteristics( csn, transformation, options,
|
|
60
57
|
relevantOptionNames, optionalOptionNames = [] ) {
|
|
61
58
|
const relevant = {};
|
|
62
|
-
for (const name of relevantOptionNames
|
|
59
|
+
for (const name of relevantOptionNames) {
|
|
63
60
|
if (options[name] !== undefined)
|
|
64
61
|
relevant[name] = options[name];
|
|
65
62
|
}
|
|
66
63
|
|
|
67
|
-
for (const name of optionalOptionNames
|
|
64
|
+
for (const name of optionalOptionNames) {
|
|
68
65
|
if (options[name] !== undefined)
|
|
69
66
|
relevant[name] = options[name];
|
|
70
67
|
}
|
|
71
68
|
|
|
72
69
|
// eslint-disable-next-line sonarjs/no-empty-collection
|
|
73
|
-
for (const name of relevantGeneralOptions
|
|
70
|
+
for (const name of relevantGeneralOptions) {
|
|
74
71
|
if (options[name] !== undefined)
|
|
75
72
|
relevant[name] = options[name];
|
|
76
73
|
}
|
|
@@ -142,7 +139,7 @@ function isPreTransformed( csn, transformation ) {
|
|
|
142
139
|
function odataInternal( csn, internalOptions, messageFunctions ) {
|
|
143
140
|
internalOptions.transformation = 'odata';
|
|
144
141
|
let oDataCsn = forOdataNew.transform4odataWithCsn(csn, internalOptions, messageFunctions);
|
|
145
|
-
oDataCsn = sortCsnForTests(oDataCsn, internalOptions);
|
|
142
|
+
oDataCsn = cloneCsn.sortCsnForTests(oDataCsn, internalOptions);
|
|
146
143
|
messageFunctions.setModel(oDataCsn);
|
|
147
144
|
attachTransformerCharacteristics(oDataCsn, 'odata', internalOptions, relevantOdataOptions, warnAboutMismatchOdata);
|
|
148
145
|
return oDataCsn;
|
|
@@ -273,13 +270,12 @@ function forHdbcds( csn, options, messageFunctions ) {
|
|
|
273
270
|
*
|
|
274
271
|
* @param {CSN.Model} csn Plain input CSN
|
|
275
272
|
* @param {EffectiveCsnOptions} options Options
|
|
273
|
+
* @param {EffectiveCsnOptions} internalOptions Options that were already processed
|
|
276
274
|
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
277
275
|
* @returns {CSN.Model} CSN transformed
|
|
278
276
|
* @private
|
|
279
277
|
*/
|
|
280
|
-
function
|
|
281
|
-
const internalOptions = prepareOptions.for.effective(options);
|
|
282
|
-
internalOptions.transformation = 'effective';
|
|
278
|
+
function forEffectiveInternal( csn, options, internalOptions, messageFunctions ) {
|
|
283
279
|
messageFunctions.setOptions( internalOptions );
|
|
284
280
|
if (options.tenantDiscriminator) {
|
|
285
281
|
messageFunctions.error('api-invalid-option', null, {
|
|
@@ -294,6 +290,40 @@ function forEffective( csn, options, messageFunctions ) {
|
|
|
294
290
|
return cloneCsn.sortCsnForTests(eCsn, internalOptions);
|
|
295
291
|
}
|
|
296
292
|
|
|
293
|
+
/**
|
|
294
|
+
* SEAL CSN transformation
|
|
295
|
+
*
|
|
296
|
+
* @param {CSN.Model} csn Plain input CSN
|
|
297
|
+
* @param {EffectiveCsnOptions} options Options
|
|
298
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
299
|
+
* @returns {CSN.Model} CSN transformed
|
|
300
|
+
* @private
|
|
301
|
+
*/
|
|
302
|
+
function forSeal( csn, options, messageFunctions ) {
|
|
303
|
+
const internalOptions = prepareOptions.for.seal(options);
|
|
304
|
+
internalOptions.transformation = 'effective';
|
|
305
|
+
return forEffectiveInternal(csn, options, internalOptions, messageFunctions);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Effective CSN transformation
|
|
310
|
+
*
|
|
311
|
+
* @param {CSN.Model} csn Plain input CSN
|
|
312
|
+
* @param {EffectiveCsnOptions} options Options
|
|
313
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
314
|
+
* @returns {CSN.Model} CSN transformed
|
|
315
|
+
* @private
|
|
316
|
+
*/
|
|
317
|
+
function forEffective( csn, options, messageFunctions ) {
|
|
318
|
+
const internalOptions = prepareOptions.for.effective(options);
|
|
319
|
+
internalOptions.transformation = 'effective';
|
|
320
|
+
// for.effective is still beta mode
|
|
321
|
+
if (!baseModel.isBetaEnabled(options, 'effectiveCsn'))
|
|
322
|
+
throw new baseError.CompilerAssertion('effective CSN is only supported with beta flag `effectiveCsn`!');
|
|
323
|
+
|
|
324
|
+
return forEffectiveInternal(csn, options, internalOptions, messageFunctions);
|
|
325
|
+
}
|
|
326
|
+
|
|
297
327
|
/**
|
|
298
328
|
* Process the given CSN into SQL.
|
|
299
329
|
*
|
|
@@ -352,7 +382,7 @@ function hdi( csn, options, messageFunctions ) {
|
|
|
352
382
|
const sqlArtifactsWithCSNNamesToSort = Object.create(null);
|
|
353
383
|
const sqlArtifactsNotToSort = Object.create(null);
|
|
354
384
|
|
|
355
|
-
forEach(flat, (key) => {
|
|
385
|
+
objectUtils.forEach(flat, (key) => {
|
|
356
386
|
const artifactNameLikeInCsn = key.replace(/\.[^/.]+$/, '');
|
|
357
387
|
nameMapping[artifactNameLikeInCsn] = key;
|
|
358
388
|
if (key.endsWith('.hdbtable') || key.endsWith('.hdbview'))
|
|
@@ -370,7 +400,7 @@ function hdi( csn, options, messageFunctions ) {
|
|
|
370
400
|
}, Object.create(null));
|
|
371
401
|
|
|
372
402
|
// now add the not-sorted stuff, like indices
|
|
373
|
-
forEach(sqlArtifactsNotToSort, (key) => {
|
|
403
|
+
objectUtils.forEach(sqlArtifactsNotToSort, (key) => {
|
|
374
404
|
sorted[remapName(key, sqlCSN, k => !k.endsWith('.hdbindex'))] = sqlArtifactsNotToSort[key];
|
|
375
405
|
});
|
|
376
406
|
|
|
@@ -392,7 +422,7 @@ function hdi( csn, options, messageFunctions ) {
|
|
|
392
422
|
function remapNames( dict, csn, filter ) {
|
|
393
423
|
const result = Object.create(null);
|
|
394
424
|
|
|
395
|
-
forEach(dict, (key, value) => {
|
|
425
|
+
objectUtils.forEach(dict, (key, value) => {
|
|
396
426
|
const name = remapName(key, csn, filter);
|
|
397
427
|
result[name] = value;
|
|
398
428
|
});
|
|
@@ -540,7 +570,7 @@ function sqlMigration( csn, options, messageFunctions, beforeImage ) {
|
|
|
540
570
|
const createAndAlterSqls = [];
|
|
541
571
|
// Turn the structured result into just a flat dictionary of "artifact name": "sql"
|
|
542
572
|
const flatSqlDict = Object.values(hdbkinds).reduce((prev, curr) => {
|
|
543
|
-
forEach(curr, (name, value) => {
|
|
573
|
+
objectUtils.forEach(curr, (name, value) => {
|
|
544
574
|
prev[name] = value;
|
|
545
575
|
});
|
|
546
576
|
return prev;
|
|
@@ -629,9 +659,9 @@ function hdiMigration( csn, options, messageFunctions, beforeImage ) {
|
|
|
629
659
|
*/
|
|
630
660
|
function createSqlDefinitions( hdbkinds, afterImage ) {
|
|
631
661
|
const result = [];
|
|
632
|
-
forEach(hdbkinds, (kind, artifacts) => {
|
|
662
|
+
objectUtils.forEach(hdbkinds, (kind, artifacts) => {
|
|
633
663
|
const suffix = `.${ kind }`;
|
|
634
|
-
forEach(artifacts, (name, sqlStatement) => {
|
|
664
|
+
objectUtils.forEach(artifacts, (name, sqlStatement) => {
|
|
635
665
|
if ( kind !== 'hdbindex' )
|
|
636
666
|
result.push({ name: getFileName(name, afterImage), suffix, sql: sqlStatement });
|
|
637
667
|
else
|
|
@@ -649,7 +679,7 @@ function createSqlDefinitions( hdbkinds, afterImage ) {
|
|
|
649
679
|
*/
|
|
650
680
|
function createSqlDeletions( deletions, beforeImage ) {
|
|
651
681
|
const result = [];
|
|
652
|
-
forEach(deletions, name => result.push({ name: getFileName(name, beforeImage), suffix: '.hdbtable' }));
|
|
682
|
+
objectUtils.forEach(deletions, name => result.push({ name: getFileName(name, beforeImage), suffix: '.hdbtable' }));
|
|
653
683
|
return result;
|
|
654
684
|
}
|
|
655
685
|
/**
|
|
@@ -661,7 +691,7 @@ function createSqlDeletions( deletions, beforeImage ) {
|
|
|
661
691
|
*/
|
|
662
692
|
function createSqlMigrations( migrations, afterImage ) {
|
|
663
693
|
const result = [];
|
|
664
|
-
forEach(migrations, (name, changeset) => result.push({ name: getFileName(name, afterImage), suffix: '.hdbmigrationtable', changeset }));
|
|
694
|
+
objectUtils.forEach(migrations, (name, changeset) => result.push({ name: getFileName(name, afterImage), suffix: '.hdbmigrationtable', changeset }));
|
|
665
695
|
return result;
|
|
666
696
|
}
|
|
667
697
|
|
|
@@ -682,6 +712,10 @@ function hdbcds( csn, options, messageFunctions ) {
|
|
|
682
712
|
internalOptions.transformation = 'hdbcds';
|
|
683
713
|
messageFunctions.setOptions( internalOptions );
|
|
684
714
|
|
|
715
|
+
// no "isBetaEnabled", because this warning must also appear with "deprecated" flags
|
|
716
|
+
if (internalOptions.betaMode || internalOptions.beta?.v5preview)
|
|
717
|
+
messageFunctions.warning('api-deprecated-v5', null, null);
|
|
718
|
+
|
|
685
719
|
if (options.tenantDiscriminator) {
|
|
686
720
|
messageFunctions.error('api-invalid-option', null, {
|
|
687
721
|
'#': 'forbidden',
|
|
@@ -1012,10 +1046,10 @@ function preparedCsnToEdmAll( csn, options, messageFunctions ) {
|
|
|
1012
1046
|
*/
|
|
1013
1047
|
function flattenResultStructure( toProcess ) {
|
|
1014
1048
|
const result = {};
|
|
1015
|
-
forEach(toProcess, (fileType, artifacts) => {
|
|
1049
|
+
objectUtils.forEach(toProcess, (fileType, artifacts) => {
|
|
1016
1050
|
if (fileType === 'messages')
|
|
1017
1051
|
return;
|
|
1018
|
-
forEach(artifacts, (filename) => {
|
|
1052
|
+
objectUtils.forEach(artifacts, (filename) => {
|
|
1019
1053
|
result[`${ filename }.${ fileType }`] = artifacts[filename];
|
|
1020
1054
|
});
|
|
1021
1055
|
});
|
|
@@ -1039,14 +1073,15 @@ module.exports = {
|
|
|
1039
1073
|
for_hdi: publishCsnProcessor(forHdi, 'for.hdi'),
|
|
1040
1074
|
for_hdbcds: publishCsnProcessor(forHdbcds, 'for.hdbcds'),
|
|
1041
1075
|
for_effective: publishCsnProcessor(forEffective, 'for.effective'),
|
|
1076
|
+
for_seal: publishCsnProcessor(forSeal, 'for.seal'),
|
|
1042
1077
|
|
|
1043
1078
|
/* Deprecated, will be removed in cds-compiler@v5 */ // TODO(v5): Remove
|
|
1044
1079
|
preparedCsnToEdmx(csn, service, options) {
|
|
1045
|
-
preparedCsnToEdmx(csn, service, options, makeMessageFunction( csn, options, 'to.edmx' ));
|
|
1080
|
+
preparedCsnToEdmx(csn, service, options, messages.makeMessageFunction( csn, options, 'to.edmx' ));
|
|
1046
1081
|
},
|
|
1047
1082
|
/* Deprecated, will be removed in cds-compiler@v5 */ // TODO(v5): Remove
|
|
1048
1083
|
preparedCsnToEdm(csn, service, options) {
|
|
1049
|
-
preparedCsnToEdm(csn, service, options, makeMessageFunction( csn, options, 'to.edm' ));
|
|
1084
|
+
preparedCsnToEdm(csn, service, options, messages.makeMessageFunction( csn, options, 'to.edm' ));
|
|
1050
1085
|
},
|
|
1051
1086
|
};
|
|
1052
1087
|
|
|
@@ -1160,7 +1195,7 @@ function checkOutdatedOptions( options, messageFunctions ) {
|
|
|
1160
1195
|
});
|
|
1161
1196
|
}
|
|
1162
1197
|
|
|
1163
|
-
forEachKey(options.variableReplacements || {}, (name) => {
|
|
1198
|
+
objectUtils.forEachKey(options.variableReplacements || {}, (name) => {
|
|
1164
1199
|
if (!name.startsWith('$') && name !== 'user' && name !== 'locale') {
|
|
1165
1200
|
messageFunctions.error('api-invalid-variable-replacement', null, {
|
|
1166
1201
|
'#': 'noDollar', option: 'variableReplacements', code: '$', name,
|
package/lib/api/options.js
CHANGED
|
@@ -52,6 +52,8 @@ const publicOptionsNewAPI = [
|
|
|
52
52
|
// for.effective
|
|
53
53
|
'resolveSimpleTypes',
|
|
54
54
|
'resolveProjections',
|
|
55
|
+
'remapOdataAnnotations',
|
|
56
|
+
'keepLocalized',
|
|
55
57
|
];
|
|
56
58
|
|
|
57
59
|
// Internal options used for testing/debugging etc.
|
|
@@ -214,12 +216,21 @@ module.exports = {
|
|
|
214
216
|
effective: (options) => {
|
|
215
217
|
const hardOptions = {};
|
|
216
218
|
const defaultOptions = {
|
|
217
|
-
sqlMapping: 'plain', resolveSimpleTypes: true, resolveProjections: true,
|
|
219
|
+
sqlMapping: 'plain', resolveSimpleTypes: true, resolveProjections: true, remapOdataAnnotations: false, keepLocalized: false,
|
|
218
220
|
};
|
|
219
221
|
const processed = translateOptions(options, defaultOptions, hardOptions, null, [ 'sql-dialect-and-naming' ], 'for.effective');
|
|
220
222
|
|
|
221
223
|
return Object.assign({}, processed);
|
|
222
224
|
},
|
|
225
|
+
seal: (options) => {
|
|
226
|
+
const hardOptions = {
|
|
227
|
+
sqlMapping: 'plain', resolveSimpleTypes: true, resolveProjections: true, keepLocalized: false,
|
|
228
|
+
};
|
|
229
|
+
const defaultOptions = { remapOdataAnnotations: true };
|
|
230
|
+
const processed = translateOptions(options, defaultOptions, hardOptions, null, [ 'sql-dialect-and-naming' ], 'for.effective');
|
|
231
|
+
|
|
232
|
+
return Object.assign({}, processed);
|
|
233
|
+
},
|
|
223
234
|
java: options => translateOptions(options, { sqlMapping: 'plain' }, {}, undefined, undefined, 'for.java'),
|
|
224
235
|
},
|
|
225
236
|
overallOptions, // exported for testing
|
package/lib/api/validate.js
CHANGED
|
@@ -140,17 +140,13 @@ const allCombinationValidators = {
|
|
|
140
140
|
if (options.sqlDialect && options.sqlMapping && options.sqlDialect !== 'hana' && [ 'quoted', 'hdbcds' ].includes(options.sqlMapping))
|
|
141
141
|
message.error('api-invalid-combination', null, { '#': 'sql-dialect-and-naming', name: options.sqlDialect, prop: options.sqlMapping });
|
|
142
142
|
},
|
|
143
|
-
'sql-dialect-and-localized': (options, message) => {
|
|
144
|
-
if (options.fewerLocalizedViews && options.sqlDialect === 'hana' && (options.withHanaAssociations || options.withHanaAssociations === undefined))
|
|
145
|
-
message.error('api-invalid-combination', null, { '#': 'sql-dialect-and-localized', option: 'fewerLocalizedViews', value: 'hana' });
|
|
146
|
-
},
|
|
147
143
|
'beta-no-test': (options, message) => {
|
|
148
144
|
if (options.beta && !options.testMode)
|
|
149
145
|
message.warning('api-unexpected-combination', null, { '#': 'beta-no-test', option: 'beta' });
|
|
150
146
|
},
|
|
151
147
|
};
|
|
152
148
|
|
|
153
|
-
const alwaysRunValidators = [ 'beta-no-test'
|
|
149
|
+
const alwaysRunValidators = [ 'beta-no-test' ];
|
|
154
150
|
|
|
155
151
|
/**
|
|
156
152
|
* Run the validations for each option.
|
package/lib/base/builtins.js
CHANGED
|
@@ -4,6 +4,32 @@
|
|
|
4
4
|
// It should not contain any specific to XSN, i.e. neither XSN structures
|
|
5
5
|
// nor any other XSN properties.
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Map of propagation rules for annotations.
|
|
9
|
+
* Does not include rules for standard propagation of annotations or other properties.
|
|
10
|
+
*
|
|
11
|
+
* @type {Record<string, string>}
|
|
12
|
+
*/
|
|
13
|
+
const propagationRules = {
|
|
14
|
+
__proto__: null,
|
|
15
|
+
'@Analytics.hidden': 'never',
|
|
16
|
+
'@Analytics.visible': 'never',
|
|
17
|
+
'@cds.autoexpose': 'onlyViaArtifact',
|
|
18
|
+
'@cds.autoexposed': 'never',
|
|
19
|
+
'@cds.external': 'never',
|
|
20
|
+
'@cds.persistence.calcview': 'never',
|
|
21
|
+
'@cds.persistence.exists': 'never',
|
|
22
|
+
'@cds.persistence.skip': 'notWithPersistenceTable',
|
|
23
|
+
'@cds.persistence.table': 'never',
|
|
24
|
+
'@cds.persistence.udf': 'never',
|
|
25
|
+
'@cds.redirection.target': 'never',
|
|
26
|
+
'@com.sap.gtt.core.CoreModel.Indexable': 'never',
|
|
27
|
+
'@fiori.draft.enabled': 'onlyViaArtifact',
|
|
28
|
+
'@sql.append': 'never',
|
|
29
|
+
'@sql.prepend': 'never',
|
|
30
|
+
'@sql.replace': 'never',
|
|
31
|
+
}
|
|
32
|
+
|
|
7
33
|
/**
|
|
8
34
|
* Checks whether the given absolute path is inside a reserved namespace.
|
|
9
35
|
*
|
|
@@ -80,6 +106,7 @@ function isAnnotationExpression( val ) {
|
|
|
80
106
|
}
|
|
81
107
|
|
|
82
108
|
module.exports = {
|
|
109
|
+
propagationRules,
|
|
83
110
|
xprInAnnoProperties,
|
|
84
111
|
functionsWithoutParens,
|
|
85
112
|
isInReservedNamespace,
|
|
@@ -64,8 +64,10 @@ const centralMessages = {
|
|
|
64
64
|
'ext-undefined-param': { severity: 'Warning' },
|
|
65
65
|
'anno-unexpected-ellipsis': { severity: 'Error', configurableFor: 'deprecated' },
|
|
66
66
|
'anno-unexpected-localized-skip': { severity: 'Error', configurableFor: true },
|
|
67
|
+
'anno-unexpected-mixin': { severity: 'Warning', errorFor: [ 'v5' ] },
|
|
67
68
|
|
|
68
69
|
'name-invalid-dollar-alias': { severity: 'Error', configurableFor: true },
|
|
70
|
+
'name-deprecated-$self': { severity: 'Warning', errorFor: [ 'v5' ], configurableFor: true },
|
|
69
71
|
|
|
70
72
|
'type-invalid-items': { severity: 'Error' }, // not supported yet
|
|
71
73
|
'assoc-as-type': { severity: 'Error' }, // TODO: allow more, but not all
|
|
@@ -84,6 +86,7 @@ const centralMessages = {
|
|
|
84
86
|
'empty-type': { severity: 'Info' }, // only still an error in old transformers
|
|
85
87
|
|
|
86
88
|
'ref-deprecated-orderby': { severity: 'Error', configurableFor: true },
|
|
89
|
+
'ref-deprecated-self-element': { severity: 'Warning', configurableFor: true, errorFor: [ 'v5' ] },
|
|
87
90
|
'ref-invalid-type': { severity: 'Error' },
|
|
88
91
|
'ref-unexpected-self': { severity: 'Error' },
|
|
89
92
|
'ref-invalid-include': { severity: 'Error' },
|
|
@@ -159,6 +162,7 @@ const centralMessages = {
|
|
|
159
162
|
'syntax-unknown-escape': { severity: 'Error', configurableFor: true },
|
|
160
163
|
'syntax-unsupported-masked': { severity: 'Error', configurableFor: 'deprecated' },
|
|
161
164
|
'syntax-unexpected-sql-clause': { severity: 'Error' }, // TODO: configurableFor:'tests'?
|
|
165
|
+
'syntax-ignoring-anno': { severity: 'Warning', errorFor: [ 'v5' ] },
|
|
162
166
|
|
|
163
167
|
'type-unsupported-precision-change': { severity: 'Error' },
|
|
164
168
|
'type-unsupported-key-change': { severity: 'Error', configurableFor: true },
|
|
@@ -230,6 +234,9 @@ for (const oldName in oldMessageIds) {
|
|
|
230
234
|
// If you change it, keep in sync with scripts/eslint/rules/message-text.js
|
|
231
235
|
|
|
232
236
|
const centralMessageTexts = {
|
|
237
|
+
'api-deprecated-v5': {
|
|
238
|
+
std: 'Support for generating hdbcds output is deprecated with @sap/cds-compiler v5 and later'
|
|
239
|
+
},
|
|
233
240
|
'api-invalid-option': {
|
|
234
241
|
std: 'Invalid option $(NAME)!',
|
|
235
242
|
deprecated: 'Option $(NAME) is no longer supported! Use latest API options instead',
|
|
@@ -251,7 +258,6 @@ const centralMessageTexts = {
|
|
|
251
258
|
std: 'Invalid option combination found: $(OPTION) and $(PROP)', // unused
|
|
252
259
|
'valid-structured': 'Structured OData is only supported with OData version v4',
|
|
253
260
|
'sql-dialect-and-naming': 'sqlDialect $(NAME) can\'t be combined with sqlMapping $(PROP)',
|
|
254
|
-
'sql-dialect-and-localized': 'Option $(OPTION) can\'t be combined with SQL dialect $(VALUE) or the to.hdi()/to.hdbcds() backend',
|
|
255
261
|
'tenant-and-naming': 'Option $(OPTION) can\'t be combined with sqlMapping $(PROP) - expected sqlMapping $(VALUE)'
|
|
256
262
|
},
|
|
257
263
|
'api-unexpected-combination': {
|
|
@@ -284,6 +290,7 @@ const centralMessageTexts = {
|
|
|
284
290
|
'anno-unstable-array': 'Unstable order of array items due to repeated assignments for $(ANNO)',
|
|
285
291
|
'anno-mismatched-ellipsis': 'An array with $(CODE) can only be used if there is an assignment below with an array value',
|
|
286
292
|
'anno-unexpected-ellipsis': 'No base annotation available to apply $(CODE)',
|
|
293
|
+
'anno-unexpected-mixin': 'Unexpected annotation on mixin definition',
|
|
287
294
|
|
|
288
295
|
'anno-unexpected-localized-skip': {
|
|
289
296
|
std: 'Compiler generated entity $(NAME) must not be annotated with $(ANNO) if $(ART) is not skipped',
|
|
@@ -291,8 +298,9 @@ const centralMessageTexts = {
|
|
|
291
298
|
},
|
|
292
299
|
|
|
293
300
|
'anno-missing-rewrite': {
|
|
294
|
-
std: 'Assign a value for $(ANNO)
|
|
295
|
-
|
|
301
|
+
std: 'Assign a value for $(ANNO); the value inherited from $(ART) can\'t be rewritten due to $(ELEMREF)',
|
|
302
|
+
unsupported: 'Assign a value for $(ANNO); the value inherited from $(ART) can\'t be rewritten due to unsupported $(ELEMREF)',
|
|
303
|
+
param: 'Assign a value for $(ANNO); the value inherited from $(ART) can\'t be rewritten due to parameter reference $(ELEMREF)',
|
|
296
304
|
},
|
|
297
305
|
|
|
298
306
|
'chained-array-of': '"Array of"/"many" must not be chained with another "array of"/"many" inside a service',
|
|
@@ -568,13 +576,17 @@ const centralMessageTexts = {
|
|
|
568
576
|
entity: 'Entity $(ART) has no parameter $(ID)',
|
|
569
577
|
action: 'Action $(ART) has no parameter $(ID)',
|
|
570
578
|
},
|
|
571
|
-
'ref-undefined-art':
|
|
579
|
+
'ref-undefined-art': {
|
|
580
|
+
std: 'No artifact has been found with name $(ART)',
|
|
581
|
+
namespace: 'No artifact has been found with name $(ART) which can be extended with annotations',
|
|
582
|
+
localized: 'Can\'t extend localized definitions, only annotate them using an $(KEYWORD) statement',
|
|
583
|
+
},
|
|
572
584
|
// TODO: proposal 'No definition found for $(NAME)',
|
|
573
585
|
'ref-undefined-element': {
|
|
574
586
|
std: 'Element $(ART) has not been found',
|
|
575
587
|
element: 'Artifact $(ART) has no element $(MEMBER)',
|
|
576
588
|
target: 'Target entity $(ART) has no element $(ID)',
|
|
577
|
-
aspect: 'Element $(ID) has not been found in the anonymous target aspect',
|
|
589
|
+
aspect: 'Element $(ID) has not been found in the anonymous target aspect',
|
|
578
590
|
query: 'The current query has no element $(ART)',
|
|
579
591
|
alias: 'Element $(ART) has not been found in the sub query for alias $(ALIAS)',
|
|
580
592
|
virtual: 'Element $(ART) has not been found. Use $(CODE) to add virtual elements in queries'
|
|
@@ -585,6 +597,7 @@ const centralMessageTexts = {
|
|
|
585
597
|
target: 'Target entity $(ART) has no element $(ID)',
|
|
586
598
|
query: 'The current query has no element $(ART)',
|
|
587
599
|
alias: 'Element $(ART) has not been found in the sub query for alias $(ALIAS)',
|
|
600
|
+
aspect: 'Element $(ID) has not been found in the anonymous target aspect',
|
|
588
601
|
},
|
|
589
602
|
'ref-undefined-var': {
|
|
590
603
|
std: 'Variable $(ID) has not been found',
|
|
@@ -705,6 +718,8 @@ const centralMessageTexts = {
|
|
|
705
718
|
min: 'Expecting argument $(PROP) for type $(TYPE) to be greater than or equal to $(NUMBER)',
|
|
706
719
|
'incorrect-type': 'Expected $(NAMES) for argument $(PROP), but found $(CODE)',
|
|
707
720
|
},
|
|
721
|
+
'type-unexpected-foreign-keys': 'A managed aspect composition can\'t have a foreign keys specification. Use composition-of-entity or remove foreign keys',
|
|
722
|
+
'type-unexpected-on-condition': 'A managed aspect composition can\'t have a specified ON-condition. Use composition-of-entity or remove the ON-condition',
|
|
708
723
|
|
|
709
724
|
'type-invalid-items': {
|
|
710
725
|
std: 'Unexpected $(PROP)', // unused
|
|
@@ -721,7 +736,7 @@ const centralMessageTexts = {
|
|
|
721
736
|
'targetAspect': 'Unexpected $(KEYWORD) on composition of aspect'
|
|
722
737
|
},
|
|
723
738
|
|
|
724
|
-
'anno-builtin': 'Builtin types should not be annotated. Use custom type instead',
|
|
739
|
+
'anno-builtin': 'Builtin types should not be annotated nor extended. Use custom type instead',
|
|
725
740
|
'ext-undefined-def': 'Artifact $(ART) has not been found',
|
|
726
741
|
'ext-undefined-art': 'No artifact has been found with name $(ART)',
|
|
727
742
|
'ext-undefined-element': {
|
|
@@ -864,7 +879,7 @@ const centralMessageTexts = {
|
|
|
864
879
|
sub: 'Expecting an entity as target; a target aspect can\'t be specified for a sub element',
|
|
865
880
|
},
|
|
866
881
|
'ref-invalid-include': {
|
|
867
|
-
std: '
|
|
882
|
+
std: 'An explicitly structured entity, type, aspect, or event is expected here',
|
|
868
883
|
bare : 'An aspect without elements is expected here',
|
|
869
884
|
param: 'A type, entity, aspect or event without parameters is expected here',
|
|
870
885
|
},
|
|
@@ -907,8 +922,8 @@ const centralMessageTexts = {
|
|
|
907
922
|
},
|
|
908
923
|
|
|
909
924
|
'query-undefined-element': {
|
|
910
|
-
std: 'Target $(TARGET) of $(NAME) is missing element $(ID);
|
|
911
|
-
redirected: 'Target $(TARGET) of $(NAME) is missing element $(ID);
|
|
925
|
+
std: 'Target $(TARGET) of $(NAME) is missing element $(ID); use $(KEYWORD) with an explicit ON-condition',
|
|
926
|
+
redirected: 'Target $(TARGET) of $(NAME) is missing element $(ID); add an ON-condition to $(KEYWORD)',
|
|
912
927
|
},
|
|
913
928
|
'query-unexpected-assoc-hdbcds': 'Publishing a managed association in a view is not possible for “hdbcds” naming mode',
|
|
914
929
|
'query-unexpected-structure-hdbcds': 'Publishing a structured element in a view is not possible for “hdbcds” naming mode',
|
|
@@ -1032,10 +1047,10 @@ const centralMessageTexts = {
|
|
|
1032
1047
|
'odata-spec-violation-assoc': 'Unexpected association in structured type for OData $(VERSION)',
|
|
1033
1048
|
'odata-spec-violation-constraints': 'Partial referential constraints produced for OData $(VERSION)',
|
|
1034
1049
|
'odata-spec-violation-id': {
|
|
1035
|
-
std: 'Expected EDM name $(ID) to start with
|
|
1050
|
+
std: 'Expected EDM name $(ID) to start with an alphabetic character or underscore, followed by a maximum of 127 alphabetic characters, digits, or underscores',
|
|
1036
1051
|
'v2firstchar': 'Unexpected first character $(PROP) of EDM Name $(ID) for OData $(VERSION)',
|
|
1037
|
-
'qualifier': 'Expected annotation qualifier $(ID) to start with
|
|
1038
|
-
'vocrefalias': 'Expected value $(VALUE) of vocabulary reference attribute $(ID) to start with
|
|
1052
|
+
'qualifier': 'Expected annotation qualifier $(ID) to start with an alphabetic character or underscore, followed by a maximum of 127 alphabetic characters, digits, or underscores',
|
|
1053
|
+
'vocrefalias': 'Expected value $(VALUE) of vocabulary reference attribute $(ID) to start with an alphabetic character or underscore, followed by a maximum of 127 alphabetic characters, digits, or underscores',
|
|
1039
1054
|
},
|
|
1040
1055
|
// version independent messages
|
|
1041
1056
|
'odata-spec-violation-key-array': {
|
|
@@ -1051,7 +1066,7 @@ const centralMessageTexts = {
|
|
|
1051
1066
|
scalar: 'Unexpected $(TYPE) mapped to $(ID) as type for key element' // flat
|
|
1052
1067
|
},
|
|
1053
1068
|
'odata-spec-violation-no-key': 'Expected entity to have a primary key',
|
|
1054
|
-
'odata-spec-violation-type-unknown': 'Unknown
|
|
1069
|
+
'odata-spec-violation-type-unknown': 'Unknown EDM Type $(TYPE)',
|
|
1055
1070
|
'odata-spec-violation-type': {
|
|
1056
1071
|
std: 'Expected element to have a type',
|
|
1057
1072
|
incompatible: 'Unexpected EDM Type $(TYPE) for OData $(VERSION)',
|
|
@@ -1148,13 +1163,14 @@ const centralMessageTexts = {
|
|
|
1148
1163
|
'odata-anno-xpr': {
|
|
1149
1164
|
'std': 'unused',
|
|
1150
1165
|
'notadynexpr': '$(OP) is not a renderable dynamic expression in $(ANNO)',
|
|
1151
|
-
'use': 'Function $(OP) is not a renderable dynamic expression in $(ANNO),
|
|
1166
|
+
'use': 'Function $(OP) is not a renderable dynamic expression in $(ANNO), use $(CODE) instead',
|
|
1152
1167
|
'canonfuncalias': 'Expected function name $(CODE) to be of the form $(META).$(OTHERMETA) for $(OP) in $(ANNO)',
|
|
1153
1168
|
'unexpected': 'Unexpected expression in $(ANNO)',
|
|
1154
1169
|
}
|
|
1155
1170
|
,
|
|
1156
1171
|
'odata-anno-xpr-type': {
|
|
1157
|
-
'std': 'Expected one qualified type name for $(OP) in $(ANNO)'
|
|
1172
|
+
'std': 'Expected one qualified type name for $(OP) in $(ANNO)',
|
|
1173
|
+
'edm': 'Expected a qualified EDM type name for $(OP) in $(ANNO) but found $(TYPE)'
|
|
1158
1174
|
},
|
|
1159
1175
|
'odata-anno-xpr-args': {
|
|
1160
1176
|
'std': 'Unexpected arguments for $(OP) in $(ANNO)',
|
|
@@ -1169,14 +1185,15 @@ const centralMessageTexts = {
|
|
|
1169
1185
|
'odata-anno-xpr-ref': {
|
|
1170
1186
|
'std': '$(ANNO) can\'t be propagated to $(NAME) because path $(ELEMREF) is not resolvable via type reference $(CODE)',
|
|
1171
1187
|
'args': 'Unexpected arguments or filters in $(ELEMREF) in $(ANNO)',
|
|
1172
|
-
'flatten_builtin': 'Expected path $(ELEMREF) in $(ANNO) to end
|
|
1173
|
-
'flatten_builtin_type': 'Expected path $(ELEMREF) in $(ANNO) to end
|
|
1188
|
+
'flatten_builtin': 'Expected path $(ELEMREF) in $(ANNO) to end in a scalar typed leaf element while flattening $(NAME)',
|
|
1189
|
+
'flatten_builtin_type': 'Expected path $(ELEMREF) in $(ANNO) to end in a scalar typed leaf element while flattening',
|
|
1174
1190
|
'invalid': 'Invalid path $(ELEMREF) in $(ANNO)',
|
|
1175
1191
|
// genericTranslation
|
|
1176
|
-
'notaparam': 'Element path $(ELEMREF) can\'t be used in $(ANNO) which is applied to a parameter entity',
|
|
1177
|
-
'notaneelement': 'Parameter path $(ELEMREF) can\'t be used in $(ANNO) which is applied to a type entity',
|
|
1178
|
-
'notrendered': 'Path step $(COUNT) of $(ELEMREF) in $(ANNO) refers to an unrendered
|
|
1179
|
-
'
|
|
1192
|
+
'notaparam': 'EDM Element path $(ELEMREF) can\'t be used in $(ANNO) which is applied to a parameter entity',
|
|
1193
|
+
'notaneelement': 'EDM Parameter path $(ELEMREF) can\'t be used in $(ANNO) which is applied to a type entity',
|
|
1194
|
+
'notrendered': 'EDM Path step $(COUNT) of $(ELEMREF) in $(ANNO) refers to an unrendered property in the OData API',
|
|
1195
|
+
'magic': 'Unexpected magic variable $(ELEMREF) in $(ANNO)',
|
|
1196
|
+
'bparam_v2': 'Unexpected explicit binding parameter path $(ELEMREF) for OData $(VERSION) in $(ANNO)',
|
|
1180
1197
|
},
|
|
1181
1198
|
// -----------------------------------------------------------------------------------
|
|
1182
1199
|
// OData Message section ends here, no messages below this line
|
package/lib/base/messages.js
CHANGED
|
@@ -82,6 +82,23 @@ function isDowngradable( messageId, moduleName, options ) {
|
|
|
82
82
|
: configurableFor && (configurableFor !== 'deprecated' || isDeprecatedEnabled( options, 'downgradableErrors' ));
|
|
83
83
|
}
|
|
84
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
|
+
|
|
85
102
|
/**
|
|
86
103
|
* Class for combined compiler errors. Additional members:
|
|
87
104
|
* - `messages`: array of compiler messages (CompileMessage)
|
|
@@ -100,8 +117,6 @@ class CompilationError extends Error {
|
|
|
100
117
|
this.code = 'ERR_CDS_COMPILATION_FAILURE';
|
|
101
118
|
this.messages = [ ...messages ].sort(compareMessageSeverityAware);
|
|
102
119
|
|
|
103
|
-
// TODO: remove this bin/cdsc.js specifics
|
|
104
|
-
Object.defineProperty( this, 'hasBeenReported', { value: false, configurable: true, writable: true, enumerable: false } );
|
|
105
120
|
// property `model` is only set with options.attachValidNames:
|
|
106
121
|
Object.defineProperty( this, 'model', { value: model || undefined, configurable: true } );
|
|
107
122
|
}
|
|
@@ -176,8 +191,14 @@ class CompileMessage {
|
|
|
176
191
|
// this.error = null;
|
|
177
192
|
}
|
|
178
193
|
|
|
179
|
-
toString() {
|
|
180
|
-
|
|
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
|
+
});
|
|
181
202
|
}
|
|
182
203
|
}
|
|
183
204
|
|
|
@@ -869,7 +890,7 @@ function transformElementRef( arg ) {
|
|
|
869
890
|
return quoted( arg );
|
|
870
891
|
// Can be used by CSN backends or compiler to create a simple path such as E:elem
|
|
871
892
|
return quoted(
|
|
872
|
-
(arg.param ? ':' : '') +
|
|
893
|
+
((arg.scope === 'param' || arg.param) ? ':' : '') +
|
|
873
894
|
ref.map(
|
|
874
895
|
item => (typeof item !== 'string'
|
|
875
896
|
? `${ item.id }${item.args ? '(…)' : ''}${item.where ? '[…]' : ''}`
|
|
@@ -997,12 +1018,17 @@ function replaceInString( text, params ) {
|
|
|
997
1018
|
* @param {boolean} [config.noMessageId]
|
|
998
1019
|
* If true, will _not_ show the message ID (+ explanation hint) in the output.
|
|
999
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
|
+
*
|
|
1000
1025
|
* @param {boolean} [config.noHome]
|
|
1001
1026
|
* If true, will _not_ show message's semantic location.
|
|
1002
1027
|
*
|
|
1003
|
-
* @param {string} [config.
|
|
1028
|
+
* @param {string} [config.moduleForMarker]
|
|
1004
1029
|
* If set, downgradable error messages will get a '‹↓›' marker, depending on whether
|
|
1005
|
-
* 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.
|
|
1006
1032
|
*
|
|
1007
1033
|
* @returns {string}
|
|
1008
1034
|
*/
|
|
@@ -1013,19 +1039,22 @@ function messageString( err, config ) {
|
|
|
1013
1039
|
normalizeFilename: arguments[1],
|
|
1014
1040
|
noMessageId: arguments[2],
|
|
1015
1041
|
noHome: arguments[3],
|
|
1016
|
-
|
|
1042
|
+
moduleForMarker: arguments[4],
|
|
1017
1043
|
};
|
|
1018
1044
|
}
|
|
1045
|
+
config.moduleForMarker ??= config.module; // v4.8.0 or earlier compatibility
|
|
1019
1046
|
|
|
1020
1047
|
const location = (err.$location?.file ? `${ locationString( err.$location, config.normalizeFilename ) }: ` : '');
|
|
1021
1048
|
const severity = err.severity || 'Error';
|
|
1022
|
-
const downgradable =
|
|
1023
|
-
isDowngradable(err.messageId, config.module, {}) ? '‹↓›' : '';
|
|
1049
|
+
const downgradable = severityChangeMarker(err, config);
|
|
1024
1050
|
// even with noHome, print err.home if the location is weak
|
|
1025
1051
|
const home = !err.home || config.noHome && err.$location?.endLine ? '' : ` (in ${ err.home })`;
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
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 }`;
|
|
1029
1058
|
}
|
|
1030
1059
|
|
|
1031
1060
|
/**
|
|
@@ -1065,9 +1094,10 @@ function messageHash( msg ) {
|
|
|
1065
1094
|
* @param {boolean} [config.hintExplanation]
|
|
1066
1095
|
* If true, messages with explanations will get a "…" marker.
|
|
1067
1096
|
*
|
|
1068
|
-
* @param {string} [config.
|
|
1097
|
+
* @param {string} [config.moduleForMarker]
|
|
1069
1098
|
* If set, downgradable error messages will get a '‹↓›' marker, depending on whether
|
|
1070
|
-
* 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.
|
|
1071
1101
|
*
|
|
1072
1102
|
* @param {Record<string, string>} [config.sourceMap]
|
|
1073
1103
|
* A dictionary of filename<->source-code entries. You can pass the `fileCache` that is used
|
|
@@ -1095,12 +1125,13 @@ function messageHash( msg ) {
|
|
|
1095
1125
|
function messageStringMultiline( err, config = {} ) {
|
|
1096
1126
|
colorTerm.changeColorMode(config ? config.color : 'auto');
|
|
1097
1127
|
|
|
1128
|
+
config.moduleForMarker ??= config.module; // v4.8.0 or earlier compatibility
|
|
1129
|
+
|
|
1098
1130
|
const explainHelp = (config.hintExplanation && hasMessageExplanation(err.messageId)) ? '…' : '';
|
|
1099
1131
|
const home = !err.home ? '' : (`at ${ err.home }`);
|
|
1100
1132
|
const severity = err.severity || 'Error';
|
|
1101
|
-
const downgradable = config
|
|
1102
|
-
|
|
1103
|
-
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 }]` : '';
|
|
1104
1135
|
|
|
1105
1136
|
let location = '';
|
|
1106
1137
|
let context = '';
|
|
@@ -1590,7 +1621,7 @@ function constructSemanticLocationFromCsnPath( model, options, csnPath ) {
|
|
|
1590
1621
|
if (!currentThing)
|
|
1591
1622
|
return result;
|
|
1592
1623
|
|
|
1593
|
-
|
|
1624
|
+
const selectDepth = (csnPath[0] !== 'extensions') ? queryDepthForMessage(csnPath, model, currentThing) : null;
|
|
1594
1625
|
|
|
1595
1626
|
// Artifact ref -------------------------------------
|
|
1596
1627
|
|
|
@@ -1759,7 +1790,7 @@ function constructSemanticLocationFromCsnPath( model, options, csnPath ) {
|
|
|
1759
1790
|
if (index >= csnPath.length)
|
|
1760
1791
|
continue; // no column name
|
|
1761
1792
|
|
|
1762
|
-
|
|
1793
|
+
const elementHierarchy = [];
|
|
1763
1794
|
|
|
1764
1795
|
// Concat column+expand/inline to get a name similar to elements.
|
|
1765
1796
|
do {
|