@sap/cds-compiler 3.9.2 → 4.0.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 +98 -0
- package/README.md +0 -1
- package/bin/cdsc.js +11 -23
- package/bin/cdsse.js +3 -3
- package/doc/API.md +5 -0
- package/doc/CHANGELOG_ARCHIVE.md +1 -1
- package/doc/CHANGELOG_BETA.md +17 -1
- package/doc/CHANGELOG_DEPRECATED.md +28 -0
- package/lib/api/.eslintrc.json +1 -1
- package/lib/api/main.js +26 -8
- package/lib/api/options.js +2 -0
- package/lib/base/error.js +2 -0
- package/lib/base/message-registry.js +144 -65
- package/lib/base/messages.js +213 -107
- package/lib/base/model.js +11 -11
- package/lib/checks/.eslintrc.json +1 -1
- package/lib/checks/annotationsOData.js +2 -2
- package/lib/checks/elements.js +1 -1
- package/lib/checks/enricher.js +26 -3
- package/lib/checks/onConditions.js +67 -12
- package/lib/checks/queryNoDbArtifacts.js +106 -105
- package/lib/checks/sql-snippets.js +2 -0
- package/lib/checks/types.js +12 -6
- package/lib/checks/validator.js +2 -2
- package/lib/compiler/assert-consistency.js +10 -8
- package/lib/compiler/builtins.js +8 -2
- package/lib/compiler/checks.js +52 -35
- package/lib/compiler/define.js +31 -26
- package/lib/compiler/extend.js +120 -65
- package/lib/compiler/finalize-parse-cdl.js +12 -43
- package/lib/compiler/generate.js +16 -5
- package/lib/compiler/index.js +8 -5
- package/lib/compiler/kick-start.js +4 -3
- package/lib/compiler/populate.js +96 -95
- package/lib/compiler/propagator.js +7 -8
- package/lib/compiler/resolve.js +377 -103
- package/lib/compiler/shared.js +794 -517
- package/lib/compiler/tweak-assocs.js +8 -6
- package/lib/compiler/utils.js +44 -0
- package/lib/edm/annotations/genericTranslation.js +24 -6
- package/lib/edm/csn2edm.js +47 -45
- package/lib/edm/edm.js +34 -31
- package/lib/edm/edmAnnoPreprocessor.js +0 -23
- package/lib/edm/edmInboundChecks.js +7 -2
- package/lib/edm/edmPreprocessor.js +18 -17
- package/lib/edm/edmUtils.js +8 -4
- package/lib/gen/Dictionary.json +18 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +4 -2
- package/lib/gen/languageParser.js +5006 -4582
- package/lib/json/from-csn.js +159 -114
- package/lib/json/to-csn.js +60 -89
- package/lib/language/antlrParser.js +17 -13
- package/lib/language/docCommentParser.js +11 -1
- package/lib/language/genericAntlrParser.js +13 -10
- package/lib/language/language.g4 +168 -97
- package/lib/main.d.ts +128 -36
- package/lib/main.js +1 -1
- package/lib/model/csnRefs.js +24 -5
- package/lib/model/csnUtils.js +9 -8
- package/lib/model/revealInternalProperties.js +7 -12
- package/lib/modelCompare/compare.js +1 -1
- package/lib/modelCompare/utils/filter.js +40 -2
- package/lib/optionProcessor.js +0 -3
- package/lib/render/toCdl.js +247 -214
- package/lib/render/toHdbcds.js +197 -181
- package/lib/render/toSql.js +325 -289
- package/lib/render/utils/common.js +42 -4
- package/lib/render/utils/delta.js +1 -1
- package/lib/render/utils/sql.js +3 -3
- package/lib/transform/braceExpression.js +2 -2
- package/lib/transform/db/.eslintrc.json +1 -1
- package/lib/transform/db/applyTransformations.js +3 -3
- package/lib/transform/db/associations.js +24 -12
- package/lib/transform/db/expansion.js +17 -18
- package/lib/transform/db/flattening.js +17 -21
- package/lib/transform/db/rewriteCalculatedElements.js +171 -64
- package/lib/transform/db/views.js +3 -4
- package/lib/transform/draft/db.js +21 -12
- package/lib/transform/draft/odata.js +4 -0
- package/lib/transform/forOdataNew.js +11 -10
- package/lib/transform/forRelationalDB.js +12 -7
- package/lib/transform/localized.js +5 -3
- package/lib/transform/odata/toFinalBaseType.js +5 -5
- package/lib/transform/odata/typesExposure.js +3 -3
- package/lib/transform/parseExpr.js +3 -0
- package/lib/transform/transformUtilsNew.js +43 -23
- package/lib/transform/translateAssocsToJoins.js +7 -6
- package/lib/transform/universalCsn/.eslintrc.json +1 -1
- package/lib/transform/universalCsn/coreComputed.js +7 -5
- package/lib/transform/universalCsn/universalCsnEnricher.js +12 -12
- package/lib/utils/file.js +3 -3
- package/lib/utils/moduleResolve.js +1 -1
- package/package.json +2 -2
- package/share/messages/{duplicate-autoexposed.md → def-duplicate-autoexposed.md} +5 -1
- package/share/messages/message-explanations.json +1 -1
package/lib/compiler/checks.js
CHANGED
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
// const { hasArtifactTypeInformation } = require('../model/csnUtils')
|
|
17
17
|
const builtins = require('../compiler/builtins');
|
|
18
18
|
const {
|
|
19
|
-
forEachGeneric,
|
|
19
|
+
forEachGeneric,
|
|
20
|
+
forEachDefinition,
|
|
21
|
+
forEachMember,
|
|
20
22
|
} = require('../base/model');
|
|
21
23
|
const { CompilerAssertion } = require('../base/error');
|
|
22
24
|
const { pathName } = require('./utils');
|
|
@@ -457,7 +459,7 @@ function check( model ) { // = XSN
|
|
|
457
459
|
const key = elem.foreignKeys[k].targetElement;
|
|
458
460
|
if (key && isVirtualElement(key._artifact))
|
|
459
461
|
error('ref-unexpected-virtual', [ key.location, elem ], { '#': 'fkey' });
|
|
460
|
-
else if (key._artifact?.$syntax === 'calc')
|
|
462
|
+
else if (key._artifact?.$syntax === 'calc' && !key._artifact.value.stored?.val)
|
|
461
463
|
error( 'ref-unexpected-calculated', [ key.location, elem ], { '#': 'fkey' } );
|
|
462
464
|
}
|
|
463
465
|
}
|
|
@@ -508,9 +510,6 @@ function check( model ) { // = XSN
|
|
|
508
510
|
* NOTE: Relies on element expansion.
|
|
509
511
|
*/
|
|
510
512
|
function checkElementIncludeOverride( def ) {
|
|
511
|
-
if (!isBetaEnabled(model.options, 'v4preview'))
|
|
512
|
-
return; // this is a v4 check only
|
|
513
|
-
|
|
514
513
|
for (const name in def.elements) {
|
|
515
514
|
const element = def.elements[name];
|
|
516
515
|
// Element is new in `art`, not expanded; we can't check for !element._origin, due
|
|
@@ -590,7 +589,7 @@ function check( model ) { // = XSN
|
|
|
590
589
|
visitExpression(elem.on, elem, (xpr, user) => {
|
|
591
590
|
checkExpressionNotVirtual(xpr, user);
|
|
592
591
|
checkExpressionAssociationUsage(xpr, user, true);
|
|
593
|
-
if (xpr._artifact?.$syntax === 'calc')
|
|
592
|
+
if (xpr._artifact?.$syntax === 'calc' && !xpr._artifact.value.stored?.val)
|
|
594
593
|
error( 'ref-unexpected-calculated', [ xpr.location, user ], { '#': 'on' } );
|
|
595
594
|
});
|
|
596
595
|
if (isDollarSelfOrProjectionOperand(elem.on)) {
|
|
@@ -612,15 +611,20 @@ function check( model ) { // = XSN
|
|
|
612
611
|
function checkCalculatedElementValue( elem ) {
|
|
613
612
|
visitExpression(elem.value, elem, (xpr, user) => {
|
|
614
613
|
if (xpr._artifact) { // we only need to check artifact references
|
|
614
|
+
const sourceLoc = xpr.path?.[xpr.path.length - 1].location || xpr.location;
|
|
615
615
|
checkExpressionNotVirtual(xpr, user);
|
|
616
|
-
|
|
617
|
-
|
|
616
|
+
// For inferred (e.g. included) calc elements, this error is already emitted at the origin.
|
|
617
|
+
// And users can't change structured to non-structured elements.
|
|
618
|
+
if (!elem.$inferred && isStructuredElement(xpr._artifact))
|
|
619
|
+
error('ref-unexpected-structured', [ sourceLoc, elem ], { '#': 'expr' } );
|
|
618
620
|
else if (xpr._artifact.target !== undefined)
|
|
619
|
-
error('ref-unexpected-assoc', [
|
|
621
|
+
error('ref-unexpected-assoc', [ sourceLoc, elem ], { '#': 'expr' });
|
|
622
|
+
else if (xpr._artifact.localized?.val)
|
|
623
|
+
error('ref-unexpected-localized', [ sourceLoc, elem ], { '#': 'calc' });
|
|
620
624
|
}
|
|
621
625
|
});
|
|
622
|
-
//
|
|
623
|
-
// in an SQL view, which is missing in OData.
|
|
626
|
+
// Calculated elements must not refer to keys, because that may lead to another
|
|
627
|
+
// key in an SQL view, which is missing in OData (for on-read).
|
|
624
628
|
// Following associations does not lead to this issue.
|
|
625
629
|
if (elem.value.path && isKeyElement(elem.value._artifact) &&
|
|
626
630
|
!followsAnAssociation(elem.value.path)) {
|
|
@@ -830,7 +834,7 @@ function check( model ) { // = XSN
|
|
|
830
834
|
|
|
831
835
|
// Element must exist in annotation
|
|
832
836
|
if (!elementDecl) {
|
|
833
|
-
warning(null, anno.location || anno.name.location,
|
|
837
|
+
warning(null, [ anno.location || anno.name.location, art ],
|
|
834
838
|
{ name: pathName(anno.name.path), anno: annoDecl.name.absolute },
|
|
835
839
|
'Element $(NAME) not found for annotation $(ANNO)');
|
|
836
840
|
return;
|
|
@@ -844,11 +848,11 @@ function check( model ) { // = XSN
|
|
|
844
848
|
// Must have literal or path unless it is a boolean
|
|
845
849
|
if (!anno.literal && !anno.path && getFinalTypeNameOf(elementDecl) !== 'cds.Boolean') {
|
|
846
850
|
if (elementDecl.type && elementDecl.type._artifact.name.absolute) {
|
|
847
|
-
warning('anno-expecting-value', anno.location || anno.name.location,
|
|
851
|
+
warning('anno-expecting-value', [ anno.location || anno.name.location, art ],
|
|
848
852
|
{ '#': 'type', type: elementDecl.type._artifact });
|
|
849
853
|
}
|
|
850
854
|
else {
|
|
851
|
-
warning('anno-expecting-value', anno.location || anno.name.location,
|
|
855
|
+
warning('anno-expecting-value', [ anno.location || anno.name.location, art ],
|
|
852
856
|
{ '#': 'std', anno: anno.name.absolute });
|
|
853
857
|
}
|
|
854
858
|
|
|
@@ -856,31 +860,31 @@ function check( model ) { // = XSN
|
|
|
856
860
|
}
|
|
857
861
|
|
|
858
862
|
// Value must be assignable to type
|
|
859
|
-
checkValueAssignableTo(anno, elementDecl, art);
|
|
863
|
+
checkValueAssignableTo(anno, anno, elementDecl, art);
|
|
860
864
|
}
|
|
861
865
|
|
|
862
866
|
// Check that annotation assignment 'value' (having 'path or 'literal' and
|
|
863
867
|
// 'val') is potentially assignable to element 'element'. Complain on 'loc'
|
|
864
868
|
// if not
|
|
865
|
-
function checkValueAssignableTo( value, elementDecl, art ) {
|
|
869
|
+
function checkValueAssignableTo( annoDef, value, elementDecl, art ) {
|
|
866
870
|
// FIXME: We currently do not have any element declaration that could match
|
|
867
871
|
// a 'path' value, so we simply leave those alone
|
|
868
872
|
if (value.path)
|
|
869
873
|
return;
|
|
870
874
|
|
|
871
|
-
|
|
875
|
+
const anno = annoDef.name.absolute;
|
|
872
876
|
const loc = [ value.location || value.name.location, art ];
|
|
873
877
|
|
|
874
878
|
// Array expected?
|
|
875
879
|
if (elementDecl._effectiveType.items) {
|
|
876
880
|
// Make sure we have an array value
|
|
877
881
|
if (value.literal !== 'array') {
|
|
878
|
-
warning(null, loc, {}, 'An array value is required
|
|
882
|
+
warning(null, loc, { anno }, 'An array value is required for annotation $(ANNO)');
|
|
879
883
|
return;
|
|
880
884
|
}
|
|
881
885
|
// Check each element
|
|
882
886
|
for (const valueItem of value.val)
|
|
883
|
-
checkValueAssignableTo(valueItem, elementDecl._effectiveType.items, art);
|
|
887
|
+
checkValueAssignableTo(value, valueItem, elementDecl._effectiveType.items, art);
|
|
884
888
|
|
|
885
889
|
return;
|
|
886
890
|
}
|
|
@@ -888,7 +892,7 @@ function check( model ) { // = XSN
|
|
|
888
892
|
// Struct expected (can only happen within arrays)?
|
|
889
893
|
if (elementDecl._effectiveType.elements) {
|
|
890
894
|
if (value.literal !== 'struct') {
|
|
891
|
-
warning(null, loc, {}, 'A struct value is required here');
|
|
895
|
+
warning(null, loc, { anno }, 'A struct value is required here for annotation $(ANNO)');
|
|
892
896
|
return;
|
|
893
897
|
}
|
|
894
898
|
// FIXME: Should check each element
|
|
@@ -899,29 +903,41 @@ function check( model ) { // = XSN
|
|
|
899
903
|
const type = getFinalTypeNameOf(elementDecl);
|
|
900
904
|
if (builtins.isStringTypeName(type)) {
|
|
901
905
|
if (value.literal !== 'string' && value.literal !== 'enum' &&
|
|
902
|
-
!elementDecl._effectiveType.enum)
|
|
903
|
-
warning(null, loc, { type },
|
|
906
|
+
!elementDecl._effectiveType.enum) {
|
|
907
|
+
warning(null, loc, { type, anno },
|
|
908
|
+
'A string value is required for type $(TYPE) for annotation $(ANNO)');
|
|
909
|
+
}
|
|
904
910
|
}
|
|
905
911
|
else if (builtins.isBinaryTypeName(type)) {
|
|
906
|
-
if (value.literal !== 'string' && value.literal !== 'x')
|
|
907
|
-
warning(null, loc, { type },
|
|
912
|
+
if (value.literal !== 'string' && value.literal !== 'x') {
|
|
913
|
+
warning(null, loc, { type, anno },
|
|
914
|
+
'A hexadecimal string value is required for type $(TYPE) for annotation $(ANNO)');
|
|
915
|
+
}
|
|
908
916
|
}
|
|
909
917
|
else if (builtins.isNumericTypeName(type)) {
|
|
910
918
|
if (value.literal !== 'number' && value.literal !== 'enum' &&
|
|
911
|
-
!elementDecl._effectiveType.enum)
|
|
912
|
-
warning(null, loc, { type },
|
|
919
|
+
!elementDecl._effectiveType.enum) {
|
|
920
|
+
warning(null, loc, { type, anno },
|
|
921
|
+
'A numerical value is required for type $(TYPE) for annotation $(ANNO)');
|
|
922
|
+
}
|
|
913
923
|
}
|
|
914
924
|
else if (builtins.isDateOrTimeTypeName(type)) {
|
|
915
925
|
if (value.literal !== 'date' && value.literal !== 'time' &&
|
|
916
|
-
value.literal !== 'timestamp' && value.literal !== 'string')
|
|
917
|
-
warning(null, loc, { type },
|
|
926
|
+
value.literal !== 'timestamp' && value.literal !== 'string') {
|
|
927
|
+
warning(null, loc, { type, anno },
|
|
928
|
+
// eslint-disable-next-line max-len
|
|
929
|
+
'A date/time value or a string is required for type $(TYPE) for annotation $(ANNO)');
|
|
930
|
+
}
|
|
918
931
|
}
|
|
919
932
|
else if (builtins.isBooleanTypeName(type)) {
|
|
920
|
-
if (value.literal && value.literal !== 'boolean')
|
|
921
|
-
warning(null, loc, { type },
|
|
933
|
+
if (value.literal && value.literal !== 'boolean') {
|
|
934
|
+
warning(null, loc, { type, anno },
|
|
935
|
+
'A boolean value is required for type $(TYPE) for annotation $(ANNO)');
|
|
936
|
+
}
|
|
922
937
|
}
|
|
923
938
|
else if (builtins.isRelationTypeName(type) || builtins.isGeoTypeName(type)) {
|
|
924
|
-
warning(null, loc, { type },
|
|
939
|
+
warning(null, loc, { type, anno },
|
|
940
|
+
'Type $(TYPE) can\'t be assigned a value for annotation $(ANNO)');
|
|
925
941
|
}
|
|
926
942
|
else if (!elementDecl._effectiveType.enum) {
|
|
927
943
|
throw new CompilerAssertion(`Unknown primitive type name: ${ type }`);
|
|
@@ -933,13 +949,14 @@ function check( model ) { // = XSN
|
|
|
933
949
|
if (expectedEnum) {
|
|
934
950
|
// Enum symbol provided and expected
|
|
935
951
|
if (!expectedEnum[value.sym.id]) {
|
|
936
|
-
//
|
|
937
|
-
warning(null, loc, { id: `#${ value.sym.id }
|
|
952
|
+
// ... but no such constant
|
|
953
|
+
warning(null, loc, { id: `#${ value.sym.id }`, anno }, 'Enum symbol $(ID) not found in enum for annotation $(ANNO)');
|
|
938
954
|
}
|
|
939
955
|
}
|
|
940
956
|
else {
|
|
941
957
|
// Enum symbol provided but not expected
|
|
942
|
-
warning(null, loc, { id: `#${ value.sym.id }`, type },
|
|
958
|
+
warning(null, loc, { id: `#${ value.sym.id }`, type, anno },
|
|
959
|
+
'Can\'t use enum symbol $(ID) for non-enum type $(TYPE) for annotation $(ANNO)');
|
|
943
960
|
}
|
|
944
961
|
}
|
|
945
962
|
else if (expectedEnum) {
|
|
@@ -948,7 +965,7 @@ function check( model ) { // = XSN
|
|
|
948
965
|
.some(symbol => getEnumValue(expectedEnum[symbol]) === value.val);
|
|
949
966
|
if (!hasValidValue) {
|
|
950
967
|
// ... and none of the valid enum symbols matches the value
|
|
951
|
-
warning(null, loc, {}, 'An enum value is required
|
|
968
|
+
warning(null, loc, { anno }, 'An enum value is required for annotation $(ANNO)');
|
|
952
969
|
}
|
|
953
970
|
}
|
|
954
971
|
}
|
package/lib/compiler/define.js
CHANGED
|
@@ -123,7 +123,6 @@ const {
|
|
|
123
123
|
forEachGeneric,
|
|
124
124
|
forEachInOrder,
|
|
125
125
|
forEachMember,
|
|
126
|
-
isBetaEnabled,
|
|
127
126
|
} = require('../base/model');
|
|
128
127
|
const shuffleGen = require('../base/shuffle');
|
|
129
128
|
const {
|
|
@@ -174,11 +173,6 @@ function define( model ) {
|
|
|
174
173
|
initMembers,
|
|
175
174
|
checkDefinitions, // TODO: remove
|
|
176
175
|
} );
|
|
177
|
-
// During the definer, we can only resolve artifact references, i.e,
|
|
178
|
-
// after a `.`, we only search in the `_subArtifacts` dictionary:
|
|
179
|
-
model.$volatileFunctions.environment = function artifactsEnv( art ) {
|
|
180
|
-
return art._subArtifacts || Object.create(null);
|
|
181
|
-
};
|
|
182
176
|
|
|
183
177
|
let boundSelfParamType = true; // special `$self` for binding param must still be initialised
|
|
184
178
|
|
|
@@ -333,6 +327,7 @@ function define( model ) {
|
|
|
333
327
|
* @param {XSN.SourceAst} src
|
|
334
328
|
*/
|
|
335
329
|
function addUsing( decl, src ) {
|
|
330
|
+
setLink( decl, '_block', src );
|
|
336
331
|
if (decl.usings) {
|
|
337
332
|
// e.g. `using {a,b} from 'file.cds'` -> recursive
|
|
338
333
|
decl.usings.forEach( u => addUsing( u, src ) );
|
|
@@ -393,7 +388,7 @@ function define( model ) {
|
|
|
393
388
|
|
|
394
389
|
function addExtension( ext, block ) {
|
|
395
390
|
setLink( ext, '_block', block );
|
|
396
|
-
const absolute = ext.name && resolveUncheckedPath( ext.name, '
|
|
391
|
+
const absolute = ext.name && resolveUncheckedPath( ext.name, '_extensions', ext );
|
|
397
392
|
if (!absolute) // broken path
|
|
398
393
|
return;
|
|
399
394
|
delete ext.name.path[0]._artifact; // might point to wrong JS object in phase 1
|
|
@@ -423,9 +418,11 @@ function define( model ) {
|
|
|
423
418
|
}
|
|
424
419
|
|
|
425
420
|
function initExtension( parent ) {
|
|
426
|
-
forEachMember( parent, function
|
|
421
|
+
forEachMember( parent, function initExtensionMember( sub, name, prop ) {
|
|
427
422
|
if (sub.kind !== 'extend' && sub.kind !== 'annotate')
|
|
428
423
|
return; // for defs inside, set somewhere else - TODO: rethink
|
|
424
|
+
if (prop === 'params' && name === '') // RETURNS
|
|
425
|
+
sub.name = { id: '', location: sub.location };
|
|
429
426
|
setLink( sub, '_block', parent._block );
|
|
430
427
|
setLink( sub, '_parent', parent );
|
|
431
428
|
setLink( sub, '_main', parent._main || parent );
|
|
@@ -512,7 +509,9 @@ function define( model ) {
|
|
|
512
509
|
'#': kindProperties[art.kind].normalized || art.kind,
|
|
513
510
|
} );
|
|
514
511
|
}
|
|
515
|
-
else {
|
|
512
|
+
else if (!art.builtin) {
|
|
513
|
+
// TODO: better messages with definitions with the same name as builtin,
|
|
514
|
+
// especially if there is just one
|
|
516
515
|
error( 'duplicate-definition', [ art.name.location, art ], {
|
|
517
516
|
name: art.name.absolute,
|
|
518
517
|
'#': (art.kind === 'annotation' ? 'annotation' : 'absolute' ),
|
|
@@ -555,7 +554,7 @@ function define( model ) {
|
|
|
555
554
|
continue;
|
|
556
555
|
for (const decl of entry) {
|
|
557
556
|
if (!decl.$duplicates) { // do not have two duplicate messages
|
|
558
|
-
error( 'duplicate-using', [ decl.name.location,
|
|
557
|
+
error( 'duplicate-using', [ decl.name.location, decl ], { name },
|
|
559
558
|
'Duplicate definition of top-level name $(NAME)' );
|
|
560
559
|
}
|
|
561
560
|
}
|
|
@@ -634,7 +633,6 @@ function define( model ) {
|
|
|
634
633
|
setLink( self, '_origin', art );
|
|
635
634
|
art.$tableAliases = Object.create(null);
|
|
636
635
|
art.$tableAliases[selfname] = self;
|
|
637
|
-
setLink( art, '_$next', model.$magicVariables );
|
|
638
636
|
}
|
|
639
637
|
|
|
640
638
|
function initDollarParameters( art ) {
|
|
@@ -713,9 +711,7 @@ function define( model ) {
|
|
|
713
711
|
function initQuery() {
|
|
714
712
|
const main = art._main || art;
|
|
715
713
|
setLink( query, '_$next',
|
|
716
|
-
|
|
717
|
-
(!art._main || art.kind === 'select' || art.kind === '$join')
|
|
718
|
-
? art : art._parent ); // TODO: check with name resolution change
|
|
714
|
+
(art.kind === '$tableAlias' ? art._parent._$next : art) );
|
|
719
715
|
setLink( query, '_block', art._block );
|
|
720
716
|
query.kind = 'select';
|
|
721
717
|
query.name = { location: query.location };
|
|
@@ -819,7 +815,7 @@ function define( model ) {
|
|
|
819
815
|
dictAddArray( p.$tableAliases, table.name.id, table );
|
|
820
816
|
}
|
|
821
817
|
if (table.name?.id[0] === '$' && table.name.$inferred !== '$internal') {
|
|
822
|
-
|
|
818
|
+
message( 'name-invalid-dollar-alias', [ table.name.location, table ], {
|
|
823
819
|
'#': (table.name.$inferred ? '$tableImplicit' : '$tableAlias'),
|
|
824
820
|
name: '$',
|
|
825
821
|
keyword: 'as',
|
|
@@ -841,6 +837,7 @@ function define( model ) {
|
|
|
841
837
|
}
|
|
842
838
|
|
|
843
839
|
function initExprForQuery( expr, query ) {
|
|
840
|
+
// TODO: use traverseExpr()
|
|
844
841
|
if (Array.isArray(expr)) { // TODO: old-style $parens ?
|
|
845
842
|
expr.forEach( e => initExprForQuery( e, query ) );
|
|
846
843
|
}
|
|
@@ -876,7 +873,7 @@ function define( model ) {
|
|
|
876
873
|
error( 'duplicate-definition', [ loc, query ], { name: dupName, '#': 'alias' } );
|
|
877
874
|
} );
|
|
878
875
|
if (mixin.name.id[0] === '$') {
|
|
879
|
-
|
|
876
|
+
message( 'name-invalid-dollar-alias', [ mixin.name.location, mixin ],
|
|
880
877
|
{ '#': 'mixin', name: '$' } );
|
|
881
878
|
}
|
|
882
879
|
}
|
|
@@ -891,7 +888,7 @@ function define( model ) {
|
|
|
891
888
|
if (!col) // parse error
|
|
892
889
|
continue;
|
|
893
890
|
hasItems = true;
|
|
894
|
-
if (!columns) {
|
|
891
|
+
if (!columns) { // expand or inline
|
|
895
892
|
if (parent.value)
|
|
896
893
|
setLink( col, '_pathHead', parent ); // also set for '*' in expand/inline
|
|
897
894
|
else if (parent._pathHead)
|
|
@@ -1059,12 +1056,14 @@ function define( model ) {
|
|
|
1059
1056
|
|
|
1060
1057
|
function initElementsAsEnum() {
|
|
1061
1058
|
// in extensions, extended enums are represented as elements
|
|
1059
|
+
let firstEnum = null;
|
|
1062
1060
|
for (const n in obj.elements) {
|
|
1063
1061
|
const e = obj.elements[n];
|
|
1064
1062
|
if (e.kind === 'element') {
|
|
1065
1063
|
// An "element" has `$syntax: 'enum'` if it could also be an enum
|
|
1066
1064
|
if (e.$syntax === 'enum') { // TODO: what about "just name"? (current forbidden)
|
|
1067
1065
|
e.kind = 'enum';
|
|
1066
|
+
firstEnum = firstEnum || e;
|
|
1068
1067
|
}
|
|
1069
1068
|
else {
|
|
1070
1069
|
// We do not want to complain separately about all element properties:
|
|
@@ -1076,6 +1075,13 @@ function define( model ) {
|
|
|
1076
1075
|
}
|
|
1077
1076
|
}
|
|
1078
1077
|
}
|
|
1078
|
+
if (firstEnum && block.$frontend !== 'json') {
|
|
1079
|
+
// Don't emit this message if `ext-unexpected-element` was already emitted.
|
|
1080
|
+
// This message is similar to the one above. In v5/6, we could probably remove the warning
|
|
1081
|
+
// and always emit the error.
|
|
1082
|
+
warning( 'ext-expecting-enum', [ firstEnum.location, construct ],
|
|
1083
|
+
{ code: 'extend … with enum' }, 'Use $(CODE) when extending enums' );
|
|
1084
|
+
}
|
|
1079
1085
|
forEachGeneric( { enum: obj.elements }, 'enum', init );
|
|
1080
1086
|
}
|
|
1081
1087
|
|
|
@@ -1166,10 +1172,6 @@ function define( model ) {
|
|
|
1166
1172
|
if (!elem.target)
|
|
1167
1173
|
elem.type = { ...elem.value.type, $inferred: 'cast' };
|
|
1168
1174
|
}
|
|
1169
|
-
if (elem.value.stored?.val === true && !isBetaEnabled(options, 'calculatedElementsOnWrite')) {
|
|
1170
|
-
const loc = [ elem.value.stored.location, elem ];
|
|
1171
|
-
message( 'def-unsupported-calc-elem', loc, { '#': 'on-write' } );
|
|
1172
|
-
}
|
|
1173
1175
|
elem.$syntax = 'calc';
|
|
1174
1176
|
}
|
|
1175
1177
|
}
|
|
@@ -1190,8 +1192,11 @@ function define( model ) {
|
|
|
1190
1192
|
}
|
|
1191
1193
|
const first = params[Object.keys( params )[0] || ''];
|
|
1192
1194
|
const type = first?.type || first?.items?.type; // this sequence = no derived type
|
|
1193
|
-
|
|
1195
|
+
const path = type?.path;
|
|
1196
|
+
if (path?.length === 1 && path[0]?.id === '$self') { // TODO: no where: ?
|
|
1194
1197
|
setLink( type, '_artifact', boundSelfParamType );
|
|
1198
|
+
setLink( path[0], '_artifact', boundSelfParamType );
|
|
1199
|
+
}
|
|
1195
1200
|
}
|
|
1196
1201
|
|
|
1197
1202
|
// To be reworked -------------------------------------------------------------
|
|
@@ -1212,11 +1217,11 @@ function define( model ) {
|
|
|
1212
1217
|
return true;
|
|
1213
1218
|
const location = dict[$location];
|
|
1214
1219
|
if (prop === 'actions') {
|
|
1215
|
-
error( 'unexpected-actions', [ location, construct ], {},
|
|
1220
|
+
error( 'def-unexpected-actions', [ location, construct ], {},
|
|
1216
1221
|
'Actions and functions only exist top-level and for entities' );
|
|
1217
1222
|
}
|
|
1218
1223
|
else if (parent.kind === 'action' || parent.kind === 'function') {
|
|
1219
|
-
error( '
|
|
1224
|
+
error( 'ext-unexpected-action', [ construct.location, construct ], { '#': parent.kind }, {
|
|
1220
1225
|
std: 'Actions and functions can\'t be extended, only annotated',
|
|
1221
1226
|
action: 'Actions can\'t be extended, only annotated',
|
|
1222
1227
|
function: 'Functions can\'t be extended, only annotated',
|
|
@@ -1254,7 +1259,7 @@ function define( model ) {
|
|
|
1254
1259
|
error( 'extend-columns', [ location, construct ], { art: construct } );
|
|
1255
1260
|
}
|
|
1256
1261
|
else { // if (prop === 'enum') {
|
|
1257
|
-
error( 'unexpected-enum', [ location, construct ], {},
|
|
1262
|
+
error( 'def-unexpected-enum', [ location, construct ], {},
|
|
1258
1263
|
'Enum symbols can only be defined for types or typed constructs' );
|
|
1259
1264
|
}
|
|
1260
1265
|
return construct === parent;
|
|
@@ -1270,7 +1275,7 @@ function define( model ) {
|
|
|
1270
1275
|
}
|
|
1271
1276
|
if (elem.targetAspect || options.parseCdl || !isDirectComposition( elem ))
|
|
1272
1277
|
return false;
|
|
1273
|
-
const name = resolveUncheckedPath( target, '
|
|
1278
|
+
const name = resolveUncheckedPath( target, 'target', elem );
|
|
1274
1279
|
const aspect = name && model.definitions[name];
|
|
1275
1280
|
return aspect && (aspect.kind === 'aspect' || aspect.kind === 'type'); // type is sloppy
|
|
1276
1281
|
}
|