@sap/cds-compiler 3.5.4 → 3.6.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 +65 -2
- package/bin/cdsc.js +14 -6
- package/doc/CHANGELOG_ARCHIVE.md +10 -10
- package/doc/CHANGELOG_DEPRECATED.md +2 -2
- package/lib/api/main.js +32 -55
- package/lib/api/options.js +3 -2
- package/lib/api/validate.js +5 -0
- package/lib/base/message-registry.js +104 -32
- package/lib/base/messages.js +277 -212
- package/lib/base/optionProcessorHelper.js +9 -2
- package/lib/base/shuffle.js +50 -0
- package/lib/checks/actionsFunctions.js +37 -20
- package/lib/checks/foreignKeys.js +13 -6
- package/lib/checks/nonexpandableStructured.js +1 -2
- package/lib/checks/onConditions.js +21 -19
- package/lib/checks/parameters.js +1 -1
- package/lib/checks/queryNoDbArtifacts.js +2 -0
- package/lib/checks/types.js +16 -22
- package/lib/compiler/assert-consistency.js +31 -28
- package/lib/compiler/builtins.js +20 -4
- package/lib/compiler/checks.js +72 -63
- package/lib/compiler/define.js +396 -314
- package/lib/compiler/extend.js +55 -49
- package/lib/compiler/index.js +5 -0
- package/lib/compiler/populate.js +28 -11
- package/lib/compiler/propagator.js +2 -1
- package/lib/compiler/resolve.js +28 -13
- package/lib/compiler/shared.js +15 -10
- package/lib/compiler/utils.js +7 -7
- package/lib/edm/annotations/genericTranslation.js +51 -46
- package/lib/edm/annotations/preprocessAnnotations.js +37 -40
- package/lib/edm/csn2edm.js +69 -21
- package/lib/edm/edm.js +2 -2
- package/lib/edm/edmInboundChecks.js +6 -8
- package/lib/edm/edmPreprocessor.js +88 -80
- package/lib/edm/edmUtils.js +6 -15
- package/lib/gen/Dictionary.json +81 -13
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +2 -1
- package/lib/gen/languageParser.js +4680 -4484
- package/lib/inspect/inspectModelStatistics.js +2 -1
- package/lib/inspect/inspectPropagation.js +2 -1
- package/lib/json/from-csn.js +131 -78
- package/lib/json/to-csn.js +39 -23
- package/lib/language/antlrParser.js +0 -3
- package/lib/language/docCommentParser.js +7 -3
- package/lib/language/errorStrategy.js +3 -2
- package/lib/language/genericAntlrParser.js +96 -41
- package/lib/language/language.g4 +112 -128
- package/lib/language/multiLineStringParser.js +2 -1
- package/lib/main.d.ts +115 -2
- package/lib/main.js +16 -3
- package/lib/model/csnRefs.js +32 -4
- package/lib/model/csnUtils.js +109 -179
- package/lib/model/enrichCsn.js +13 -8
- package/lib/model/revealInternalProperties.js +4 -3
- package/lib/optionProcessor.js +22 -3
- package/lib/render/manageConstraints.js +11 -15
- package/lib/render/toCdl.js +144 -47
- package/lib/render/toHdbcds.js +22 -22
- package/lib/render/toRename.js +3 -4
- package/lib/render/toSql.js +31 -22
- package/lib/render/utils/delta.js +3 -1
- package/lib/render/utils/sql.js +2 -14
- package/lib/transform/db/associations.js +6 -6
- package/lib/transform/db/cdsPersistence.js +3 -3
- package/lib/transform/db/constraints.js +4 -6
- package/lib/transform/db/expansion.js +4 -4
- package/lib/transform/db/flattening.js +12 -15
- package/lib/transform/db/temporal.js +4 -3
- package/lib/transform/db/transformExists.js +13 -7
- package/lib/transform/draft/db.js +7 -7
- package/lib/transform/forOdataNew.js +15 -4
- package/lib/transform/forRelationalDB.js +59 -41
- package/lib/transform/odata/toFinalBaseType.js +106 -82
- package/lib/transform/odata/typesExposure.js +26 -17
- package/lib/transform/odata/utils.js +1 -1
- package/lib/transform/parseExpr.js +1 -1
- package/lib/transform/transformUtilsNew.js +33 -10
- package/lib/transform/translateAssocsToJoins.js +8 -7
- package/lib/transform/universalCsn/coreComputed.js +7 -5
- package/lib/transform/universalCsn/universalCsnEnricher.js +12 -4
- package/lib/utils/timetrace.js +2 -2
- package/package.json +1 -2
package/lib/compiler/checks.js
CHANGED
|
@@ -20,6 +20,7 @@ const {
|
|
|
20
20
|
} = require('../base/model');
|
|
21
21
|
const { CompilerAssertion } = require('../base/error');
|
|
22
22
|
const { pathName } = require('./utils');
|
|
23
|
+
const { forEachMemberRecursively } = require('../model/csnUtils');
|
|
23
24
|
|
|
24
25
|
function check( model ) { // = XSN
|
|
25
26
|
const {
|
|
@@ -40,6 +41,10 @@ function check( model ) { // = XSN
|
|
|
40
41
|
|
|
41
42
|
function checkAnnotationDefinition( art ) {
|
|
42
43
|
checkEnumType( art );
|
|
44
|
+
forEachMemberRecursively( art, (member) => {
|
|
45
|
+
if (member.localized?.val)
|
|
46
|
+
warning( 'def-unexpected-localized-anno', [ member.localized.location, member ] );
|
|
47
|
+
});
|
|
43
48
|
// TODO: Should we check elements similar to definition-elements as well?
|
|
44
49
|
}
|
|
45
50
|
|
|
@@ -54,24 +59,33 @@ function check( model ) { // = XSN
|
|
|
54
59
|
if (art.kind === 'enum')
|
|
55
60
|
checkEnum( art );
|
|
56
61
|
checkEnumType( art );
|
|
62
|
+
|
|
57
63
|
forEachMember( art, checkGenericConstruct );
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
function checkElement( elem ) {
|
|
61
67
|
checkLocalizedSubElement(elem);
|
|
62
|
-
if (elem.key
|
|
63
|
-
if (elem.virtual
|
|
64
|
-
error(
|
|
65
|
-
|
|
66
|
-
|
|
68
|
+
if (elem.key?.val) {
|
|
69
|
+
if (elem.virtual?.val) {
|
|
70
|
+
error('def-unexpected-key', [ elem.key.location, elem ],
|
|
71
|
+
{ '#': 'virtual', name: elem.name.element, prop: 'key' });
|
|
72
|
+
}
|
|
73
|
+
checkForUnmanagedAssociationsAsKey( elem, elem.key );
|
|
67
74
|
}
|
|
68
75
|
checkAssociation( elem );
|
|
69
76
|
checkLocalizedElement( elem );
|
|
70
77
|
if (elem.on && !elem.on.$inferred)
|
|
71
78
|
checkExpression(elem.on, true);
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
|
|
80
|
+
if (elem.value) {
|
|
81
|
+
if (elem.$syntax === 'calc')
|
|
82
|
+
checkCalculatedElement( elem );
|
|
83
|
+
else
|
|
84
|
+
checkExpression( elem.value );
|
|
85
|
+
}
|
|
86
|
+
|
|
74
87
|
checkCardinality(elem); // TODO: also for assoc types
|
|
88
|
+
|
|
75
89
|
forEachGeneric( elem, 'elements', checkElement );
|
|
76
90
|
}
|
|
77
91
|
|
|
@@ -111,6 +125,24 @@ function check( model ) { // = XSN
|
|
|
111
125
|
}
|
|
112
126
|
}
|
|
113
127
|
|
|
128
|
+
function checkCalculatedElement( elem ) {
|
|
129
|
+
if (elem.value.path) {
|
|
130
|
+
checkExpressionsInPaths(elem.value);
|
|
131
|
+
|
|
132
|
+
const loc = [ elem.value.location, elem ];
|
|
133
|
+
if (isVirtualElement(elem.value._artifact))
|
|
134
|
+
error('ref-unexpected-virtual', loc, { '#': 'expr' });
|
|
135
|
+
else if (isStructuredElement(elem.value._artifact))
|
|
136
|
+
error('ref-unexpected-structured', loc, { '#': 'expr' } );
|
|
137
|
+
else if (elem.value._artifact?.target !== undefined)
|
|
138
|
+
error('ref-unexpected-assoc', loc, { '#': 'expr' });
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
// TODO: The checks above should also be run for each path in expressions.
|
|
142
|
+
checkExpression( elem.value );
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
114
146
|
function checkQuery( query ) {
|
|
115
147
|
checkNoUnmanagedAssocsInGroupByOrderBy( query );
|
|
116
148
|
// TODO: check too simple (just one source), as most of those in this file
|
|
@@ -169,9 +201,8 @@ function check( model ) { // = XSN
|
|
|
169
201
|
// Special handling to print a more detailed error message.
|
|
170
202
|
// Other cases like `null` as enum value are handled in `checkEnumValueType()`
|
|
171
203
|
if (type === 'enum') {
|
|
172
|
-
warning('enum-value-ref', [ loc, enumNode ], {},
|
|
204
|
+
warning('enum-value-ref', [ loc, enumNode ], {}, // TODO: make this an error in v4
|
|
173
205
|
'References to other values are not allowed as enum values');
|
|
174
|
-
return;
|
|
175
206
|
}
|
|
176
207
|
}
|
|
177
208
|
|
|
@@ -329,7 +360,7 @@ function check( model ) { // = XSN
|
|
|
329
360
|
*
|
|
330
361
|
* @param {any} element Element to check recursively
|
|
331
362
|
*/
|
|
332
|
-
function
|
|
363
|
+
function checkForUnmanagedAssociationsAsKey( element, keyObj ) {
|
|
333
364
|
if (element.targetAspect) {
|
|
334
365
|
// TODO: bad location / message
|
|
335
366
|
message('composition-as-key', [ keyObj.location, element ], {},
|
|
@@ -345,7 +376,7 @@ function check( model ) { // = XSN
|
|
|
345
376
|
// TODO: ease check for subelements: using unmanaged assocs is OK there, as
|
|
346
377
|
// long as the whole key is "closed", i.e., no ref in ON refers to element
|
|
347
378
|
// outside.
|
|
348
|
-
forEachGeneric( element, 'elements', e =>
|
|
379
|
+
forEachGeneric( element, 'elements', e => checkForUnmanagedAssociationsAsKey( e, keyObj ) );
|
|
349
380
|
}
|
|
350
381
|
|
|
351
382
|
// Check that min and max cardinalities of 'elem' in 'art' have legal values
|
|
@@ -468,14 +499,12 @@ function check( model ) { // = XSN
|
|
|
468
499
|
|
|
469
500
|
function checkAssociation( elem ) {
|
|
470
501
|
// TODO: yes, a check similar to this could make it into the compiler)
|
|
471
|
-
//
|
|
502
|
+
// when virtual element is part of association
|
|
472
503
|
if (elem.foreignKeys) {
|
|
473
504
|
for (const k in elem.foreignKeys) {
|
|
474
505
|
const key = elem.foreignKeys[k].targetElement;
|
|
475
|
-
if (key && key._artifact
|
|
476
|
-
error(
|
|
477
|
-
'Virtual elements can\'t be used as a foreign key for a managed association');
|
|
478
|
-
}
|
|
506
|
+
if (key && isVirtualElement(key._artifact))
|
|
507
|
+
error('ref-unexpected-virtual', [ key.location, elem ], { '#': 'fkey' });
|
|
479
508
|
}
|
|
480
509
|
}
|
|
481
510
|
if (elem.on && !elem.on.$inferred)
|
|
@@ -601,13 +630,24 @@ function check( model ) { // = XSN
|
|
|
601
630
|
*
|
|
602
631
|
* TO CLARIFY: do we want the "no virtual element" check for virtual elements/columns, too?
|
|
603
632
|
*
|
|
604
|
-
* @param {any}
|
|
633
|
+
* @param {any} elem Element to check (part of an expression)
|
|
605
634
|
* @returns {Boolean}
|
|
606
635
|
*/
|
|
607
|
-
function isVirtualElement(
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
636
|
+
function isVirtualElement( elem ) {
|
|
637
|
+
let parent = elem?._origin || elem;
|
|
638
|
+
while (parent) {
|
|
639
|
+
if (parent.virtual?.val === true)
|
|
640
|
+
return true;
|
|
641
|
+
parent = parent._parent;
|
|
642
|
+
}
|
|
643
|
+
return false;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
function isStructuredElement( elem ) {
|
|
647
|
+
// The effective type always points to something with elements _if_ the
|
|
648
|
+
// type is structured. But `elem` should already have `elements` if its
|
|
649
|
+
// structured due to element expansion.
|
|
650
|
+
return !!(elem?._effectiveType || elem)?.elements;
|
|
611
651
|
}
|
|
612
652
|
|
|
613
653
|
/**
|
|
@@ -620,9 +660,8 @@ function check( model ) { // = XSN
|
|
|
620
660
|
const args = Array.isArray(xpr.args) ? xpr.args : Object.values(xpr.args || {});
|
|
621
661
|
// Check for illegal argument usage within the expression
|
|
622
662
|
for (const arg of args) {
|
|
623
|
-
if (isVirtualElement(arg))
|
|
624
|
-
error(
|
|
625
|
-
|
|
663
|
+
if (isVirtualElement(arg._artifact || arg))
|
|
664
|
+
error('ref-unexpected-virtual', arg.location, { '#': 'expr' });
|
|
626
665
|
|
|
627
666
|
// Recursively traverse the argument expression
|
|
628
667
|
checkTokenStreamExpression(arg, allowAssocTail);
|
|
@@ -643,20 +682,17 @@ function check( model ) { // = XSN
|
|
|
643
682
|
|
|
644
683
|
// Check for illegal argument usage within the expression
|
|
645
684
|
for (const arg of Array.isArray(xpr.args) && xpr.args || []) { // TODO named args?
|
|
646
|
-
if (isVirtualElement(arg))
|
|
647
|
-
error(
|
|
685
|
+
if (isVirtualElement(arg._artifact || arg))
|
|
686
|
+
error('ref-unexpected-virtual', arg.location, { '#': 'expr' });
|
|
648
687
|
|
|
649
688
|
// Arg must not be an association and not $self
|
|
650
689
|
// Only if path is not approved exists path (that is non-query position)
|
|
651
690
|
if (arg.path && arg.$expected !== undefined) { // not 'approved-exists'
|
|
652
|
-
if (arg.$expected === 'exists')
|
|
653
|
-
error(
|
|
654
|
-
'An association can\'t be used as a value in an expression');
|
|
655
|
-
}
|
|
691
|
+
if (arg.$expected === 'exists')
|
|
692
|
+
error('ref-unexpected-assoc', arg.location, { '#': 'expr' } );
|
|
656
693
|
}
|
|
657
694
|
else if (!allowAssocTail && isAssociationOperand(arg)) {
|
|
658
|
-
error(
|
|
659
|
-
'An association can\'t be used as a value in an expression');
|
|
695
|
+
error('ref-unexpected-assoc', arg.location, { '#': 'expr' } );
|
|
660
696
|
}
|
|
661
697
|
|
|
662
698
|
if (isDollarSelfOrProjectionOperand(arg)) {
|
|
@@ -769,7 +805,7 @@ function check( model ) { // = XSN
|
|
|
769
805
|
|
|
770
806
|
// Sanity checks
|
|
771
807
|
if (!elementDecl._effectiveType)
|
|
772
|
-
throw new
|
|
808
|
+
throw new CompilerAssertion(`Expecting annotation declaration to have _finalType: ${ JSON.stringify(annoDecl) }`);
|
|
773
809
|
|
|
774
810
|
|
|
775
811
|
// Must have literal or path unless it is a boolean
|
|
@@ -929,40 +965,13 @@ function check( model ) { // = XSN
|
|
|
929
965
|
}
|
|
930
966
|
|
|
931
967
|
/**
|
|
932
|
-
* Ensure that the sap.common.
|
|
933
|
-
* e.g. `locale` and `ID_texts`.
|
|
934
|
-
*
|
|
935
|
-
* @param {XSN.Model} model
|
|
936
|
-
*/
|
|
937
|
-
function checkSapCommonTextsAspects( model ) {
|
|
938
|
-
checkSapCommonTextsAspectLocale( model, 'sap.common.TextsAspect' );
|
|
939
|
-
checkSapCommonTextsAspectLocale( model, 'sap.common.FioriTextsAspect' );
|
|
940
|
-
|
|
941
|
-
// Check ID_texts: Fiori requires it to be UUID.
|
|
942
|
-
const fioriTextsAspect = model.definitions['sap.common.FioriTextsAspect'];
|
|
943
|
-
const id = fioriTextsAspect?.elements?.ID_texts;
|
|
944
|
-
if (id) {
|
|
945
|
-
const idType = id._effectiveType;
|
|
946
|
-
if (!idType || idType.name?.absolute !== 'cds.UUID') {
|
|
947
|
-
const { error } = model.$messageFunctions;
|
|
948
|
-
error('def-invalid-element-type', [ id.type.location, id ], {
|
|
949
|
-
'#': 'std',
|
|
950
|
-
art: 'sap.common.FioriTextsAspect',
|
|
951
|
-
elemref: 'ID_texts',
|
|
952
|
-
type: 'cds.UUID',
|
|
953
|
-
});
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
/**
|
|
959
|
-
* Ensure that the `locale` element of sap.common.[Fiori]TextsAspects
|
|
968
|
+
* Ensure that the `locale` element of sap.common.TextsAspects
|
|
960
969
|
* is a string type. This is required by CAP runtimes to work properly.
|
|
961
970
|
*
|
|
962
971
|
* @param {XSN.Model} model
|
|
963
|
-
* @param {string} name Either sap.common.TextsAspects or sap.common.FioriTextsAspects
|
|
964
972
|
*/
|
|
965
|
-
function
|
|
973
|
+
function checkSapCommonTextsAspects( model ) {
|
|
974
|
+
const name = 'sap.common.TextsAspect';
|
|
966
975
|
const locale = model.definitions[name]?.elements?.locale;
|
|
967
976
|
if (locale) {
|
|
968
977
|
// `locale` could also be `sap.common.Locale`, which must also be a string.
|