@sap/cds-compiler 3.6.2 → 3.8.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 +109 -1
- package/README.md +3 -0
- package/bin/cdsc.js +12 -5
- package/doc/CHANGELOG_ARCHIVE.md +6 -6
- package/doc/CHANGELOG_BETA.md +35 -2
- package/doc/CHANGELOG_DEPRECATED.md +2 -2
- package/doc/DeprecatedOptions_v2.md +1 -1
- package/doc/NameResolution.md +1 -1
- package/lib/api/main.js +63 -23
- package/lib/api/options.js +1 -0
- package/lib/api/validate.js +5 -0
- package/lib/base/dictionaries.js +15 -3
- package/lib/base/keywords.js +2 -0
- package/lib/base/message-registry.js +120 -34
- package/lib/base/messages.js +51 -27
- package/lib/base/model.js +4 -2
- package/lib/base/shuffle.js +2 -1
- package/lib/checks/arrayOfs.js +1 -1
- package/lib/checks/defaultValues.js +1 -1
- package/lib/checks/elements.js +29 -1
- package/lib/checks/{emptyOrOnlyVirtual.js → hasPersistedElements.js} +10 -6
- package/lib/checks/invalidTarget.js +1 -1
- package/lib/checks/nonexpandableStructured.js +1 -1
- package/lib/checks/onConditions.js +15 -9
- package/lib/checks/sql-snippets.js +2 -2
- package/lib/checks/types.js +5 -1
- package/lib/checks/validator.js +7 -3
- package/lib/compiler/assert-consistency.js +42 -26
- package/lib/compiler/base.js +50 -4
- package/lib/compiler/builtins.js +17 -8
- package/lib/compiler/checks.js +241 -246
- package/lib/compiler/define.js +113 -146
- package/lib/compiler/extend.js +889 -383
- package/lib/compiler/finalize-parse-cdl.js +5 -58
- package/lib/compiler/index.js +1 -1
- package/lib/compiler/kick-start.js +7 -8
- package/lib/compiler/populate.js +297 -293
- package/lib/compiler/propagator.js +27 -18
- package/lib/compiler/resolve.js +146 -463
- package/lib/compiler/shared.js +36 -79
- package/lib/compiler/tweak-assocs.js +30 -28
- package/lib/compiler/utils.js +31 -5
- package/lib/edm/annotations/genericTranslation.js +131 -59
- package/lib/edm/annotations/preprocessAnnotations.js +3 -0
- package/lib/edm/csn2edm.js +22 -5
- package/lib/edm/edm.js +6 -4
- package/lib/edm/edmAnnoPreprocessor.js +1 -0
- package/lib/edm/edmPreprocessor.js +42 -26
- package/lib/gen/Dictionary.json +38 -2
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +3 -1
- package/lib/gen/languageLexer.js +1 -1
- package/lib/gen/languageParser.js +4828 -4472
- package/lib/inspect/inspectPropagation.js +20 -34
- package/lib/json/from-csn.js +140 -44
- package/lib/json/to-csn.js +114 -122
- package/lib/language/errorStrategy.js +2 -0
- package/lib/language/genericAntlrParser.js +156 -36
- package/lib/language/language.g4 +100 -58
- package/lib/language/textUtils.js +13 -0
- package/lib/main.d.ts +43 -3
- package/lib/main.js +4 -2
- package/lib/model/csnRefs.js +15 -3
- package/lib/model/csnUtils.js +12 -74
- package/lib/model/revealInternalProperties.js +4 -2
- package/lib/modelCompare/compare.js +2 -1
- package/lib/optionProcessor.js +3 -0
- package/lib/render/manageConstraints.js +5 -2
- package/lib/render/toCdl.js +216 -104
- package/lib/render/toHdbcds.js +2 -9
- package/lib/render/toRename.js +14 -51
- package/lib/render/toSql.js +4 -3
- package/lib/render/utils/common.js +9 -5
- package/lib/transform/braceExpression.js +6 -0
- package/lib/transform/db/assertUnique.js +2 -1
- package/lib/transform/db/expansion.js +2 -0
- package/lib/transform/db/flattening.js +37 -36
- package/lib/transform/db/rewriteCalculatedElements.js +600 -0
- package/lib/transform/db/transformExists.js +4 -0
- package/lib/transform/db/views.js +40 -37
- package/lib/transform/forOdataNew.js +20 -15
- package/lib/transform/forRelationalDB.js +58 -41
- package/lib/transform/odata/typesExposure.js +50 -15
- package/lib/transform/parseExpr.js +16 -8
- package/lib/transform/transformUtilsNew.js +42 -14
- package/lib/transform/translateAssocsToJoins.js +60 -37
- package/lib/transform/universalCsn/coreComputed.js +15 -7
- package/lib/transform/universalCsn/universalCsnEnricher.js +4 -4
- package/package.json +2 -1
package/lib/compiler/define.js
CHANGED
|
@@ -119,7 +119,11 @@
|
|
|
119
119
|
|
|
120
120
|
'use strict';
|
|
121
121
|
|
|
122
|
-
const {
|
|
122
|
+
const {
|
|
123
|
+
forEachGeneric,
|
|
124
|
+
forEachInOrder,
|
|
125
|
+
forEachMember,
|
|
126
|
+
} = require('../base/model');
|
|
123
127
|
const shuffleGen = require('../base/shuffle');
|
|
124
128
|
const {
|
|
125
129
|
dictAdd, dictAddArray, dictForEach, pushToDict,
|
|
@@ -132,7 +136,6 @@ const {
|
|
|
132
136
|
dependsOnSilent,
|
|
133
137
|
pathName,
|
|
134
138
|
splitIntoPath,
|
|
135
|
-
annotationHasEllipsis,
|
|
136
139
|
isDirectComposition,
|
|
137
140
|
} = require('./utils');
|
|
138
141
|
const { compareLayer } = require('./moduleLayers');
|
|
@@ -160,19 +163,15 @@ function define( model ) {
|
|
|
160
163
|
} = model.$messageFunctions;
|
|
161
164
|
const {
|
|
162
165
|
resolveUncheckedPath,
|
|
163
|
-
checkAnnotate,
|
|
164
166
|
} = model.$functions;
|
|
165
167
|
const { shuffleDict, shuffleArray } = shuffleGen( options.testMode );
|
|
166
168
|
|
|
167
|
-
const extensionsDict = Object.create(null);
|
|
168
169
|
Object.assign( model.$functions, {
|
|
169
170
|
shuffleDict,
|
|
170
171
|
shuffleArray,
|
|
171
172
|
initArtifact,
|
|
172
173
|
initMembers,
|
|
173
|
-
|
|
174
|
-
checkDefinitions,
|
|
175
|
-
initAnnotations,
|
|
174
|
+
checkDefinitions, // TODO: remove
|
|
176
175
|
} );
|
|
177
176
|
// During the definer, we can only resolve artifact references, i.e,
|
|
178
177
|
// after a `.`, we only search in the `_subArtifacts` dictionary:
|
|
@@ -202,7 +201,7 @@ function define( model ) {
|
|
|
202
201
|
setLink( model, '_entities', [] ); // for entities with includes
|
|
203
202
|
model.$entity = 0;
|
|
204
203
|
model.$compositionTargets = Object.create(null);
|
|
205
|
-
model.$lateExtensions = Object.create(null); //
|
|
204
|
+
model.$lateExtensions = Object.create(null); // TODO: rename to $collectedExtensions
|
|
206
205
|
|
|
207
206
|
initBuiltins( model );
|
|
208
207
|
const sourceNames = shuffleArray( Object.keys( model.sources ) );
|
|
@@ -212,7 +211,7 @@ function define( model ) {
|
|
|
212
211
|
initNamespaceAndUsing( model.sources[name] );
|
|
213
212
|
dictForEach( model.definitions, initArtifact );
|
|
214
213
|
dictForEach( model.vocabularies, initVocabulary );
|
|
215
|
-
dictForEach(
|
|
214
|
+
dictForEach( model.$lateExtensions, e => e._extensions.forEach( initExtension ) );
|
|
216
215
|
|
|
217
216
|
addI18nBlocks();
|
|
218
217
|
}
|
|
@@ -398,19 +397,52 @@ function define( model ) {
|
|
|
398
397
|
return;
|
|
399
398
|
delete ext.name.path[0]._artifact; // might point to wrong JS object in phase 1
|
|
400
399
|
ext.name.absolute = absolute; // definition might not be there yet, no _artifact link
|
|
401
|
-
|
|
400
|
+
const location = { file: '' }; // stupid required location
|
|
401
|
+
const late = model.$lateExtensions[absolute] ||
|
|
402
|
+
(model.$lateExtensions[absolute] = {
|
|
403
|
+
kind: 'annotate',
|
|
404
|
+
name: { absolute, location },
|
|
405
|
+
$inferred: '',
|
|
406
|
+
location,
|
|
407
|
+
});
|
|
408
|
+
pushToDict( late, '_extensions', ext );
|
|
402
409
|
if (!ext.artifacts)
|
|
403
410
|
return;
|
|
411
|
+
|
|
404
412
|
// Directly add the artifacts of context and service extension:
|
|
405
413
|
if (!model.$blocks)
|
|
406
414
|
model.$blocks = Object.create( null );
|
|
407
415
|
// Set block number for debugging (--raw-output):
|
|
408
416
|
// eslint-disable-next-line no-multi-assign
|
|
409
417
|
ext.name.select = model.$blocks[absolute] = (model.$blocks[absolute] || 0) + 1;
|
|
418
|
+
// add "namespace" for the case that ext.artifacts is empty (TODO: later)
|
|
419
|
+
// now add all definitions in ext.artifacts:
|
|
410
420
|
const prefix = `${ absolute }.`;
|
|
411
421
|
dictForEach( ext.artifacts, a => addArtifact( a, ext, prefix ) );
|
|
412
422
|
}
|
|
413
423
|
|
|
424
|
+
function initExtension( parent ) {
|
|
425
|
+
forEachMember( parent, function init( sub ) {
|
|
426
|
+
if (sub.kind !== 'extend' && sub.kind !== 'annotate')
|
|
427
|
+
return; // for defs inside, set somewhere else - TODO: rethink
|
|
428
|
+
setLink( sub, '_block', parent._block );
|
|
429
|
+
setLink( sub, '_parent', parent );
|
|
430
|
+
setLink( sub, '_main', parent._main || parent );
|
|
431
|
+
initExtension( sub );
|
|
432
|
+
} );
|
|
433
|
+
if (parent.kind !== 'extend')
|
|
434
|
+
return;
|
|
435
|
+
if (parent.columns) // TODO: sub queries? expand/inline?
|
|
436
|
+
parent.columns.forEach( c => setLink( c, '_block', parent._block ) );
|
|
437
|
+
if (parent.scale && !parent.precision) {
|
|
438
|
+
// TODO: where could we store the location of the name?
|
|
439
|
+
error( 'syntax-missing-type-property', [ parent.scale.location ],
|
|
440
|
+
{ prop: 'scale', otherprop: 'precision' },
|
|
441
|
+
'Type extension with property $(PROP) must also have property $(OTHERPROP)' );
|
|
442
|
+
parent.scale = undefined; // no consequential error
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
414
446
|
function addVocabulary( vocab, block, prefix ) {
|
|
415
447
|
setLink( vocab, '_block', block );
|
|
416
448
|
const { name } = vocab;
|
|
@@ -534,13 +566,10 @@ function define( model ) {
|
|
|
534
566
|
initArtifactParentLink( art, model.definitions );
|
|
535
567
|
const block = art._block;
|
|
536
568
|
checkRedefinition( art );
|
|
537
|
-
initAnnotations( art, block );
|
|
538
569
|
initMembers( art, art, block );
|
|
539
570
|
initDollarSelf( art ); // $self
|
|
540
571
|
if (art.params)
|
|
541
572
|
initDollarParameters( art );
|
|
542
|
-
if (art.includes && !(art.name.absolute in extensionsDict)) // TODO: in next phase?
|
|
543
|
-
extensionsDict[art.name.absolute] = []; // structure with includes must be "extended"
|
|
544
573
|
|
|
545
574
|
if (!art.query)
|
|
546
575
|
return;
|
|
@@ -548,6 +577,7 @@ function define( model ) {
|
|
|
548
577
|
setLink( art, '_from', [] ); // for sequence of resolve steps
|
|
549
578
|
if (!setLink( art, '_leadingQuery', initQueryExpression( art.query, art ) ) )
|
|
550
579
|
return; // null or undefined in case of parse error
|
|
580
|
+
// if (art._leadingQuery !== art.$queries [0]) throw Error('FOO');
|
|
551
581
|
setLink( art._leadingQuery, '_$next', art );
|
|
552
582
|
if (art.elements) { // specified element via compilation of client-style CSN
|
|
553
583
|
// TODO: consider this part of a revamped on-demand 'extend' functionality
|
|
@@ -560,7 +590,6 @@ function define( model ) {
|
|
|
560
590
|
initArtifactParentLink( art, model.vocabularies );
|
|
561
591
|
checkRedefinition( art );
|
|
562
592
|
const block = art._block;
|
|
563
|
-
initAnnotations( art, block );
|
|
564
593
|
initMembers( art, art, block );
|
|
565
594
|
}
|
|
566
595
|
|
|
@@ -586,57 +615,6 @@ function define( model ) {
|
|
|
586
615
|
parent._subArtifacts[absolute.substring( dot + 1 )] = art; // not dictAdd()
|
|
587
616
|
}
|
|
588
617
|
|
|
589
|
-
/** Initialize the extension `ext`.
|
|
590
|
-
*
|
|
591
|
-
* Currently:
|
|
592
|
-
*
|
|
593
|
-
* - initialize annotations (set _block, $priority, `...` check) on "main"
|
|
594
|
-
* extension and its columns do more later
|
|
595
|
-
* - for members in compile(): init annotations via extendMembers/annotateMembers
|
|
596
|
-
* - for members in parse.cdl(): init annotation via initMembers
|
|
597
|
-
*
|
|
598
|
-
* In the future (after name cleanup):
|
|
599
|
-
*
|
|
600
|
-
* - also initialize members and member extensions/annotations here
|
|
601
|
-
* - we might also do other things, like calculating whether an `extend` is
|
|
602
|
-
* `annotate`-like, i.e. only contains name-resolution irrelevant extensions.
|
|
603
|
-
*/
|
|
604
|
-
function initExtension( ext ) {
|
|
605
|
-
const block = ext._block;
|
|
606
|
-
initAnnotations( ext, block, ext.kind );
|
|
607
|
-
if (ext.columns) // the columns themselves are "definitions"
|
|
608
|
-
ext.columns.forEach( col => initAnnotations( col, block ) );
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
// Set _block links for annotations (necessary for layering) and do a late
|
|
612
|
-
// syntax check (`...` only with extensions, not definitions).
|
|
613
|
-
// extKind is either ext.kind (=art is extension) or false (=art is not an extension)
|
|
614
|
-
function initAnnotations( art, block, extKind = false ) {
|
|
615
|
-
// TODO: think of removing $priority, then
|
|
616
|
-
// no _block: define, _block: annotate/extend/edmx
|
|
617
|
-
// would fit with extending defs with props like length
|
|
618
|
-
for (const prop in art) {
|
|
619
|
-
if (prop.charAt(0) === '@' || prop === 'doc') {
|
|
620
|
-
const anno = art[prop];
|
|
621
|
-
// TODO: make anno never be an array, see addAnnotation() in genericAntlrParser
|
|
622
|
-
if (Array.isArray( anno ))
|
|
623
|
-
anno.forEach( init );
|
|
624
|
-
else
|
|
625
|
-
init( anno );
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
return;
|
|
629
|
-
|
|
630
|
-
function init( anno ) {
|
|
631
|
-
setLink( anno, '_block', block );
|
|
632
|
-
anno.$priority = extKind;
|
|
633
|
-
if (!extKind && annotationHasEllipsis( anno )) {
|
|
634
|
-
error( 'anno-unexpected-ellipsis',
|
|
635
|
-
[ anno.name.location, art ], { code: '...' } );
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
|
|
640
618
|
// Init special things: -------------------------------------------------------
|
|
641
619
|
|
|
642
620
|
function initDollarSelf( art ) {
|
|
@@ -708,7 +686,6 @@ function define( model ) {
|
|
|
708
686
|
setLink( self, '_origin', query );
|
|
709
687
|
setLink( self, '_parent', query );
|
|
710
688
|
setLink( self, '_main', query._main );
|
|
711
|
-
setLink( self, '_effectiveType', query ); // TODO: remove
|
|
712
689
|
query.$tableAliases.$self = self;
|
|
713
690
|
query.$tableAliases.$projection = self;
|
|
714
691
|
}
|
|
@@ -770,15 +747,16 @@ function define( model ) {
|
|
|
770
747
|
// _origin is set when we resolve the ref
|
|
771
748
|
if (query._parent.kind !== 'select')
|
|
772
749
|
query._main._from.push( table ); // store tabref if outside "real" subquery
|
|
750
|
+
// (tab refs on the right of union are unnecessary)
|
|
773
751
|
}
|
|
774
752
|
else if (table.query) {
|
|
775
|
-
if (!table.name
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
753
|
+
if (!table.name?.id) {
|
|
754
|
+
// We don't worry about duplicate names here.
|
|
755
|
+
const id = `$_select_${ query._main.$queries.length + 1 }__`;
|
|
756
|
+
table.name = { id, location: table.location, $inferred: '$internal' };
|
|
757
|
+
table.$inferred = '$internal';
|
|
779
758
|
}
|
|
780
759
|
addAsAlias();
|
|
781
|
-
setLink( table, '_effectiveType', table.query ); // TODO: remove!
|
|
782
760
|
// Store _origin to leading query of table.query for name resolution
|
|
783
761
|
setLink( table, '_origin', initQueryExpression( table.query, table ) );
|
|
784
762
|
}
|
|
@@ -823,8 +801,15 @@ function define( model ) {
|
|
|
823
801
|
table.kind = '$tableAlias';
|
|
824
802
|
setMemberParent( table, table.name.id, query );
|
|
825
803
|
setLink( table, '_block', query._block );
|
|
826
|
-
dictAdd( query.$tableAliases, table.name.id, table, ( name, loc ) => {
|
|
827
|
-
|
|
804
|
+
dictAdd( query.$tableAliases, table.name.id, table, ( name, loc, tableAlias ) => {
|
|
805
|
+
if (tableAlias.$inferred === '$internal') {
|
|
806
|
+
const semanticLoc = tableAlias.query?.name ? tableAlias.query : tableAlias;
|
|
807
|
+
error( 'name-missing-alias', [ tableAlias.location, semanticLoc ],
|
|
808
|
+
{ '#': 'duplicate', code: 'as ‹alias›' });
|
|
809
|
+
}
|
|
810
|
+
else {
|
|
811
|
+
error( 'duplicate-definition', [ loc, table ], { name, '#': 'alias' } );
|
|
812
|
+
}
|
|
828
813
|
} );
|
|
829
814
|
// also add to JOIN nodes for name restrictions:
|
|
830
815
|
for (const p of joinParents) {
|
|
@@ -832,7 +817,7 @@ function define( model ) {
|
|
|
832
817
|
// already used for duplicate aliases of queries:
|
|
833
818
|
dictAddArray( p.$tableAliases, table.name.id, table );
|
|
834
819
|
}
|
|
835
|
-
if (table.name
|
|
820
|
+
if (table.name?.id[0] === '$' && table.name.$inferred !== '$internal') {
|
|
836
821
|
warning( 'name-invalid-dollar-alias', [ table.name.location, table ], {
|
|
837
822
|
'#': (table.name.$inferred ? '$tableImplicit' : '$tableAlias'),
|
|
838
823
|
name: '$',
|
|
@@ -935,7 +920,6 @@ function define( model ) {
|
|
|
935
920
|
// Either expression (value), expand or new association (target && type)
|
|
936
921
|
else if (col.value || col.expand || (col.target && col.type)) {
|
|
937
922
|
setLink( col, '_block', parent._block );
|
|
938
|
-
initAnnotations( col, parent._block );
|
|
939
923
|
if (col.inline) { // `@anno elem.{ * }` does not work
|
|
940
924
|
if (col.doc) {
|
|
941
925
|
warning( 'syntax-ignoring-anno', [ col.doc.location, col ],
|
|
@@ -1010,12 +994,14 @@ function define( model ) {
|
|
|
1010
994
|
*
|
|
1011
995
|
* If not for extensions: construct === parent
|
|
1012
996
|
*
|
|
997
|
+
* Param `initExtensions` is for parse.cdl - TODO delete
|
|
998
|
+
*
|
|
1013
999
|
* TODO: separate extension!
|
|
1014
1000
|
*/
|
|
1015
1001
|
function initMembers( construct, parent, block, initExtensions = false ) {
|
|
1016
1002
|
// TODO: split extend from init
|
|
1017
1003
|
const main = parent._main || parent;
|
|
1018
|
-
const isQueryExtension =
|
|
1004
|
+
const isQueryExtension = construct.kind === 'extend' && main.query;
|
|
1019
1005
|
let obj = construct;
|
|
1020
1006
|
let { items } = obj;
|
|
1021
1007
|
while (items) {
|
|
@@ -1043,46 +1029,8 @@ function define( model ) {
|
|
|
1043
1029
|
'A managed aspect composition can\'t have a specified ON-condition' );
|
|
1044
1030
|
delete obj.on; // continuation semantics: not specified
|
|
1045
1031
|
}
|
|
1046
|
-
if (targetAspect.elements)
|
|
1047
|
-
|
|
1048
|
-
const inEntity = parent._main && parent._main.kind === 'entity';
|
|
1049
|
-
// TODO: also allow indirectly (component in component in entity)?
|
|
1050
|
-
setLink( targetAspect, '_outer', obj );
|
|
1051
|
-
setLink( targetAspect, '_parent', parent._parent );
|
|
1052
|
-
setLink( targetAspect, '_main', null ); // for name resolution
|
|
1053
|
-
|
|
1054
|
-
parent = targetAspect;
|
|
1055
|
-
construct = parent; // avoid extension behavior
|
|
1056
|
-
targetAspect.kind = 'aspect'; // TODO: probably '$aspect' to detect
|
|
1057
|
-
setLink( targetAspect, '_block', block );
|
|
1058
|
-
initDollarSelf( targetAspect );
|
|
1059
|
-
// allow ref of up_ in anonymous aspect inside entity
|
|
1060
|
-
// (TODO: complain if used and the managed composition is included into
|
|
1061
|
-
// another entity - might induce auto-redirection):
|
|
1062
|
-
if (inEntity && !targetAspect.elements.up_) {
|
|
1063
|
-
const up = {
|
|
1064
|
-
name: {
|
|
1065
|
-
id: 'up_',
|
|
1066
|
-
alias: 'up_',
|
|
1067
|
-
element: obj.name.element,
|
|
1068
|
-
absolute: obj.name.absolute,
|
|
1069
|
-
},
|
|
1070
|
-
kind: '$navElement',
|
|
1071
|
-
location: obj.location,
|
|
1072
|
-
};
|
|
1073
|
-
setLink( up, '_parent', targetAspect );
|
|
1074
|
-
setLink( up, '_main', targetAspect ); // used on main artifact
|
|
1075
|
-
// recompilation case: both target and targetAspect → allow up_ in that case, too:
|
|
1076
|
-
const name = obj.target && resolveUncheckedPath( obj.target, 'target', obj );
|
|
1077
|
-
const entity = name && model.definitions[name];
|
|
1078
|
-
if (entity && entity.elements)
|
|
1079
|
-
setLink( up, '_origin', entity.elements.up_ );
|
|
1080
|
-
// processAspectComposition/expand() sets _origin to element of
|
|
1081
|
-
// generated target entity
|
|
1082
|
-
targetAspect.$tableAliases.up_ = up;
|
|
1083
|
-
}
|
|
1084
|
-
obj = targetAspect;
|
|
1085
|
-
}
|
|
1032
|
+
if (targetAspect.elements)
|
|
1033
|
+
initAnonymousAspect();
|
|
1086
1034
|
}
|
|
1087
1035
|
if (obj !== parent && obj.elements && parent.enum) { // applying the extension
|
|
1088
1036
|
initElementsAsEnum();
|
|
@@ -1102,7 +1050,8 @@ function define( model ) {
|
|
|
1102
1050
|
forEachInOrder( construct, 'params', init );
|
|
1103
1051
|
const { returns } = construct;
|
|
1104
1052
|
if (returns) {
|
|
1105
|
-
|
|
1053
|
+
const { kind } = construct;
|
|
1054
|
+
returns.kind = (kind === 'extend' || kind === 'annotate') ? kind : 'param';
|
|
1106
1055
|
init( returns, '' ); // '' is special name for returns parameter
|
|
1107
1056
|
}
|
|
1108
1057
|
return;
|
|
@@ -1129,6 +1078,47 @@ function define( model ) {
|
|
|
1129
1078
|
forEachGeneric( { enum: obj.elements }, 'enum', init );
|
|
1130
1079
|
}
|
|
1131
1080
|
|
|
1081
|
+
function initAnonymousAspect() {
|
|
1082
|
+
// TODO: main?
|
|
1083
|
+
const inEntity = parent._main && parent._main.kind === 'entity';
|
|
1084
|
+
// TODO: also allow indirectly (component in component in entity)?
|
|
1085
|
+
setLink( targetAspect, '_outer', obj );
|
|
1086
|
+
setLink( targetAspect, '_parent', parent._parent );
|
|
1087
|
+
setLink( targetAspect, '_main', null ); // for name resolution
|
|
1088
|
+
|
|
1089
|
+
parent = targetAspect;
|
|
1090
|
+
construct = parent; // avoid extension behavior
|
|
1091
|
+
targetAspect.kind = 'aspect'; // TODO: probably '$aspect' to detect
|
|
1092
|
+
setLink( targetAspect, '_block', block );
|
|
1093
|
+
initDollarSelf( targetAspect );
|
|
1094
|
+
// allow ref of up_ in anonymous aspect inside entity
|
|
1095
|
+
// (TODO: complain if used and the managed composition is included into
|
|
1096
|
+
// another entity - might induce auto-redirection):
|
|
1097
|
+
if (inEntity && !targetAspect.elements.up_) {
|
|
1098
|
+
const up = {
|
|
1099
|
+
name: {
|
|
1100
|
+
id: 'up_',
|
|
1101
|
+
alias: 'up_',
|
|
1102
|
+
element: obj.name.element,
|
|
1103
|
+
absolute: obj.name.absolute,
|
|
1104
|
+
},
|
|
1105
|
+
kind: '$navElement',
|
|
1106
|
+
location: obj.location,
|
|
1107
|
+
};
|
|
1108
|
+
setLink( up, '_parent', targetAspect );
|
|
1109
|
+
setLink( up, '_main', targetAspect ); // used on main artifact
|
|
1110
|
+
// recompilation case: both target and targetAspect → allow up_ in that case, too:
|
|
1111
|
+
const name = obj.target && resolveUncheckedPath( obj.target, 'target', obj );
|
|
1112
|
+
const entity = name && model.definitions[name];
|
|
1113
|
+
if (entity && entity.elements)
|
|
1114
|
+
setLink( up, '_origin', entity.elements.up_ );
|
|
1115
|
+
// processAspectComposition/expand() sets _origin to element of
|
|
1116
|
+
// generated target entity
|
|
1117
|
+
targetAspect.$tableAliases.up_ = up;
|
|
1118
|
+
}
|
|
1119
|
+
obj = targetAspect;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1132
1122
|
function init( elem, name, prop ) {
|
|
1133
1123
|
if (!elem.kind) // wrong CSN input
|
|
1134
1124
|
elem.kind = dictKinds[prop];
|
|
@@ -1138,12 +1128,12 @@ function define( model ) {
|
|
|
1138
1128
|
elem.name = Object.assign( { $inferred: 'as' },
|
|
1139
1129
|
ref.path[ref.path.length - 1] );
|
|
1140
1130
|
}
|
|
1141
|
-
else { //
|
|
1131
|
+
else { // RETURNS, parser robustness
|
|
1142
1132
|
elem.name = { id: name, location: elem.location };
|
|
1143
1133
|
}
|
|
1144
1134
|
}
|
|
1145
1135
|
// if (!kindProperties[ elem.kind ]) console.log(elem.kind,elem.name)
|
|
1146
|
-
if (
|
|
1136
|
+
if ((elem.kind === 'extend' || elem.kind === 'annotate') && !initExtensions) {
|
|
1147
1137
|
storeExtension( elem, name, prop, parent, block );
|
|
1148
1138
|
return;
|
|
1149
1139
|
}
|
|
@@ -1161,9 +1151,6 @@ function define( model ) {
|
|
|
1161
1151
|
setMemberParent( elem, name, parent, add && prop );
|
|
1162
1152
|
// console.log(message( null, elem.location, elem, {}, 'Info', 'INIT').toString())
|
|
1163
1153
|
checkRedefinition( elem );
|
|
1164
|
-
if (elem.kind === 'annotate' || elem.kind === 'extend')
|
|
1165
|
-
checkAnnotate( elem, elem );
|
|
1166
|
-
initAnnotations( elem, bl );
|
|
1167
1154
|
initMembers( elem, elem, bl, initExtensions );
|
|
1168
1155
|
if (boundSelfParamType && (elem.kind === 'action' || elem.kind === 'function'))
|
|
1169
1156
|
initBoundSelfParam( elem.params );
|
|
@@ -1174,31 +1161,11 @@ function define( model ) {
|
|
|
1174
1161
|
elem.$syntax === 'enum' && parent.kind === 'extend') // ambiguous in parse-cdl
|
|
1175
1162
|
return;
|
|
1176
1163
|
// -> it's a calculated element
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
function checkCalculatedElement( elem ) {
|
|
1183
|
-
const loc = [ elem.value.location, elem ];
|
|
1184
|
-
if (elem._main.kind !== 'entity' && elem._main.kind !== 'aspect' &&
|
|
1185
|
-
elem._main.kind !== 'extend') {
|
|
1186
|
-
error( 'syntax-invalid-calc-elem', loc, { '#': elem._main.kind } );
|
|
1187
|
-
}
|
|
1188
|
-
else if (!isBetaEnabled( options, 'calculatedElements' )) {
|
|
1189
|
-
error( 'def-unsupported-calc-elem', loc,
|
|
1190
|
-
'Calculated elements are not supported' );
|
|
1191
|
-
}
|
|
1192
|
-
else {
|
|
1193
|
-
const noTruthyAllowed = [ 'localized', 'key', 'virtual' ];
|
|
1194
|
-
for (const prop of noTruthyAllowed) {
|
|
1195
|
-
if (elem[prop]?.val) {
|
|
1196
|
-
// probably better than a parse error (which is good for DEFAULT vs calc),
|
|
1197
|
-
// also appears with parse-cdl:
|
|
1198
|
-
error('syntax-invalid-calc-elem', loc, { '#': prop });
|
|
1199
|
-
return; // one error is enough
|
|
1200
|
-
}
|
|
1164
|
+
if (!elem.type && elem.value?.type) { // top-level CAST( expr AS type )
|
|
1165
|
+
if (!elem.target)
|
|
1166
|
+
elem.type = { ...elem.value.type, $inferred: 'cast' };
|
|
1201
1167
|
}
|
|
1168
|
+
elem.$syntax = 'calc';
|
|
1202
1169
|
}
|
|
1203
1170
|
}
|
|
1204
1171
|
|