@sap/cds-compiler 6.5.0 → 6.6.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 +34 -0
- package/bin/cdsc.js +1 -1
- package/lib/api/main.js +0 -3
- package/lib/base/builtins.js +2 -1
- package/lib/base/message-registry.js +13 -14
- package/lib/base/model.js +0 -1
- package/lib/checks/sql-snippets.js +8 -0
- package/lib/checks/validator.js +4 -2
- package/lib/compiler/define.js +102 -115
- package/lib/compiler/extend.js +67 -37
- package/lib/compiler/finalize-parse-cdl.js +1 -1
- package/lib/compiler/generate.js +34 -11
- package/lib/compiler/index.js +2 -2
- package/lib/compiler/kick-start.js +26 -35
- package/lib/compiler/populate.js +4 -7
- package/lib/compiler/propagator.js +20 -1
- package/lib/compiler/resolve.js +26 -1
- package/lib/compiler/shared.js +49 -9
- package/lib/compiler/utils.js +2 -2
- package/lib/edm/annotations/edmJson.js +111 -37
- package/lib/edm/annotations/genericTranslation.js +3 -1
- package/lib/main.d.ts +0 -3
- package/lib/main.js +2 -0
- package/lib/model/csnRefs.js +6 -1
- package/lib/render/toSql.js +0 -4
- package/lib/transform/db/applyTransformations.js +1 -1
- package/lib/transform/db/associations.js +24 -15
- package/lib/transform/db/flattening.js +1 -1
- package/lib/transform/db/views.js +0 -39
- package/lib/transform/effective/associations.js +5 -55
- package/lib/transform/effective/main.js +4 -2
- package/lib/transform/effective/misc.js +1 -1
- package/lib/transform/effective/types.js +36 -12
- package/lib/transform/forOdata.js +126 -3
- package/lib/transform/forRelationalDB.js +13 -4
- package/lib/transform/transformUtils.js +51 -1
- package/lib/transform/translateAssocsToJoins.js +43 -19
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -13,6 +13,40 @@ we might not list every change in its behavior here.
|
|
|
13
13
|
Productive code should never require a `beta` flag to be set, and
|
|
14
14
|
might use a deprecated flag only for a limited period of time.
|
|
15
15
|
|
|
16
|
+
## Version 6.6.0 - 2025-12-12
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- compiler:
|
|
21
|
+
+ Support for upcoming ESlint rules (by other team) for Fiori elements annotations.
|
|
22
|
+
+ Namespace `cds.dataproducts` is no longer reserved by the cds-compiler. It is used by the CAP @sap/cds-data-products plugin.
|
|
23
|
+
- for.odata/to.edm(x):
|
|
24
|
+
+ Enumeration symbols are now supported in annotation expression syntax.
|
|
25
|
+
+ For projections and views, the `@hierarchy` annotation now triggers generation of
|
|
26
|
+
additional Fiori Tree View relevant annotations and fields.
|
|
27
|
+
- for.effective: First non-beta release.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- `to.sql`: Annotating a foreign key of an association in a view with a sql-snippet annotation (e.g. `@sql.append`)
|
|
32
|
+
now results in an error. This is the default behaviour for any element in a view.
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- compiler:
|
|
37
|
+
+ Minor fixes for auto-redirections and recompilation with localized data
|
|
38
|
+
in very rare situations when an aspect definition uses an entity as include.
|
|
39
|
+
+ Don't let “namespaces” prevent the compiler to generate texts/target entities.
|
|
40
|
+
- to.sql: Improve foreign key flattening for various edge cases.
|
|
41
|
+
|
|
42
|
+
## Version 6.5.2 - 2025-12-02
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
|
|
46
|
+
- to.sql|hdi:
|
|
47
|
+
+ Don't add superfluous (and actually wrong) parentheses around `UNION`s
|
|
48
|
+
+ Don't dump with a specific column expressions in the query after a `UNION`
|
|
49
|
+
|
|
16
50
|
## Version 6.5.0 - 2025-11-21
|
|
17
51
|
|
|
18
52
|
### Added
|
package/bin/cdsc.js
CHANGED
|
@@ -153,7 +153,7 @@ function cdscMain() {
|
|
|
153
153
|
// Internally, parseCdl/parseOnly are options, so we map the command to it.
|
|
154
154
|
if (cmdLine.command === 'parse') {
|
|
155
155
|
cmdLine.command = 'toCsn';
|
|
156
|
-
cmdLine.options.toCsn = cmdLine.options.parseCdl;
|
|
156
|
+
cmdLine.options.toCsn = cmdLine.options.parse || cmdLine.options.parseCdl;
|
|
157
157
|
cmdLine.options.parseCdl = true;
|
|
158
158
|
cmdLine.args.files = [ cmdLine.args.file ];
|
|
159
159
|
}
|
package/lib/api/main.js
CHANGED
|
@@ -321,9 +321,6 @@ function forSeal( csn, options, messageFunctions ) {
|
|
|
321
321
|
function forEffective( csn, options, messageFunctions ) {
|
|
322
322
|
const internalOptions = prepareOptions.for.effective(options);
|
|
323
323
|
internalOptions.transformation = 'effective';
|
|
324
|
-
// for.effective is still beta mode
|
|
325
|
-
if (!baseModel.isBetaEnabled(options, 'effectiveCsn'))
|
|
326
|
-
throw new baseError.CompilerAssertion('effective CSN is only supported with beta flag `effectiveCsn`!');
|
|
327
324
|
|
|
328
325
|
return forEffectiveInternal(csn, options, internalOptions, messageFunctions);
|
|
329
326
|
}
|
package/lib/base/builtins.js
CHANGED
|
@@ -50,7 +50,8 @@ function isInReservedNamespace( absolute ) {
|
|
|
50
50
|
!absolute.match( /^cds\.foundation(\.|$)/ ) &&
|
|
51
51
|
!absolute.match( /^cds\.outbox(\.|$)/ ) && // Requested by Node runtime
|
|
52
52
|
!absolute.match( /^cds\.core(\.|$)/ ) && // Requested by Node runtime
|
|
53
|
-
!absolute.match( /^cds\.xt(\.|$)/ )
|
|
53
|
+
!absolute.match( /^cds\.xt(\.|$)/ ) && // Requested by Mtx
|
|
54
|
+
!absolute.match( /^cds\.dataproducts(\.|$)/ ); // Requested by @sap/cds-data-products
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
/**
|
|
@@ -735,7 +735,6 @@ const centralMessageTexts = {
|
|
|
735
735
|
},
|
|
736
736
|
'ref-undefined-art': {
|
|
737
737
|
std: 'No artifact has been found with name $(ART)',
|
|
738
|
-
namespace: 'No artifact has been found with name $(ART) which can be extended with annotations',
|
|
739
738
|
localized: 'Can\'t extend localized definitions, only annotate them using an $(KEYWORD) statement',
|
|
740
739
|
},
|
|
741
740
|
// TODO: proposal 'No definition found for $(NAME)',
|
|
@@ -959,28 +958,28 @@ const centralMessageTexts = {
|
|
|
959
958
|
'ext-undefined-art-sec': 'No artifact has been found with name $(ART)',
|
|
960
959
|
'ext-undefined-element': {
|
|
961
960
|
std: 'Element $(NAME) has not been found',
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
returns: '
|
|
965
|
-
|
|
961
|
+
enum: 'Enum symbol $(NAME) has not been found',
|
|
962
|
+
returns: 'The return value has no element $(NAME)',
|
|
963
|
+
'enum-returns': 'The return value has no enum $(NAME)',
|
|
964
|
+
},
|
|
965
|
+
'ext-undefined-element-sec': {
|
|
966
|
+
std: 'Element $(NAME) has not been found',
|
|
967
|
+
enum: 'Enum symbol $(NAME) has not been found',
|
|
968
|
+
returns: 'The return value has no element $(NAME)',
|
|
969
|
+
'enum-returns': 'The return value has no enum $(NAME)',
|
|
966
970
|
},
|
|
967
|
-
'ext-undefined-element-sec': 'Element $(NAME) has not been found',
|
|
968
971
|
'ext-undefined-key': 'Foreign key $(NAME) has not been found',
|
|
969
972
|
'ext-undefined-action': {
|
|
970
|
-
std: 'Action $(
|
|
971
|
-
action: 'Artifact $(ART) has no action $(NAME)',
|
|
973
|
+
std: 'Action $(NAME) has not been found',
|
|
972
974
|
},
|
|
973
975
|
'ext-undefined-action-sec': {
|
|
974
|
-
std: 'Action $(
|
|
975
|
-
action: 'Artifact $(ART) has no action $(NAME)',
|
|
976
|
+
std: 'Action $(NAME) has not been found',
|
|
976
977
|
},
|
|
977
978
|
'ext-undefined-param': {
|
|
978
|
-
std: 'Parameter $(
|
|
979
|
-
param: 'Artifact $(ART) has no parameter $(NAME)',
|
|
979
|
+
std: 'Parameter $(NAME) has not been found',
|
|
980
980
|
},
|
|
981
981
|
'ext-undefined-param-sec': {
|
|
982
|
-
std: 'Parameter $(
|
|
983
|
-
param: 'Artifact $(ART) has no parameter $(NAME)',
|
|
982
|
+
std: 'Parameter $(NAME) has not been found',
|
|
984
983
|
},
|
|
985
984
|
|
|
986
985
|
// annotation checks against their definition
|
package/lib/base/model.js
CHANGED
|
@@ -38,6 +38,14 @@ function checkSqlAnnotationOnElement( member, memberName, prop, path ) {
|
|
|
38
38
|
checkValidAnnoValue(member, '@sql.append', path, this.error, this.options);
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
+
|
|
42
|
+
// recursive check for keys
|
|
43
|
+
if (member.keys) {
|
|
44
|
+
for (const keyName of Object.keys(member.keys)) {
|
|
45
|
+
const key = member.keys[keyName];
|
|
46
|
+
checkSqlAnnotationOnElement.call(this, key, keyName, prop, path.concat([ 'keys', keyName ]));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
41
49
|
}
|
|
42
50
|
|
|
43
51
|
/**
|
package/lib/checks/validator.js
CHANGED
|
@@ -93,7 +93,6 @@ const forRelationalDBCsnValidators = [
|
|
|
93
93
|
navigationIntoMany,
|
|
94
94
|
checkPathsInStoredCalcElement,
|
|
95
95
|
featureFlags,
|
|
96
|
-
checkAndRemoveEnums,
|
|
97
96
|
];
|
|
98
97
|
/**
|
|
99
98
|
* @type {Array<(query: CSN.Query, path: CSN.Path) => void>}
|
|
@@ -200,8 +199,11 @@ function _validate( csn, that,
|
|
|
200
199
|
function getDBCsnValidators( options ) {
|
|
201
200
|
const validations = [ ...forRelationalDBCsnValidators ];
|
|
202
201
|
|
|
203
|
-
if (options.transformation !== 'effective')
|
|
202
|
+
if (options.transformation !== 'effective') {
|
|
203
|
+
validations.push(checkAndRemoveEnums);
|
|
204
204
|
validations.push(checkForParams.csnValidator);
|
|
205
|
+
}
|
|
206
|
+
|
|
205
207
|
if (options.sqlDialect === 'h2' || options.sqlDialect === 'postgres')
|
|
206
208
|
validations.push(checkForHanaTypes);
|
|
207
209
|
|
package/lib/compiler/define.js
CHANGED
|
@@ -140,7 +140,6 @@ const {
|
|
|
140
140
|
initDollarSelf,
|
|
141
141
|
initDollarParameters,
|
|
142
142
|
initBoundSelfParam,
|
|
143
|
-
storeExtension,
|
|
144
143
|
dependsOnSilent,
|
|
145
144
|
pathName,
|
|
146
145
|
targetCantBeAspect,
|
|
@@ -178,7 +177,7 @@ function define( model ) {
|
|
|
178
177
|
Object.assign( model.$functions, {
|
|
179
178
|
shuffleDict,
|
|
180
179
|
shuffleArray,
|
|
181
|
-
|
|
180
|
+
initMainArtifact,
|
|
182
181
|
initMembers, // for finalize-parser-cdl.js
|
|
183
182
|
targetIsTargetAspect,
|
|
184
183
|
checkRedefinition,
|
|
@@ -213,7 +212,7 @@ function define( model ) {
|
|
|
213
212
|
// Phase 2:
|
|
214
213
|
for (const name of sourceNames)
|
|
215
214
|
initNamespaceAndUsing( model.sources[name] );
|
|
216
|
-
dictForEach( model.definitions,
|
|
215
|
+
dictForEach( model.definitions, initMainArtifact );
|
|
217
216
|
dictForEach( model.vocabularies, initVocabulary );
|
|
218
217
|
dictForEach( model.$collectedExtensions, e => e._extensions.forEach( initExtension ) );
|
|
219
218
|
|
|
@@ -254,7 +253,7 @@ function define( model ) {
|
|
|
254
253
|
if (src.$frontend !== 'json') { // CDL input
|
|
255
254
|
// TODO: set _block to builtin
|
|
256
255
|
if (src.artifacts) {
|
|
257
|
-
//
|
|
256
|
+
// addBlockArtifact() adds usings to src.artifacts: shuffleDict must be assigned first
|
|
258
257
|
src.artifacts = shuffleDict( src.artifacts );
|
|
259
258
|
addPathPrefixes( src.artifacts, prefix ); // before addUsing
|
|
260
259
|
}
|
|
@@ -265,14 +264,14 @@ function define( model ) {
|
|
|
265
264
|
shuffleArray( src.usings ).forEach( u => addUsing( u, src ) );
|
|
266
265
|
if (namespace?.id) // successfully set a full name for namespace
|
|
267
266
|
addNamespace( namespace, src );
|
|
268
|
-
if (src.artifacts) { //
|
|
267
|
+
if (src.artifacts) { // addBlockArtifact needs usings for context extensions
|
|
269
268
|
src.artifacts = shuffleDict( src.artifacts );
|
|
270
|
-
dictForEach( src.artifacts, a =>
|
|
269
|
+
dictForEach( src.artifacts, a => addBlockArtifact( a, src, prefix ) );
|
|
271
270
|
}
|
|
272
271
|
}
|
|
273
272
|
else if (src.definitions) { // CSN input
|
|
274
273
|
prefix = ''; // also for addVocabulary() below
|
|
275
|
-
dictForEach( shuffleDict( src.definitions ), def =>
|
|
274
|
+
dictForEach( shuffleDict( src.definitions ), def => addMainArtifact( def, src, prefix ) );
|
|
276
275
|
}
|
|
277
276
|
if (src.vocabularies) {
|
|
278
277
|
if (!model.vocabularies)
|
|
@@ -284,7 +283,7 @@ function define( model ) {
|
|
|
284
283
|
}
|
|
285
284
|
}
|
|
286
285
|
|
|
287
|
-
function
|
|
286
|
+
function addMainArtifact( art, block, prefix ) {
|
|
288
287
|
setLink( art, '_block', block );
|
|
289
288
|
initExprAnnoBlock( art, block );
|
|
290
289
|
art.name.id ??= prefix + pathName( art.name.path );
|
|
@@ -384,15 +383,15 @@ function define( model ) {
|
|
|
384
383
|
$inferred: 'namespace',
|
|
385
384
|
};
|
|
386
385
|
}
|
|
387
|
-
function
|
|
386
|
+
function addBlockArtifact( art, block, prefix ) {
|
|
388
387
|
if (art.kind === 'using')
|
|
389
388
|
return;
|
|
390
|
-
|
|
389
|
+
addMainArtifact( art, block, prefix );
|
|
391
390
|
if (art.artifacts) {
|
|
392
391
|
const p = `${ art.name.id }.`;
|
|
393
392
|
// path prefixes (usings) must be added before extensions in artifacts:
|
|
394
393
|
addPathPrefixes( art.artifacts, p );
|
|
395
|
-
dictForEach( art.artifacts, a =>
|
|
394
|
+
dictForEach( art.artifacts, a => addBlockArtifact( a, art, p ) );
|
|
396
395
|
}
|
|
397
396
|
if (art.extensions) { // requires using to be known!
|
|
398
397
|
art.extensions.forEach( e => e.name && addExtension( e, art ) );
|
|
@@ -426,7 +425,7 @@ function define( model ) {
|
|
|
426
425
|
// eslint-disable-next-line no-multi-assign
|
|
427
426
|
ext.$effectiveSeqNo = model.$blocks[absolute] = (model.$blocks[absolute] || 0) + 1;
|
|
428
427
|
const prefix = `${ absolute }.`;
|
|
429
|
-
dictForEach( ext.artifacts, a =>
|
|
428
|
+
dictForEach( ext.artifacts, a => addBlockArtifact( a, ext, prefix ) );
|
|
430
429
|
}
|
|
431
430
|
|
|
432
431
|
function addVocabulary( vocab, block, prefix ) {
|
|
@@ -484,7 +483,7 @@ function define( model ) {
|
|
|
484
483
|
}
|
|
485
484
|
|
|
486
485
|
// Phase 2 ("init"), top-level & main -----------------------------------------
|
|
487
|
-
// Functions called from top-level: initNamespaceAndUsing(),
|
|
486
|
+
// Functions called from top-level: initNamespaceAndUsing(), initMainArtifact(),
|
|
488
487
|
// initVocabulary(), initExtension()
|
|
489
488
|
|
|
490
489
|
function initNamespaceAndUsing( src ) {
|
|
@@ -525,11 +524,11 @@ function define( model ) {
|
|
|
525
524
|
}
|
|
526
525
|
}
|
|
527
526
|
|
|
528
|
-
function
|
|
527
|
+
function initMainArtifact( art, reInit = false ) {
|
|
529
528
|
if (!reInit) // not for auto-exposed entity
|
|
530
529
|
initArtifactParentLink( art, model.definitions );
|
|
531
530
|
checkRedefinition( art );
|
|
532
|
-
initDollarSelf( art ); // $self
|
|
531
|
+
initDollarSelf( art ); // $self, TODO: also for 'namespace'?
|
|
533
532
|
initMembers( art );
|
|
534
533
|
if (art.params)
|
|
535
534
|
initDollarParameters( art ); // $parameters
|
|
@@ -608,7 +607,7 @@ function define( model ) {
|
|
|
608
607
|
}
|
|
609
608
|
|
|
610
609
|
// TODO: message ids
|
|
611
|
-
// Called by
|
|
610
|
+
// Called by initMainArtifact() and initVocabulary() and for members
|
|
612
611
|
function checkRedefinition( art ) {
|
|
613
612
|
if (art.kind === 'annotate' || art.kind === 'extend') // move this check to call in extend.js?
|
|
614
613
|
return; // extensions are merged into a super-annotate; $duplicates are only kept for LSP
|
|
@@ -983,9 +982,10 @@ function define( model ) {
|
|
|
983
982
|
initExprForQuery( col.value, parent );
|
|
984
983
|
if (col.expand || col.inline)
|
|
985
984
|
initSelectItems( col, null, user ); // TODO: use col, remove 3rd param?
|
|
986
|
-
}
|
|
987
985
|
|
|
988
|
-
|
|
986
|
+
initMembers( col ); // with #13933, TODO: only for enums
|
|
987
|
+
checkCdlTypeCast( col );
|
|
988
|
+
}
|
|
989
989
|
}
|
|
990
990
|
|
|
991
991
|
if (hasItems && !wildcard && parent.excludingDict && !options.$recompile) {
|
|
@@ -1038,13 +1038,7 @@ function define( model ) {
|
|
|
1038
1038
|
return col.name.id;
|
|
1039
1039
|
}
|
|
1040
1040
|
|
|
1041
|
-
function
|
|
1042
|
-
if (col.val)
|
|
1043
|
-
return; // e.g. '*' column
|
|
1044
|
-
|
|
1045
|
-
setMemberParent( col, col.name, parent );
|
|
1046
|
-
initMembers( col );
|
|
1047
|
-
|
|
1041
|
+
function checkCdlTypeCast( col ) { // with #13933:
|
|
1048
1042
|
// We don't allow CDL-style casts to anonymous structures. We reject it already here
|
|
1049
1043
|
// and not in checks.js to ensure that it's rejected in parseCdl.
|
|
1050
1044
|
// TODO: via <guard> in CdlGrammar.g4
|
|
@@ -1052,7 +1046,7 @@ function define( model ) {
|
|
|
1052
1046
|
error( 'type-invalid-cast', [ (col.elements[$location] ?? col.location), col ],
|
|
1053
1047
|
{ '#': 'to-inline-structure' } );
|
|
1054
1048
|
}
|
|
1055
|
-
else if (col.expand && (col.type || col.
|
|
1049
|
+
else if (col.expand && (col.type || col.items)) {
|
|
1056
1050
|
const loc = (col.type?.location || col.elements?.[$location] ||
|
|
1057
1051
|
col.items?.location || col.location);
|
|
1058
1052
|
error( 'type-invalid-cast', [ loc, col ], { '#': 'expand' } );
|
|
@@ -1068,7 +1062,7 @@ function define( model ) {
|
|
|
1068
1062
|
*
|
|
1069
1063
|
* Param `initExtensions` is for parse.cdl - TODO delete
|
|
1070
1064
|
*/
|
|
1071
|
-
function initMembers( parent
|
|
1065
|
+
function initMembers( parent ) {
|
|
1072
1066
|
const block = parent._block;
|
|
1073
1067
|
let obj = initItemsLinks( parent, block );
|
|
1074
1068
|
initExprAnnoBlock( parent, block );
|
|
@@ -1086,109 +1080,102 @@ function define( model ) {
|
|
|
1086
1080
|
error( 'type-unexpected-on-condition', [ obj.on.location, parent ] );
|
|
1087
1081
|
delete obj.on; // continuation semantics: not specified
|
|
1088
1082
|
}
|
|
1089
|
-
if (targetAspect.elements)
|
|
1090
|
-
initAnonymousAspect();
|
|
1083
|
+
if (targetAspect.elements) // eslint-disable-next-line no-multi-assign
|
|
1084
|
+
parent = obj = initAnonymousAspect( parent, obj, targetAspect );
|
|
1091
1085
|
}
|
|
1092
|
-
forEachInOrder( obj, 'elements',
|
|
1093
|
-
forEachGeneric( obj, 'enum',
|
|
1094
|
-
forEachInOrder( obj, 'foreignKeys',
|
|
1095
|
-
forEachGeneric( parent, 'actions',
|
|
1096
|
-
forEachInOrder( parent, 'params',
|
|
1086
|
+
forEachInOrder( obj, 'elements', (...args) => initArtifact( parent, ...args ) );
|
|
1087
|
+
forEachGeneric( obj, 'enum', (...args) => initArtifact( parent, ...args ) );
|
|
1088
|
+
forEachInOrder( obj, 'foreignKeys', (...args) => initArtifact( parent, ...args ) );
|
|
1089
|
+
forEachGeneric( parent, 'actions', (...args) => initArtifact( parent, ...args ) );
|
|
1090
|
+
forEachInOrder( parent, 'params', (...args) => initArtifact( parent, ...args ) );
|
|
1097
1091
|
|
|
1098
1092
|
const { returns } = parent;
|
|
1099
1093
|
if (returns) {
|
|
1100
1094
|
const { kind } = parent;
|
|
1101
1095
|
returns.kind = (kind === 'extend' || kind === 'annotate') ? kind : 'param';
|
|
1102
|
-
|
|
1096
|
+
initArtifact( parent, returns, '' ); // '' is special name for returns parameter
|
|
1103
1097
|
}
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
targetAspect.$tableAliases.up_ = up;
|
|
1137
|
-
}
|
|
1138
|
-
obj = targetAspect;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
function initAnonymousAspect( parent, obj, targetAspect ) {
|
|
1101
|
+
// TODO: main?
|
|
1102
|
+
const inEntity = parent._main?.kind === 'entity';
|
|
1103
|
+
// TODO: also allow indirectly (component in component in entity)?
|
|
1104
|
+
setLink( targetAspect, '_outer', obj );
|
|
1105
|
+
setLink( targetAspect, '_parent', parent._parent );
|
|
1106
|
+
setLink( targetAspect, '_main', null ); // for name resolution
|
|
1107
|
+
|
|
1108
|
+
targetAspect.kind = 'aspect'; // TODO: probably '$aspect' to detect
|
|
1109
|
+
setLink( targetAspect, '_block', parent._block );
|
|
1110
|
+
initDollarSelf( targetAspect );
|
|
1111
|
+
// allow ref of up_ in anonymous aspect inside entity
|
|
1112
|
+
// (TODO: complain if used and the managed composition is included into
|
|
1113
|
+
// another entity - might induce auto-redirection):
|
|
1114
|
+
if (inEntity && !targetAspect.elements.up_) {
|
|
1115
|
+
const up = {
|
|
1116
|
+
name: { id: 'up_' },
|
|
1117
|
+
kind: '$navElement',
|
|
1118
|
+
location: obj.location,
|
|
1119
|
+
};
|
|
1120
|
+
setLink( up, '_parent', targetAspect );
|
|
1121
|
+
setLink( up, '_main', targetAspect ); // used on main artifact
|
|
1122
|
+
// recompilation case: both target and targetAspect → allow up_ in that case, too:
|
|
1123
|
+
const name = obj.target && resolveUncheckedPath( obj.target, 'target', obj );
|
|
1124
|
+
const entity = name && model.definitions[name];
|
|
1125
|
+
if (entity && entity.elements)
|
|
1126
|
+
setLink( up, '_origin', entity.elements.up_ );
|
|
1127
|
+
// processAspectComposition/expand() sets _origin to element of
|
|
1128
|
+
// generated target entity
|
|
1129
|
+
targetAspect.$tableAliases.up_ = up;
|
|
1139
1130
|
}
|
|
1131
|
+
return targetAspect;
|
|
1132
|
+
}
|
|
1140
1133
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
}
|
|
1150
|
-
else { // RETURNS, parser robustness
|
|
1151
|
-
elem.name = { id: name, location: elem.location };
|
|
1152
|
-
}
|
|
1134
|
+
function initArtifact( parent, elem, name, prop ) {
|
|
1135
|
+
if (!elem.kind) // wrong CSN input
|
|
1136
|
+
elem.kind = dictKinds[prop];
|
|
1137
|
+
if (!elem.name && !elem._outer) {
|
|
1138
|
+
const ref = elem.targetElement || elem.kind === 'element' && elem.value;
|
|
1139
|
+
if (ref && ref.path) {
|
|
1140
|
+
elem.name = Object.assign( { $inferred: 'as' },
|
|
1141
|
+
ref.path[ref.path.length - 1] );
|
|
1153
1142
|
}
|
|
1154
|
-
//
|
|
1155
|
-
|
|
1156
|
-
storeExtension( elem, name, prop, parent, block );
|
|
1157
|
-
return;
|
|
1143
|
+
else { // RETURNS, parser robustness
|
|
1144
|
+
elem.name = { id: name, location: elem.location };
|
|
1158
1145
|
}
|
|
1146
|
+
}
|
|
1159
1147
|
|
|
1160
|
-
|
|
1161
|
-
setLink( elem, '_block',
|
|
1148
|
+
if (!elem._block)
|
|
1149
|
+
setLink( elem, '_block', parent._block );
|
|
1162
1150
|
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1151
|
+
// don't dump with `entity T {}; extend T with { extend e {}; e {}; e {} };`:
|
|
1152
|
+
setMemberParent( elem, name, parent );
|
|
1153
|
+
checkRedefinition( elem );
|
|
1154
|
+
initMembers( elem );
|
|
1155
|
+
if (elem.kind === 'action' || elem.kind === 'function')
|
|
1156
|
+
initBoundSelfParam( elem.params, elem._main );
|
|
1169
1157
|
|
|
1170
|
-
|
|
1158
|
+
// for a correct home path, setMemberParent needed to be called
|
|
1171
1159
|
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
}
|
|
1160
|
+
if (!elem.value || elem.kind !== 'element' ||
|
|
1161
|
+
elem.$syntax === 'enum' && parent.kind === 'extend') // ambiguous in parse-cdl
|
|
1162
|
+
return;
|
|
1163
|
+
// -> it's a calculated element
|
|
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' };
|
|
1167
|
+
}
|
|
1168
|
+
elem.$syntax = 'calc';
|
|
1169
|
+
// TODO: it is not just "syntax" - maybe better test for `$calcDepElement`?
|
|
1170
|
+
createAndLinkCalcDepElement( elem );
|
|
1171
|
+
|
|
1172
|
+
// Special case (hack) for calculated elements that use composition+filter:
|
|
1173
|
+
// See "Notes on `$enclosed`" in `ExposingAssocWithFilter.md` for details.
|
|
1174
|
+
// TODO: hm, only for inferred type - then just do not infer it in that case
|
|
1175
|
+
if (elem.target && elem.value.path?.[elem.value.path.length - 1]?.where) {
|
|
1176
|
+
delete elem.type;
|
|
1177
|
+
delete elem.on;
|
|
1178
|
+
delete elem.target;
|
|
1192
1179
|
}
|
|
1193
1180
|
}
|
|
1194
1181
|
|