@sap/cds-compiler 6.9.3 → 7.0.1
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 +76 -2
- package/bin/cdsc.js +4 -33
- package/doc/IncompatibleChanges_v7.md +639 -0
- package/lib/api/main.js +4 -56
- package/lib/api/options.js +5 -15
- package/lib/api/validate.js +1 -0
- package/lib/base/builtins.js +1 -2
- package/lib/base/csnRefs.js +2 -6
- package/lib/base/message-registry.js +82 -76
- package/lib/base/messages.js +8 -5
- package/lib/base/optionProcessor.js +2 -72
- package/lib/base/specialOptions.js +20 -17
- package/lib/checks/defaultValues.js +1 -39
- package/lib/checks/hasPersistedElements.js +19 -3
- package/lib/checks/parameters.js +0 -34
- package/lib/checks/selectItems.js +2 -38
- package/lib/checks/typeParameters.js +162 -0
- package/lib/checks/validator.js +5 -8
- package/lib/compiler/assert-consistency.js +19 -5
- package/lib/compiler/checks.js +47 -43
- package/lib/compiler/define.js +6 -6
- package/lib/compiler/extend.js +102 -111
- package/lib/compiler/generate.js +4 -8
- package/lib/compiler/populate.js +4 -7
- package/lib/compiler/propagator.js +9 -9
- package/lib/compiler/resolve.js +205 -7
- package/lib/compiler/shared.js +76 -82
- package/lib/compiler/tweak-assocs.js +102 -22
- package/lib/compiler/utils.js +57 -12
- package/lib/compiler/xpr-rewrite.js +2 -15
- package/lib/edm/annotations/edmJson.js +14 -10
- package/lib/edm/annotations/genericTranslation.js +3 -1
- package/lib/edm/annotations/preprocessAnnotations.js +9 -26
- package/lib/edm/csn2edm.js +27 -20
- package/lib/edm/edmUtils.js +25 -0
- package/lib/gen/CdlGrammar.checksum +1 -1
- package/lib/gen/CdlParser.js +2237 -2241
- package/lib/gen/Dictionary.json +17 -2
- package/lib/json/from-csn.js +67 -52
- package/lib/json/to-csn.js +28 -25
- package/lib/language/textUtils.js +0 -13
- package/lib/main.d.ts +22 -59
- package/lib/main.js +1 -1
- package/lib/model/csnUtils.js +9 -8
- package/lib/parsers/AstBuildingParser.js +45 -55
- package/lib/parsers/Lexer.js +2 -0
- package/lib/parsers/identifiers.js +0 -9
- package/lib/render/toCdl.js +41 -40
- package/lib/render/toSql.js +8 -1
- package/lib/render/utils/common.js +1 -1
- package/lib/render/utils/sql.js +2 -3
- package/lib/tool-lib/enrichCsn.js +1 -2
- package/lib/transform/db/applyTransformations.js +7 -5
- package/lib/transform/db/assertUnique.js +8 -51
- package/lib/transform/db/associations.js +1 -1
- package/lib/transform/db/cdsPersistence.js +1 -15
- package/lib/transform/db/expansion.js +9 -12
- package/lib/transform/db/flattening.js +1 -1
- package/lib/transform/db/groupByOrderBy.js +0 -16
- package/lib/transform/db/views.js +57 -161
- package/lib/transform/draft/db.js +2 -2
- package/lib/transform/forOdata.js +25 -14
- package/lib/transform/forRelationalDB.js +93 -301
- package/lib/transform/localized.js +33 -102
- package/lib/transform/odata/flattening.js +11 -2
- package/lib/transform/transformUtils.js +25 -3
- package/lib/transform/universalCsn/universalCsnEnricher.js +1 -2
- package/package.json +2 -2
- package/lib/render/toHdbcds.js +0 -1810
|
@@ -110,6 +110,7 @@ function assertConsistency( model, stage ) {
|
|
|
110
110
|
'$functions',
|
|
111
111
|
'$assert',
|
|
112
112
|
'_sortedSources',
|
|
113
|
+
'_associations', // backlink associations
|
|
113
114
|
],
|
|
114
115
|
},
|
|
115
116
|
':parser': { // top-level from parser
|
|
@@ -268,6 +269,7 @@ function assertConsistency( model, stage ) {
|
|
|
268
269
|
also: [ false ],
|
|
269
270
|
},
|
|
270
271
|
$keysNavigation: { kind: true, test: TODO },
|
|
272
|
+
$backlink: { kind: true, test: TODO },
|
|
271
273
|
$filtered: { kind: true, inherits: 'value' }, // for assoc+filter
|
|
272
274
|
$enclosed: { kind: true, inherits: 'value' }, // for comp+filter
|
|
273
275
|
params: { kind: true, inherits: 'definitions' },
|
|
@@ -375,7 +377,7 @@ function assertConsistency( model, stage ) {
|
|
|
375
377
|
requires: [ 'location' ],
|
|
376
378
|
optional: [
|
|
377
379
|
'path', 'elements', '_outer', '_parent', '_main', '_block', 'kind',
|
|
378
|
-
'scope', '_artifact', '$inferred', '$expand', '$inCycle',
|
|
380
|
+
'scope', '_artifact', '$inferred', '$expand', '$inCycle', '$backlink',
|
|
379
381
|
'$tableAliases', '_$next',
|
|
380
382
|
'_origin', '_effectiveType', '$effectiveSeqNo', '_extensions', '$contains',
|
|
381
383
|
],
|
|
@@ -429,7 +431,7 @@ function assertConsistency( model, stage ) {
|
|
|
429
431
|
kind: [ 'entity', 'view', 'type', 'aspect' ],
|
|
430
432
|
test: isString, // CSN parser should check for 'entity', 'view', 'projection'
|
|
431
433
|
},
|
|
432
|
-
$tokenTexts: {
|
|
434
|
+
$tokenTexts: { // TODO: rename to $isExpression
|
|
433
435
|
parser: true,
|
|
434
436
|
test: isStringOrBool,
|
|
435
437
|
},
|
|
@@ -498,7 +500,7 @@ function assertConsistency( model, stage ) {
|
|
|
498
500
|
'literal', 'val', 'sym', 'struct', 'variant', 'path', 'name', '$duplicates', 'upTo',
|
|
499
501
|
// expressions as annotation values
|
|
500
502
|
'$tokenTexts', 'op', 'args', 'func', '_artifact', 'type', '$typeArgs',
|
|
501
|
-
'scale', 'srid', 'length', 'precision', 'scope', '$parens',
|
|
503
|
+
'scale', 'srid', 'length', 'precision', 'scope', '$parens', '$errorReported',
|
|
502
504
|
'_block', '_outer', // for annotation assignments
|
|
503
505
|
],
|
|
504
506
|
// TODO: restrict path to #simplePath
|
|
@@ -567,9 +569,20 @@ function assertConsistency( model, stage ) {
|
|
|
567
569
|
expectedKind: { kind: [ 'extend' ], test: locationVal( isString ) },
|
|
568
570
|
virtual: { kind: true, test: locationVal() },
|
|
569
571
|
key: { kind: true, test: locationVal(), also: [ null, undefined ] },
|
|
570
|
-
masked: { kind: true, test: locationVal() },
|
|
571
572
|
notNull: { kind: true, test: locationVal() },
|
|
572
|
-
includes: {
|
|
573
|
+
includes: {
|
|
574
|
+
kind: true,
|
|
575
|
+
test: isArray(),
|
|
576
|
+
inherits: 'type',
|
|
577
|
+
optional: [
|
|
578
|
+
'path', 'scope', '_artifact', '$inferred', '$postponeInclude',
|
|
579
|
+
],
|
|
580
|
+
},
|
|
581
|
+
$postponeInclude: {
|
|
582
|
+
kind: true,
|
|
583
|
+
parser: true,
|
|
584
|
+
test: isNumber,
|
|
585
|
+
},
|
|
573
586
|
returns: {
|
|
574
587
|
kind: [ 'action', 'function' ],
|
|
575
588
|
requires: [ 'kind', 'location' ],
|
|
@@ -677,6 +690,7 @@ function assertConsistency( model, stage ) {
|
|
|
677
690
|
_projections: { kind: true, test: TODO },
|
|
678
691
|
_complexProjections: { kind: true, test: TODO }, // for projected paths with filters
|
|
679
692
|
_entities: { test: TODO },
|
|
693
|
+
_associations: { test: TODO },
|
|
680
694
|
$compositionTargets: { test: isDictionary( isBoolean ) },
|
|
681
695
|
$collectedExtensions: { test: TODO },
|
|
682
696
|
_upperAspects: { kind: [ 'type', 'entity' ], test: isArray( TODO ) },
|
package/lib/compiler/checks.js
CHANGED
|
@@ -565,7 +565,8 @@ function check( model ) {
|
|
|
565
565
|
}
|
|
566
566
|
|
|
567
567
|
function checkDefaultValue( art ) {
|
|
568
|
-
|
|
568
|
+
const effective = art._effectiveType;
|
|
569
|
+
if (!effective)
|
|
569
570
|
return;
|
|
570
571
|
if (art.kind !== 'element' && art.kind !== 'type' && art.kind !== 'param')
|
|
571
572
|
return;
|
|
@@ -590,21 +591,37 @@ function check( model ) {
|
|
|
590
591
|
}
|
|
591
592
|
}
|
|
592
593
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
594
|
+
if (effective.elements) {
|
|
595
|
+
const kind = art.type?._artifact?.kind;
|
|
596
|
+
const isEntity = (kind === 'entity' || kind === '$self');
|
|
597
|
+
if (isEntity || Object.keys( effective.elements ).length !== 1) {
|
|
598
|
+
message( 'type-unexpected-default-struct', [ defaultValue.location, art ], {
|
|
599
|
+
'#': (isEntity ? kind : art.kind), keyword: 'default',
|
|
600
|
+
}, {
|
|
601
|
+
std: 'Unexpected $(KEYWORD) for a structure',
|
|
602
|
+
// eslint-disable-next-line @stylistic/max-len
|
|
603
|
+
param: 'Unexpected $(KEYWORD) for a structured parameter with not exactly one sub element',
|
|
604
|
+
// eslint-disable-next-line @stylistic/max-len
|
|
605
|
+
type: 'Unexpected $(KEYWORD) for a structured type definition with not exactly one element',
|
|
606
|
+
// eslint-disable-next-line @stylistic/max-len
|
|
607
|
+
element: 'Unexpected $(KEYWORD) for a structured element with not exactly one sub element',
|
|
608
|
+
$self: 'Unexpected $(KEYWORD) for a binding parameter',
|
|
609
|
+
entity: 'Unexpected $(KEYWORD) for an entity-typed parameter',
|
|
610
|
+
} );
|
|
611
|
+
}
|
|
598
612
|
}
|
|
599
|
-
else if (
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
'#':
|
|
613
|
+
else if (effective.items) {
|
|
614
|
+
const kind = art.items?.type?._artifact?.kind;
|
|
615
|
+
message( 'type-unexpected-default-array', [ defaultValue.location, art ], {
|
|
616
|
+
'#': (kind === '$self' ? kind : 'std'), keyword: 'default',
|
|
603
617
|
}, {
|
|
604
|
-
std: 'Unexpected $(KEYWORD) for
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
618
|
+
std: 'Unexpected $(KEYWORD) for an array',
|
|
619
|
+
$self: 'Unexpected $(KEYWORD) for a binding parameter',
|
|
620
|
+
} );
|
|
621
|
+
}
|
|
622
|
+
else if (effective.name.id === 'cds.Map') {
|
|
623
|
+
error( 'type-unexpected-default', [ defaultValue.location, art ], {
|
|
624
|
+
'#': 'map', keyword: 'default', type: 'cds.Map',
|
|
608
625
|
} );
|
|
609
626
|
}
|
|
610
627
|
}
|
|
@@ -1008,30 +1025,11 @@ function check( model ) {
|
|
|
1008
1025
|
return false;
|
|
1009
1026
|
}
|
|
1010
1027
|
|
|
1011
|
-
/**
|
|
1012
|
-
* Returns true if the given annotation accepts expressions as values.
|
|
1013
|
-
*
|
|
1014
|
-
* @param {object} anno
|
|
1015
|
-
* @param {XSN.Artifact} art
|
|
1016
|
-
* @returns {boolean}
|
|
1017
|
-
*/
|
|
1018
|
-
function checkAnnotationAcceptsExpressions( anno, art ) {
|
|
1019
|
-
const name = anno.name?.id;
|
|
1020
|
-
if (!name)
|
|
1021
|
-
return true;
|
|
1022
|
-
if (!propagationRules[`@${ name }`] || acceptsExprValues[`@${ name }`])
|
|
1023
|
-
return true;
|
|
1024
|
-
error( 'anno-unexpected-expr', [ anno.location, art ], { anno: name },
|
|
1025
|
-
'Unexpected expression as value for $(ANNO)' );
|
|
1026
|
-
return false;
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
1028
|
function checkAnnotationAssignment1( art, anno ) {
|
|
1030
1029
|
const name = anno.name?.id;
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
}
|
|
1030
|
+
const forbid = name && propagationRules[`@${ name }`] &&
|
|
1031
|
+
!acceptsExprValues[`@${ name }`];
|
|
1032
|
+
checkAnnotationExpressions( anno, art, forbid && name );
|
|
1035
1033
|
|
|
1036
1034
|
// Has been slightly adapted for model.vocabularies but comments need to be
|
|
1037
1035
|
// adapted, etc.
|
|
@@ -1142,16 +1140,22 @@ function check( model ) {
|
|
|
1142
1140
|
/**
|
|
1143
1141
|
* Check the expressions inside annotations.
|
|
1144
1142
|
*/
|
|
1145
|
-
function checkAnnotationExpressions( anno, art ) {
|
|
1146
|
-
if (anno.$tokenTexts) {
|
|
1147
|
-
|
|
1143
|
+
function checkAnnotationExpressions( anno, art, forbid ) {
|
|
1144
|
+
if (!anno.sym && anno.$tokenTexts) {
|
|
1145
|
+
if (forbid) {
|
|
1146
|
+
error( 'anno-unexpected-expr', [ anno.location, art ], { anno: forbid },
|
|
1147
|
+
'Unexpected expression as value for $(ANNO)' );
|
|
1148
|
+
}
|
|
1149
|
+
else {
|
|
1150
|
+
checkGenericExpression( anno, art, null, 'anno' );
|
|
1151
|
+
}
|
|
1148
1152
|
}
|
|
1149
1153
|
else if (anno.literal === 'array') {
|
|
1150
|
-
anno.val.forEach( val => checkAnnotationExpressions( val, art ) );
|
|
1154
|
+
anno.val.forEach( val => checkAnnotationExpressions( val, art, forbid ) );
|
|
1151
1155
|
}
|
|
1152
1156
|
else if (anno.literal === 'struct') {
|
|
1153
1157
|
const struct = Object.values(anno.struct);
|
|
1154
|
-
struct.forEach(val => checkAnnotationExpressions( val, art ));
|
|
1158
|
+
struct.forEach(val => checkAnnotationExpressions( val, art, forbid ));
|
|
1155
1159
|
}
|
|
1156
1160
|
}
|
|
1157
1161
|
|
|
@@ -1246,8 +1250,8 @@ function check( model ) {
|
|
|
1246
1250
|
if (value.literal === 'enum') {
|
|
1247
1251
|
if (expectedEnum) {
|
|
1248
1252
|
// Enum symbol provided and expected
|
|
1249
|
-
if (!expectedEnum[value.sym.id]) {
|
|
1250
|
-
// ... but no such constant
|
|
1253
|
+
if (!expectedEnum[value.sym.id] && value.sym._artifact === undefined) {
|
|
1254
|
+
// ... but no such constant and not yet reported
|
|
1251
1255
|
warning( null, loc, { id: `#${ value.sym.id }`, anno }, 'Enum symbol $(ID) not found in enum for annotation $(ANNO)' );
|
|
1252
1256
|
}
|
|
1253
1257
|
}
|
package/lib/compiler/define.js
CHANGED
|
@@ -213,9 +213,9 @@ function define( model ) {
|
|
|
213
213
|
addI18nBlocks(); // TODO: part of extend.js?
|
|
214
214
|
|
|
215
215
|
const { $self } = model.definitions;
|
|
216
|
-
if ($self && $self.kind !== 'namespace') {
|
|
217
|
-
|
|
218
|
-
|
|
216
|
+
if ($self && $self.kind !== 'namespace') {
|
|
217
|
+
error( 'name-deprecated-$self', [ $self.name.location, $self ], { name: '$self' },
|
|
218
|
+
'Do not use $(NAME) as name for an artifact definition' );
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
221
|
|
|
@@ -279,7 +279,7 @@ function define( model ) {
|
|
|
279
279
|
|
|
280
280
|
function addMainArtifact( art, block, prefix ) {
|
|
281
281
|
setLink( art, '_block', block );
|
|
282
|
-
initExprAnnoBlock( art, block );
|
|
282
|
+
initExprAnnoBlock( art, block, error ); // TODO: why also here?
|
|
283
283
|
art.name.id ??= prefix + pathName( art.name.path );
|
|
284
284
|
const absolute = art.name.id;
|
|
285
285
|
// TODO: check reserved, see checkName()/checkLocalizedObjects() of checks.js
|
|
@@ -394,7 +394,7 @@ function define( model ) {
|
|
|
394
394
|
|
|
395
395
|
function addExtension( ext, block ) {
|
|
396
396
|
setLink( ext, '_block', block );
|
|
397
|
-
initExprAnnoBlock( ext, block );
|
|
397
|
+
initExprAnnoBlock( ext, block, error );
|
|
398
398
|
const absolute = ext.name && resolveUncheckedPath( ext.name, '_uncheckedExtension', ext );
|
|
399
399
|
if (!absolute) // broken path
|
|
400
400
|
return;
|
|
@@ -1048,7 +1048,7 @@ function define( model ) {
|
|
|
1048
1048
|
function initMembers( parent ) {
|
|
1049
1049
|
// TODO: combine with initMembers() - better structuring
|
|
1050
1050
|
const block = parent._block;
|
|
1051
|
-
initExprAnnoBlock( parent, block );
|
|
1051
|
+
initExprAnnoBlock( parent, block, error );
|
|
1052
1052
|
const obj = initItemsLinks( parent, block ); // down many / array of
|
|
1053
1053
|
|
|
1054
1054
|
if (obj.scale && !obj.precision &&
|