@sap/cds-compiler 5.6.0 → 5.7.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 +31 -0
- package/bin/cdsse.js +1 -0
- package/bin/cdsv2m.js +2 -1
- package/doc/Versioning.md +4 -4
- package/lib/api/options.js +1 -0
- package/lib/base/builtins.js +2 -2
- package/lib/base/dictionaries.js +1 -2
- package/lib/base/keywords.js +3 -1
- package/lib/base/lazyload.js +1 -1
- package/lib/base/message-registry.js +169 -144
- package/lib/base/messages.js +69 -59
- package/lib/base/model.js +3 -3
- package/lib/base/node-helpers.js +17 -16
- package/lib/base/optionProcessorHelper.js +13 -14
- package/lib/base/shuffle.js +4 -1
- package/lib/checks/structuredAnnoExpressions.js +1 -1
- package/lib/compiler/assert-consistency.js +1 -1
- package/lib/compiler/builtins.js +2 -1
- package/lib/compiler/extend.js +20 -5
- package/lib/compiler/resolve.js +45 -9
- package/lib/compiler/shared.js +1 -0
- package/lib/edm/annotations/edmJson.js +3 -3
- package/lib/edm/annotations/genericTranslation.js +5 -1
- package/lib/edm/annotations/vocabularyDefinitions.js +2 -2
- package/lib/edm/edmUtils.js +2 -1
- package/lib/gen/BaseParser.js +32 -32
- package/lib/gen/CdlParser.js +2237 -2196
- package/lib/json/from-csn.js +2 -0
- package/lib/json/to-csn.js +13 -4
- package/lib/language/docCommentParser.js +11 -5
- package/lib/language/errorStrategy.js +3 -3
- package/lib/language/genericAntlrParser.js +2 -0
- package/lib/model/csnUtils.js +6 -1
- package/lib/optionProcessor.js +5 -1
- package/lib/parsers/AstBuildingParser.js +151 -72
- package/lib/parsers/CdlGrammar.g4 +125 -83
- package/lib/parsers/Lexer.js +5 -3
- package/lib/parsers/index.js +1 -1
- package/lib/render/toCdl.js +6 -5
- package/lib/render/toHdbcds.js +1 -1
- package/lib/render/toSql.js +5 -3
- package/lib/render/utils/common.js +19 -6
- package/lib/render/utils/standardDatabaseFunctions.js +576 -0
- package/lib/transform/addTenantFields.js +2 -1
- package/lib/transform/db/flattening.js +18 -77
- package/lib/transform/db/groupByOrderBy.js +2 -2
- package/lib/transform/db/rewriteCalculatedElements.js +14 -19
- package/lib/transform/db/temporal.js +2 -1
- package/lib/transform/odata/adaptAnnotationRefs.js +79 -0
- package/lib/transform/odata/createForeignKeys.js +4 -71
- package/lib/transform/odata/flattening.js +11 -1
- package/lib/transform/transformUtils.js +20 -85
- package/package.json +2 -1
- package/bin/cds_update_annotations.js +0 -180
package/lib/base/messages.js
CHANGED
|
@@ -17,7 +17,7 @@ const meta = require('./meta');
|
|
|
17
17
|
|
|
18
18
|
const fs = require('fs');
|
|
19
19
|
const path = require('path');
|
|
20
|
-
const { inspect } = require('util')
|
|
20
|
+
const { inspect } = require('util');
|
|
21
21
|
|
|
22
22
|
// term instance for messages
|
|
23
23
|
const colorTerm = term();
|
|
@@ -89,7 +89,7 @@ function isDowngradable( messageId, moduleName, options ) {
|
|
|
89
89
|
*
|
|
90
90
|
* @returns {string}
|
|
91
91
|
*/
|
|
92
|
-
function severityChangeMarker(msg, config) {
|
|
92
|
+
function severityChangeMarker( msg, config ) {
|
|
93
93
|
const severity = msg.severity || 'Error';
|
|
94
94
|
if (config.moduleForMarker) {
|
|
95
95
|
if (severity === 'Error' &&
|
|
@@ -118,7 +118,7 @@ class CompilationError extends Error {
|
|
|
118
118
|
// no proper message about _what_ the root cause of the exception was.
|
|
119
119
|
// To mitigate that, we serialize the first error in the message as well.
|
|
120
120
|
const firstError = messages.find( m => m.severity === 'Error' )?.toString() || '';
|
|
121
|
-
super( `CDS compilation failed (@sap/cds-compiler v${ meta.version() })\n${firstError}` );
|
|
121
|
+
super( `CDS compilation failed (@sap/cds-compiler v${ meta.version() })\n${ firstError }` );
|
|
122
122
|
|
|
123
123
|
/** @since v4.0.0 */
|
|
124
124
|
this.code = 'ERR_CDS_COMPILATION_FAILURE';
|
|
@@ -153,8 +153,7 @@ class CompilationError extends Error {
|
|
|
153
153
|
if (this.messages) {
|
|
154
154
|
messages = messages.concat(this.messages
|
|
155
155
|
.filter(msg => msg.severity === 'Error')
|
|
156
|
-
.map( m => m.toString())
|
|
157
|
-
);
|
|
156
|
+
.map( m => m.toString()));
|
|
158
157
|
}
|
|
159
158
|
return messages.join('\n');
|
|
160
159
|
}
|
|
@@ -235,7 +234,7 @@ const severitySpecs = {
|
|
|
235
234
|
*/
|
|
236
235
|
function reclassifiedSeverity( msg, options, moduleName ) {
|
|
237
236
|
const spec = centralMessages[msg.messageId] || { severity: msg.severity, configurableFor: null, errorFor: null };
|
|
238
|
-
let severity = spec
|
|
237
|
+
let { severity } = spec;
|
|
239
238
|
|
|
240
239
|
if (spec.severity === 'Error') {
|
|
241
240
|
if (!isDowngradable(msg.messageId, moduleName, options))
|
|
@@ -430,7 +429,7 @@ function makeMessageFunction( model, options, _moduleName = null ) {
|
|
|
430
429
|
hasNewError = hasNewError || msg.severity === 'Error' &&
|
|
431
430
|
!(options.testMode && isDowngradable( msg.messageId, moduleName, options ));
|
|
432
431
|
if (!hasMessageArray)
|
|
433
|
-
console.error( messageString( msg ) );
|
|
432
|
+
console.error( messageString( msg ) ); // eslint-disable-line no-console
|
|
434
433
|
return msg;
|
|
435
434
|
}
|
|
436
435
|
|
|
@@ -500,7 +499,7 @@ function makeMessageFunction( model, options, _moduleName = null ) {
|
|
|
500
499
|
|
|
501
500
|
let semanticLocation = location[1] ? homeName( location[1], false ) : null;
|
|
502
501
|
if (location[2]) { // optional suffix, e.g. annotation
|
|
503
|
-
semanticLocation += `/${ (typeof location[2] === 'string') ? location[2]: homeName(location[2]) }`;
|
|
502
|
+
semanticLocation += `/${ (typeof location[2] === 'string') ? location[2] : homeName(location[2]) }`;
|
|
504
503
|
}
|
|
505
504
|
|
|
506
505
|
const definition = location[1] ? homeName( location[1], true ) : null;
|
|
@@ -564,9 +563,8 @@ function makeMessageFunction( model, options, _moduleName = null ) {
|
|
|
564
563
|
}
|
|
565
564
|
|
|
566
565
|
function throwWithError() {
|
|
567
|
-
if (hasNewError)
|
|
566
|
+
if (hasNewError)
|
|
568
567
|
throw new CompilationError(messages, options.attachValidNames && model);
|
|
569
|
-
}
|
|
570
568
|
}
|
|
571
569
|
|
|
572
570
|
/**
|
|
@@ -581,9 +579,8 @@ function makeMessageFunction( model, options, _moduleName = null ) {
|
|
|
581
579
|
if (!messages || !messages.length)
|
|
582
580
|
return;
|
|
583
581
|
const hasError = options.testMode ? hasNonDowngradableErrors : hasErrors;
|
|
584
|
-
if (hasError( messages, moduleName, options ))
|
|
582
|
+
if (hasError( messages, moduleName, options ))
|
|
585
583
|
throw new CompilationError(messages, options.attachValidNames && model);
|
|
586
|
-
}
|
|
587
584
|
}
|
|
588
585
|
|
|
589
586
|
/**
|
|
@@ -635,11 +632,10 @@ function makeMessageFunction( model, options, _moduleName = null ) {
|
|
|
635
632
|
}
|
|
636
633
|
|
|
637
634
|
/**
|
|
638
|
-
*
|
|
639
635
|
* Change the moduleName used for reclassifying messages.
|
|
640
636
|
* Needed for to.sql.migration + script
|
|
641
|
-
*
|
|
642
|
-
* @param {string} __moduleName
|
|
637
|
+
*
|
|
638
|
+
* @param {string} __moduleName
|
|
643
639
|
*/
|
|
644
640
|
function setModuleName( __moduleName ) {
|
|
645
641
|
moduleName = __moduleName;
|
|
@@ -654,8 +650,6 @@ function makeMessageFunction( model, options, _moduleName = null ) {
|
|
|
654
650
|
function setOptions( _options ) {
|
|
655
651
|
options = _options;
|
|
656
652
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
653
|
}
|
|
660
654
|
|
|
661
655
|
/**
|
|
@@ -789,9 +783,13 @@ const paramsTransform = {
|
|
|
789
783
|
// more complex convenience:
|
|
790
784
|
names: transformManyWith( quoted ),
|
|
791
785
|
number: quote.single, // number cited from source or expected in source
|
|
786
|
+
location: ({ line, col }) => `${ line }:${ col }`,
|
|
792
787
|
count: quote.direct,
|
|
793
788
|
line: quote.direct,
|
|
794
789
|
col: quote.direct,
|
|
790
|
+
literal: quote.direct,
|
|
791
|
+
n: quote.direct,
|
|
792
|
+
m: quote.direct,
|
|
795
793
|
value,
|
|
796
794
|
rawvalue: quote.single,
|
|
797
795
|
rawvalues: transformManyWith( quote.single ), // no 'double' quotes for strings
|
|
@@ -812,9 +810,9 @@ const paramsTransform = {
|
|
|
812
810
|
version: quote.single, // TODO delete: just use for OData $(VERSION), with version: 2.0
|
|
813
811
|
};
|
|
814
812
|
|
|
815
|
-
function asDelimitedId(id) {
|
|
813
|
+
function asDelimitedId( id ) {
|
|
816
814
|
// Same as in toCdl, but we don't want cyclic dependencies to toCdl.
|
|
817
|
-
return `![${id.replace(/]/g, ']]')}]`;
|
|
815
|
+
return `![${ id.replace(/]/g, ']]') }]`;
|
|
818
816
|
}
|
|
819
817
|
|
|
820
818
|
function anno( name ) {
|
|
@@ -912,9 +910,10 @@ function transformElementRef( arg ) {
|
|
|
912
910
|
((arg.scope === 'param' || arg.param) ? ':' : '') +
|
|
913
911
|
ref.map(
|
|
914
912
|
item => (typeof item !== 'string'
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
913
|
+
? `${ item.id }${ item.args ? '(…)' : '' }${ item.where ? '[…]' : '' }`
|
|
914
|
+
: item)
|
|
915
|
+
).join('.')
|
|
916
|
+
);
|
|
918
917
|
}
|
|
919
918
|
|
|
920
919
|
function transformArg( arg, r, args, texts ) {
|
|
@@ -936,7 +935,7 @@ function transformArg( arg, r, args, texts ) {
|
|
|
936
935
|
return quoted( arg.name );
|
|
937
936
|
const name = getArtifactName( arg );
|
|
938
937
|
const prop = [ 'element', 'param', 'action', 'alias' ].find( p => name[p] );
|
|
939
|
-
//if (!prop) throw Error()
|
|
938
|
+
// if (!prop) throw Error()
|
|
940
939
|
if (!prop || !texts[prop] )
|
|
941
940
|
return shortArtName( arg );
|
|
942
941
|
r['#'] = texts[name.$variant] && name.$variant || prop; // text variant (set by searchName)
|
|
@@ -1047,14 +1046,16 @@ function replaceInString( text, params ) {
|
|
|
1047
1046
|
*
|
|
1048
1047
|
* @returns {string}
|
|
1049
1048
|
*/
|
|
1050
|
-
function messageString( err,
|
|
1049
|
+
function messageString( err, config ) {
|
|
1051
1050
|
// backwards compatibility <v4
|
|
1052
1051
|
if (!config || typeof config === 'boolean' || arguments.length > 2) {
|
|
1053
1052
|
config = {
|
|
1053
|
+
/* eslint-disable prefer-rest-params */
|
|
1054
1054
|
normalizeFilename: arguments[1],
|
|
1055
1055
|
noMessageId: arguments[2],
|
|
1056
1056
|
noHome: arguments[3],
|
|
1057
1057
|
moduleForMarker: arguments[4],
|
|
1058
|
+
/* eslint-enable prefer-rest-params */
|
|
1058
1059
|
};
|
|
1059
1060
|
}
|
|
1060
1061
|
config.moduleForMarker ??= config.module; // v4.8.0 or earlier compatibility
|
|
@@ -1064,7 +1065,7 @@ function messageString( err, config ) {
|
|
|
1064
1065
|
const downgradable = severityChangeMarker(err, config);
|
|
1065
1066
|
// even with noHome, print err.home if the location is weak
|
|
1066
1067
|
const home = !err.home || config.noHome && err.$location?.endLine ? '' : ` (in ${ err.home })`;
|
|
1067
|
-
const msgId = (err.messageId && !config.noMessageId) ? `[${err.messageId}]` : '';
|
|
1068
|
+
const msgId = (err.messageId && !config.noMessageId) ? `[${ err.messageId }]` : '';
|
|
1068
1069
|
return `${ location }${ severity }${ downgradable }${ msgId }: ${ err.message }${ home }`;
|
|
1069
1070
|
}
|
|
1070
1071
|
|
|
@@ -1142,7 +1143,7 @@ function messageStringMultiline( err, config = {} ) {
|
|
|
1142
1143
|
const home = !err.home ? '' : (`at ${ err.home }`);
|
|
1143
1144
|
const severity = err.severity || 'Error';
|
|
1144
1145
|
const downgradable = severityChangeMarker(err, config);
|
|
1145
|
-
const msgId = (err.messageId && !config.noMessageId) ? `${downgradable}[${ err.messageId }${ explainHelp }]` : '';
|
|
1146
|
+
const msgId = (err.messageId && !config.noMessageId) ? `${ downgradable }[${ err.messageId }${ explainHelp }]` : '';
|
|
1146
1147
|
|
|
1147
1148
|
let location = '';
|
|
1148
1149
|
let context = '';
|
|
@@ -1152,7 +1153,7 @@ function messageStringMultiline( err, config = {} ) {
|
|
|
1152
1153
|
location += ', ';
|
|
1153
1154
|
context = _messageContext(err, config);
|
|
1154
1155
|
if (context !== '')
|
|
1155
|
-
context = `\n${context}`;
|
|
1156
|
+
context = `\n${ context }`;
|
|
1156
1157
|
}
|
|
1157
1158
|
else if (!home) {
|
|
1158
1159
|
return `${ colorTerm.severity(severity, severity + msgId) } ${ err.message }`;
|
|
@@ -1161,7 +1162,7 @@ function messageStringMultiline( err, config = {} ) {
|
|
|
1161
1162
|
const additionalIndent = err.$location ? `${ err.$location.endLine || err.$location.line || 1 }`.length : 1;
|
|
1162
1163
|
const lineSpacer = `\n ${ ' '.repeat( additionalIndent ) }|`;
|
|
1163
1164
|
|
|
1164
|
-
return `${ colorTerm.severity(severity, severity + msgId) }: ${ err.message }${ lineSpacer }\n ${ location }${ home }${context}`;
|
|
1165
|
+
return `${ colorTerm.severity(severity, severity + msgId) }: ${ err.message }${ lineSpacer }\n ${ location }${ home }${ context }`;
|
|
1165
1166
|
}
|
|
1166
1167
|
|
|
1167
1168
|
/**
|
|
@@ -1173,14 +1174,14 @@ function messageStringMultiline( err, config = {} ) {
|
|
|
1173
1174
|
* @return {number[]}
|
|
1174
1175
|
* @private
|
|
1175
1176
|
*/
|
|
1176
|
-
function _createSourceLineMap(source) {
|
|
1177
|
+
function _createSourceLineMap( source ) {
|
|
1177
1178
|
const newlines = [ 0 ];
|
|
1178
1179
|
|
|
1179
1180
|
const re = new RegExp(cdlNewLineRegEx, 'g');
|
|
1180
1181
|
let line;
|
|
1181
|
-
while((line = re.exec(source)) !== null)
|
|
1182
|
+
while ((line = re.exec(source)) !== null)
|
|
1182
1183
|
newlines.push(line.index + line[0].length);
|
|
1183
|
-
|
|
1184
|
+
|
|
1184
1185
|
newlines.push(source.length); // EOF marker
|
|
1185
1186
|
|
|
1186
1187
|
return newlines;
|
|
@@ -1252,7 +1253,7 @@ function _messageContext( err, config ) {
|
|
|
1252
1253
|
// print source line(s)
|
|
1253
1254
|
for (let line = startLine; line <= maxLine; line++) {
|
|
1254
1255
|
// Replaces tabs with 1 space
|
|
1255
|
-
let sourceCode = source.substring(sourceLines[line], sourceLines[line+1] || source.length).trimEnd();
|
|
1256
|
+
let sourceCode = source.substring(sourceLines[line], sourceLines[line + 1] || source.length).trimEnd();
|
|
1256
1257
|
sourceCode = sourceCode.replace(/\t/g, ' ');
|
|
1257
1258
|
if (sourceCode.length >= MAX_COL_LENGTH)
|
|
1258
1259
|
sourceCode = sourceCode.slice(0, MAX_COL_LENGTH);
|
|
@@ -1303,7 +1304,7 @@ function _messageContext( err, config ) {
|
|
|
1303
1304
|
*/
|
|
1304
1305
|
function messageContext( sourceLines, err, config ) {
|
|
1305
1306
|
const loc = err.$location;
|
|
1306
|
-
if (!loc || !loc.line|| !loc.file)
|
|
1307
|
+
if (!loc || !loc.line || !loc.file)
|
|
1307
1308
|
return '';
|
|
1308
1309
|
|
|
1309
1310
|
colorTerm.changeColorMode(config ? config.color : 'auto');
|
|
@@ -1323,8 +1324,8 @@ function compareMessage( a, b ) {
|
|
|
1323
1324
|
const aFile = a.$location && a.$location.file;
|
|
1324
1325
|
const bFile = b.$location && b.$location.file;
|
|
1325
1326
|
if (aFile && bFile) {
|
|
1326
|
-
const aEnd = a.$location.endLine && a.$location.endCol && a.$location || { endLine: Number.MAX_SAFE_INTEGER, endCol: Number.MAX_SAFE_INTEGER };
|
|
1327
|
-
const bEnd = b.$location.endLine && b.$location.endCol && b.$location || { endLine: Number.MAX_SAFE_INTEGER, endCol: Number.MAX_SAFE_INTEGER };
|
|
1327
|
+
const aEnd = a.$location.endLine && a.$location.endCol && a.$location || { endLine: Number.MAX_SAFE_INTEGER, endCol: Number.MAX_SAFE_INTEGER }; // eslint-disable-line @stylistic/js/max-len
|
|
1328
|
+
const bEnd = b.$location.endLine && b.$location.endCol && b.$location || { endLine: Number.MAX_SAFE_INTEGER, endCol: Number.MAX_SAFE_INTEGER }; // eslint-disable-line @stylistic/js/max-len
|
|
1328
1329
|
return ( c( aFile, bFile ) ||
|
|
1329
1330
|
c( a.$location.line, b.$location.line ) ||
|
|
1330
1331
|
c( a.$location.col, b.$location.col ) ||
|
|
@@ -1344,7 +1345,9 @@ function compareMessage( a, b ) {
|
|
|
1344
1345
|
return (b.messageId && b.messageId.startsWith( 'api-' )) ? 1 : -1;
|
|
1345
1346
|
|
|
1346
1347
|
function c( x, y ) {
|
|
1347
|
-
|
|
1348
|
+
if (x === y)
|
|
1349
|
+
return 0;
|
|
1350
|
+
return (x > y) ? 1 : -1;
|
|
1348
1351
|
}
|
|
1349
1352
|
}
|
|
1350
1353
|
|
|
@@ -1435,8 +1438,9 @@ function artName( art, omit ) {
|
|
|
1435
1438
|
const loc = art.location ? ` at ${ locationString( art.location ) }` : '';
|
|
1436
1439
|
throw new CompilerAssertion(
|
|
1437
1440
|
art.path
|
|
1438
|
-
? `No artifact for ${ art.path.map( i => i.id ).join( '.' )}${ loc }`
|
|
1439
|
-
: `No name found in ${ Object.keys( art ).join( '+' )}${ loc }`
|
|
1441
|
+
? `No artifact for ${ art.path.map( i => i.id ).join( '.' ) }${ loc }`
|
|
1442
|
+
: `No name found in ${ Object.keys( art ).join( '+' ) }${ loc }`
|
|
1443
|
+
);
|
|
1440
1444
|
}
|
|
1441
1445
|
|
|
1442
1446
|
const r = (name.absolute) ? [ quoted( name.absolute ) ] : [];
|
|
@@ -1451,7 +1455,7 @@ function artName( art, omit ) {
|
|
|
1451
1455
|
|
|
1452
1456
|
if (name.element != null && omit !== 'element') {
|
|
1453
1457
|
if (name.select != null && !art.$inferred)
|
|
1454
|
-
r.push(
|
|
1458
|
+
r.push( `column:${ quoted( name.element ) }` );
|
|
1455
1459
|
else if (art.kind === 'builtin')
|
|
1456
1460
|
return `$var:${ quoted( name.element ) }`;
|
|
1457
1461
|
else
|
|
@@ -1484,20 +1488,25 @@ function homeName( art, absoluteOnly ) {
|
|
|
1484
1488
|
return homeName( art._user, absoluteOnly );
|
|
1485
1489
|
if (art._outer) { // in items property, or annotation with path
|
|
1486
1490
|
const outer = homeName( art._outer, absoluteOnly );
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1491
|
+
if (art.kind === '$annotation') // eslint-disable-next-line sonarjs/no-nested-template-literals
|
|
1492
|
+
return `${ outer }/${ quoted( `@${ art.name.id }` ) }`;
|
|
1493
|
+
return outer;
|
|
1490
1494
|
}
|
|
1491
|
-
else if (art.kind === 'source' || !art.name) // error reported in parser or on source level
|
|
1495
|
+
else if (art.kind === 'source' || !art.name) { // error reported in parser or on source level
|
|
1492
1496
|
return null;
|
|
1493
|
-
|
|
1497
|
+
}
|
|
1498
|
+
else if (art.kind === 'using') {
|
|
1494
1499
|
return `using:${ quoted( art.name.id ) }`;
|
|
1495
|
-
|
|
1500
|
+
}
|
|
1501
|
+
else if (art.kind === 'extend' || art.kind === 'annotate') {
|
|
1496
1502
|
return !absoluteOnly && homeNameForExtend( art );
|
|
1497
|
-
|
|
1503
|
+
}
|
|
1504
|
+
else if (!art.kind) { // annotation assignments are not really supported
|
|
1498
1505
|
return (absoluteOnly) ? art.name.id : quoted( `@${ art.name.id }` );
|
|
1499
|
-
|
|
1506
|
+
}
|
|
1507
|
+
else if (art.name._artifact) { // block, extend, annotate
|
|
1500
1508
|
return homeName( art.name._artifact, absoluteOnly ); // use corresponding definition
|
|
1509
|
+
}
|
|
1501
1510
|
let main = art._main || art;
|
|
1502
1511
|
while (main._outer) // anonymous aspect
|
|
1503
1512
|
main = main._outer._main || main._outer; // w/o `_main` if wrongly in `type`
|
|
@@ -1591,7 +1600,7 @@ function constructSemanticLocationFromCsnPath( model, options, csnPath ) {
|
|
|
1591
1600
|
let step = csnPath[index];
|
|
1592
1601
|
let currentThing = model?.[step];
|
|
1593
1602
|
|
|
1594
|
-
function next(steps = 1) {
|
|
1603
|
+
function next( steps = 1 ) {
|
|
1595
1604
|
for (; steps > 0; --steps) {
|
|
1596
1605
|
++index;
|
|
1597
1606
|
step = csnPath[index];
|
|
@@ -1599,7 +1608,7 @@ function constructSemanticLocationFromCsnPath( model, options, csnPath ) {
|
|
|
1599
1608
|
}
|
|
1600
1609
|
}
|
|
1601
1610
|
|
|
1602
|
-
function peek(steps = 1) {
|
|
1611
|
+
function peek( steps = 1 ) {
|
|
1603
1612
|
return csnPath[index + steps];
|
|
1604
1613
|
}
|
|
1605
1614
|
|
|
@@ -1674,13 +1683,12 @@ function constructSemanticLocationFromCsnPath( model, options, csnPath ) {
|
|
|
1674
1683
|
else if (step === 'cast') {
|
|
1675
1684
|
// To shorten the location, only print 'cast' if it's not a
|
|
1676
1685
|
// redirection target.
|
|
1677
|
-
if (csnPath[index+1] !== 'on' && csnPath[index+1] !== 'target')
|
|
1686
|
+
if (csnPath[index + 1] !== 'on' && csnPath[index + 1] !== 'target')
|
|
1678
1687
|
result += '/cast';
|
|
1679
|
-
}
|
|
1680
1688
|
}
|
|
1681
1689
|
// @ts-ignore
|
|
1682
1690
|
else if (queryPropsLast.includes(step)) {
|
|
1683
|
-
result +=
|
|
1691
|
+
result += `/${ step }`;
|
|
1684
1692
|
break; // always last step
|
|
1685
1693
|
}
|
|
1686
1694
|
else if (step === 'on') {
|
|
@@ -1689,7 +1697,7 @@ function constructSemanticLocationFromCsnPath( model, options, csnPath ) {
|
|
|
1689
1697
|
}
|
|
1690
1698
|
else if (step === 'target') {
|
|
1691
1699
|
if (currentThing)
|
|
1692
|
-
result +=
|
|
1700
|
+
result += `/target:${ _quoted(currentThing) }`;
|
|
1693
1701
|
else
|
|
1694
1702
|
result += '/target';
|
|
1695
1703
|
break;
|
|
@@ -1782,13 +1790,14 @@ function constructSemanticLocationFromCsnPath( model, options, csnPath ) {
|
|
|
1782
1790
|
// the last SELECT, e.g. "columns".
|
|
1783
1791
|
for (let j = csnPath.length - 1; j > index; --j) {
|
|
1784
1792
|
// @ts-ignore
|
|
1785
|
-
if (csnPath[j] === 'SELECT' && !csnDictionaries.includes(csnPath[j-1])) {
|
|
1793
|
+
if (csnPath[j] === 'SELECT' && !csnDictionaries.includes(csnPath[j - 1])) {
|
|
1786
1794
|
next(j - index); // found last SELECT
|
|
1787
1795
|
break;
|
|
1788
1796
|
}
|
|
1789
1797
|
}
|
|
1790
1798
|
result += `/select:${ selectDepth }`;
|
|
1791
|
-
}
|
|
1799
|
+
}
|
|
1800
|
+
else {
|
|
1792
1801
|
result += '/select';
|
|
1793
1802
|
}
|
|
1794
1803
|
}
|
|
@@ -1815,7 +1824,8 @@ function constructSemanticLocationFromCsnPath( model, options, csnPath ) {
|
|
|
1815
1824
|
if (peek() === 'expand' || peek() === 'inline') {
|
|
1816
1825
|
next(); // skip expand/inline
|
|
1817
1826
|
next(); // go to next column
|
|
1818
|
-
}
|
|
1827
|
+
}
|
|
1828
|
+
else {
|
|
1819
1829
|
break;
|
|
1820
1830
|
}
|
|
1821
1831
|
} while (index < csnPath.length);
|
|
@@ -1823,7 +1833,7 @@ function constructSemanticLocationFromCsnPath( model, options, csnPath ) {
|
|
|
1823
1833
|
if (elementHierarchy.length > 0)
|
|
1824
1834
|
result += `/column:${ _quoted(elementHierarchy.join('.')) }`;
|
|
1825
1835
|
}
|
|
1826
|
-
else if(step === 'args') {
|
|
1836
|
+
else if (step === 'args') {
|
|
1827
1837
|
// Should only be reached for cases, where no SELECT in a union is picked.
|
|
1828
1838
|
next(); // skip index
|
|
1829
1839
|
}
|
|
@@ -1868,10 +1878,10 @@ function queryDepthForMessage( csnPath, model, view ) {
|
|
|
1868
1878
|
return 0;
|
|
1869
1879
|
}
|
|
1870
1880
|
|
|
1871
|
-
function sanitizeCsnPath(csnPath) {
|
|
1881
|
+
function sanitizeCsnPath( csnPath ) {
|
|
1872
1882
|
for (const step of csnPath) {
|
|
1873
1883
|
if (typeof step !== 'string' && typeof step !== 'number')
|
|
1874
|
-
throw new CompilerAssertion(`Found CSN path step that is neither string nor number: ${step} ${ JSON.stringify(csnPath) }`)
|
|
1884
|
+
throw new CompilerAssertion(`Found CSN path step that is neither string nor number: ${ step } ${ JSON.stringify(csnPath) }`);
|
|
1875
1885
|
}
|
|
1876
1886
|
}
|
|
1877
1887
|
|
package/lib/base/model.js
CHANGED
|
@@ -38,9 +38,9 @@ const availableDeprecatedFlags = {
|
|
|
38
38
|
eagerPersistenceForGeneratedEntities: true,
|
|
39
39
|
noKeyPropagationWithExpansions: true,
|
|
40
40
|
ignoreSpecifiedQueryElements: true,
|
|
41
|
-
}
|
|
41
|
+
};
|
|
42
42
|
|
|
43
|
-
const
|
|
43
|
+
const oldDeprecatedFlagsV2 = [
|
|
44
44
|
'createLocalizedViews',
|
|
45
45
|
// 'downgradableErrors', // re-added in v4
|
|
46
46
|
'generatedEntityNameWithUnderscore',
|
|
@@ -117,7 +117,7 @@ function checkRemovedDeprecatedFlags( options, { error } ) {
|
|
|
117
117
|
return;
|
|
118
118
|
|
|
119
119
|
forEach(options.deprecated, (key, val) => {
|
|
120
|
-
if (val &&
|
|
120
|
+
if (val && oldDeprecatedFlagsV2.includes(key)) {
|
|
121
121
|
error('api-invalid-deprecated', null, { name: key },
|
|
122
122
|
'Deprecated flag $(NAME) has been removed in CDS compiler v3');
|
|
123
123
|
}
|
package/lib/base/node-helpers.js
CHANGED
|
@@ -2,16 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
class PromiseAllError extends Error {
|
|
6
|
+
constructor(subs, ...args) {
|
|
7
|
+
super(...args);
|
|
8
|
+
this.valuesOrErrors = subs;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Version of Promise.all() which does not reject immediately, i.e. after one
|
|
14
|
+
* promise rejects, the others are still resolved.
|
|
15
|
+
*
|
|
16
|
+
* If rejected, we reject with a PromiseAllError containing all promise values
|
|
17
|
+
* (is Error in case of rejection). Compare that with Promise.all() which
|
|
18
|
+
* rejects with the result of the first rejected promise.
|
|
19
|
+
*
|
|
20
|
+
* This function only works as intended if no promise in `promises` fulfill
|
|
21
|
+
* with a value which is an instance of Error.
|
|
22
|
+
*/
|
|
15
23
|
function promiseAllDoNotRejectImmediately( promises ) {
|
|
16
24
|
return Promise.all( promises.map( p => p.catch(e => e) ) )
|
|
17
25
|
.then( values => (values.some(e => e instanceof Error)
|
|
@@ -21,13 +29,6 @@ function promiseAllDoNotRejectImmediately( promises ) {
|
|
|
21
29
|
: values));
|
|
22
30
|
}
|
|
23
31
|
|
|
24
|
-
class PromiseAllError extends Error {
|
|
25
|
-
constructor(subs, ...args) {
|
|
26
|
-
super(...args);
|
|
27
|
-
this.valuesOrErrors = subs;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
32
|
module.exports = {
|
|
32
33
|
promiseAllDoNotRejectImmediately,
|
|
33
34
|
};
|
|
@@ -369,24 +369,21 @@ function createOptionProcessor() {
|
|
|
369
369
|
splitSingleLetterOption(argv, i); // `-ab` -> `-a -b`
|
|
370
370
|
i += processOption(i);
|
|
371
371
|
}
|
|
372
|
-
else {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
result.command = optionProcessor.commands[arg].longName;
|
|
378
|
-
result.options[result.command] = {};
|
|
379
|
-
}
|
|
380
|
-
else {
|
|
381
|
-
// Not found as command, take as arg and stop looking for commands
|
|
382
|
-
processPositionalArgument(arg);
|
|
383
|
-
result.command = null;
|
|
384
|
-
}
|
|
372
|
+
else if (result.command === undefined) { // Command or arg
|
|
373
|
+
if (optionProcessor.commands[arg]) {
|
|
374
|
+
// Found as command
|
|
375
|
+
result.command = optionProcessor.commands[arg].longName;
|
|
376
|
+
result.options[result.command] = {};
|
|
385
377
|
}
|
|
386
378
|
else {
|
|
379
|
+
// Not found as command, take as arg and stop looking for commands
|
|
387
380
|
processPositionalArgument(arg);
|
|
381
|
+
result.command = null;
|
|
388
382
|
}
|
|
389
383
|
}
|
|
384
|
+
else {
|
|
385
|
+
processPositionalArgument(arg);
|
|
386
|
+
}
|
|
390
387
|
}
|
|
391
388
|
// Avoid 'toXyz: {}' for command without options
|
|
392
389
|
if (result.command && Object.keys(result.options[result.command]).length === 0)
|
|
@@ -414,7 +411,9 @@ function createOptionProcessor() {
|
|
|
414
411
|
*/
|
|
415
412
|
function getCurrentPositionArguments() {
|
|
416
413
|
const cmd = optionProcessor.commands[result.command];
|
|
417
|
-
return ( cmd && cmd.positionalArguments && cmd.positionalArguments.length )
|
|
414
|
+
return ( cmd && cmd.positionalArguments && cmd.positionalArguments.length )
|
|
415
|
+
? cmd.positionalArguments
|
|
416
|
+
: optionProcessor.positionalArguments;
|
|
418
417
|
}
|
|
419
418
|
|
|
420
419
|
function processPositionalArgument( argumentValue ) {
|
package/lib/base/shuffle.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
|
+
// Return shuffle functions using pseudo random functions
|
|
3
4
|
// By <https://github.com/bryc/code/blob/c97a26ad27a9f9d4f48cd3307fd8ee6f1772d4eb/jshash/PRNGs.md>:
|
|
4
5
|
|
|
6
|
+
/* eslint no-bitwise: 0, operator-assignment: 0 */
|
|
7
|
+
|
|
5
8
|
// The random seed must be an integer between 1 and 4294967296 (= 2**32),
|
|
6
9
|
// otherwise no shuffling takes place.
|
|
7
10
|
function shuffleGen( seed ) {
|
|
@@ -13,7 +13,7 @@ function checkAnnotationExpression( member, _memberName, _prop, path ) {
|
|
|
13
13
|
const { art, scope } = this.csnUtils.inspectRef(refPath);
|
|
14
14
|
if (scope !== '$magic' && art) {
|
|
15
15
|
const ft = this.csnUtils.getFinalTypeInfo(art.type);
|
|
16
|
-
if (!isBuiltinType(ft?.type))
|
|
16
|
+
if (!isBuiltinType(ft?.type) && !ft?.items)
|
|
17
17
|
this.error('odata-anno-xpr-ref', refPath, { anno, elemref, '#': 'flatten_builtin_type' });
|
|
18
18
|
}
|
|
19
19
|
},
|
|
@@ -485,7 +485,7 @@ function assertConsistency( model, stage ) {
|
|
|
485
485
|
'struct', 'array', 'enum', 'null', 'token',
|
|
486
486
|
],
|
|
487
487
|
},
|
|
488
|
-
sym: { requires: [ 'location', 'id' ], optional: [ '$delimited' ] },
|
|
488
|
+
sym: { requires: [ 'location', 'id' ], optional: [ '$delimited', '_artifact' ] },
|
|
489
489
|
val: {
|
|
490
490
|
test: isVal, // the following for array/struct value
|
|
491
491
|
requires: [ 'location' ],
|
package/lib/compiler/builtins.js
CHANGED
|
@@ -222,9 +222,10 @@ const dateRegEx = /^(-?\d{4})-(\d{1,2})-(\d{1,2})$/;
|
|
|
222
222
|
// YYYY - MM - dd
|
|
223
223
|
const timeRegEx = /^T?(\d{1,2}):(\d{1,2})(?::(\d{1,2}))?(?:Z|[+-]\d{2}(?::\d{2})?)?$/;
|
|
224
224
|
// T HH : mm : ss TZD
|
|
225
|
-
// eslint-disable-next-line @stylistic/js/max-len
|
|
225
|
+
// eslint-disable-next-line @stylistic/js/max-len, sonarjs/regex-complexity
|
|
226
226
|
const timestampRegEx = /^(-?\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2})(?::(\d{2})(\.\d{1,7})?)?(?:Z|[+-]\d{2}(?::\d{2})?)?$/;
|
|
227
227
|
// YYYY - MM - dd T HH : mm : ss . fraction TZD
|
|
228
|
+
// eslint-disable-next-line sonarjs/regex-complexity
|
|
228
229
|
const numberRegEx = /^[ \t]*[-+]?(\d+(\.\d*)?|\.\d+)(e[-+]?\d+)?[ \t]*$/i;
|
|
229
230
|
|
|
230
231
|
/**
|
package/lib/compiler/extend.js
CHANGED
|
@@ -487,14 +487,24 @@ function extend( model ) {
|
|
|
487
487
|
return anno;
|
|
488
488
|
const hasBase = previousAnno?.literal === 'array';
|
|
489
489
|
if (!previousAnno) {
|
|
490
|
-
const
|
|
491
|
-
message( 'anno-unexpected-ellipsis', [
|
|
492
|
-
previousAnno = {
|
|
490
|
+
const location = firstEllipsis.location || anno.name.location;
|
|
491
|
+
message( 'anno-unexpected-ellipsis', [ location, art ], { code: '...' } );
|
|
492
|
+
previousAnno = {
|
|
493
|
+
val: [],
|
|
494
|
+
literal: 'array',
|
|
495
|
+
name: { id: annoName.slice( 1 ) },
|
|
496
|
+
location,
|
|
497
|
+
};
|
|
493
498
|
}
|
|
494
499
|
else if (previousAnno.literal !== 'array') {
|
|
495
500
|
// TODO: If we introduce sub-messages, point to the non-array base value.
|
|
496
501
|
error( 'anno-mismatched-ellipsis', [ anno.name.location, art ], { code: '...' } );
|
|
497
|
-
previousAnno = {
|
|
502
|
+
previousAnno = {
|
|
503
|
+
val: [],
|
|
504
|
+
literal: 'array',
|
|
505
|
+
name: previousAnno.name,
|
|
506
|
+
location: previousAnno.location,
|
|
507
|
+
};
|
|
498
508
|
}
|
|
499
509
|
const previousValue = previousAnno.val;
|
|
500
510
|
let prevPos = 0;
|
|
@@ -522,7 +532,12 @@ function extend( model ) {
|
|
|
522
532
|
}
|
|
523
533
|
}
|
|
524
534
|
// console.log('TP:',previousValue.map(se),anno.val.map(se),'->',result.map(se))
|
|
525
|
-
return {
|
|
535
|
+
return {
|
|
536
|
+
val: result,
|
|
537
|
+
literal: 'array',
|
|
538
|
+
name: previousAnno.name,
|
|
539
|
+
location: previousAnno.location,
|
|
540
|
+
};
|
|
526
541
|
}
|
|
527
542
|
// function se(a) { return a.upTo ? [a.val,a.upTo.val] : a.val ; }
|
|
528
543
|
|