@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.
Files changed (38) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/bin/cdsc.js +1 -1
  3. package/lib/api/main.js +0 -3
  4. package/lib/base/builtins.js +2 -1
  5. package/lib/base/message-registry.js +13 -14
  6. package/lib/base/model.js +0 -1
  7. package/lib/checks/sql-snippets.js +8 -0
  8. package/lib/checks/validator.js +4 -2
  9. package/lib/compiler/define.js +102 -115
  10. package/lib/compiler/extend.js +67 -37
  11. package/lib/compiler/finalize-parse-cdl.js +1 -1
  12. package/lib/compiler/generate.js +34 -11
  13. package/lib/compiler/index.js +2 -2
  14. package/lib/compiler/kick-start.js +26 -35
  15. package/lib/compiler/populate.js +4 -7
  16. package/lib/compiler/propagator.js +20 -1
  17. package/lib/compiler/resolve.js +26 -1
  18. package/lib/compiler/shared.js +49 -9
  19. package/lib/compiler/utils.js +2 -2
  20. package/lib/edm/annotations/edmJson.js +111 -37
  21. package/lib/edm/annotations/genericTranslation.js +3 -1
  22. package/lib/main.d.ts +0 -3
  23. package/lib/main.js +2 -0
  24. package/lib/model/csnRefs.js +6 -1
  25. package/lib/render/toSql.js +0 -4
  26. package/lib/transform/db/applyTransformations.js +1 -1
  27. package/lib/transform/db/associations.js +24 -15
  28. package/lib/transform/db/flattening.js +1 -1
  29. package/lib/transform/db/views.js +0 -39
  30. package/lib/transform/effective/associations.js +5 -55
  31. package/lib/transform/effective/main.js +4 -2
  32. package/lib/transform/effective/misc.js +1 -1
  33. package/lib/transform/effective/types.js +36 -12
  34. package/lib/transform/forOdata.js +126 -3
  35. package/lib/transform/forRelationalDB.js +13 -4
  36. package/lib/transform/transformUtils.js +51 -1
  37. package/lib/transform/translateAssocsToJoins.js +43 -19
  38. 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
  }
@@ -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(\.|$)/ ); // Requested by Mtx
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
- element: 'Artifact $(ART) has no element $(NAME)',
963
- enum: 'Artifact $(ART) has no enum $(NAME)',
964
- returns: 'Return value of $(ART) has no element $(NAME)',
965
- 'enum-returns': 'Return value of $(ART) has no enum $(NAME)',
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 $(ART) has not been found',
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 $(ART) has not been found',
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 $(ART) has not been found',
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 $(ART) has not been found',
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
@@ -24,7 +24,6 @@ const availableBetaFlags = {
24
24
  mapAssocToJoinCardinality: true, // only SAP HANA HEX engine supports it
25
25
  enableUniversalCsn: true,
26
26
  odataTerms: true,
27
- effectiveCsn: true,
28
27
  tenantVariable: true,
29
28
  calcAssoc: true,
30
29
  temporalRawProjection: true,
@@ -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
  /**
@@ -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
 
@@ -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
- initArtifact,
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, initArtifact );
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
- // addArtifact() adds usings to src.artifacts: shuffleDict must be assigned first
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) { // addArtifact needs usings for context extensions
267
+ if (src.artifacts) { // addBlockArtifact needs usings for context extensions
269
268
  src.artifacts = shuffleDict( src.artifacts );
270
- dictForEach( src.artifacts, a => addArtifact( a, src, prefix ) );
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 => addDefinition( def, src, prefix ) );
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 addDefinition( art, block, prefix ) {
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 addArtifact( art, block, prefix ) {
386
+ function addBlockArtifact( art, block, prefix ) {
388
387
  if (art.kind === 'using')
389
388
  return;
390
- addDefinition( art, block, prefix );
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 => addArtifact( a, art, p ) );
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 => addArtifact( a, ext, prefix ) );
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(), initArtifact(),
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 initArtifact( art, reInit = false ) {
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 initArtifact() and initVocabulary() and for members
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
- initCdlTypeCast( col, parent );
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 initCdlTypeCast( col, parent ) {
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.elements || col.items)) {
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, initExtensions = false ) {
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', init );
1093
- forEachGeneric( obj, 'enum', init );
1094
- forEachInOrder( obj, 'foreignKeys', init );
1095
- forEachGeneric( parent, 'actions', init );
1096
- forEachInOrder( parent, 'params', init );
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
- init( returns, '' ); // '' is special name for returns parameter
1096
+ initArtifact( parent, returns, '' ); // '' is special name for returns parameter
1103
1097
  }
1104
- return;
1105
-
1106
- function initAnonymousAspect() {
1107
- // TODO: main?
1108
- const inEntity = parent._main?.kind === 'entity';
1109
- // TODO: also allow indirectly (component in component in entity)?
1110
- setLink( targetAspect, '_outer', obj );
1111
- setLink( targetAspect, '_parent', parent._parent );
1112
- setLink( targetAspect, '_main', null ); // for name resolution
1113
-
1114
- parent = targetAspect;
1115
- targetAspect.kind = 'aspect'; // TODO: probably '$aspect' to detect
1116
- setLink( targetAspect, '_block', block );
1117
- initDollarSelf( targetAspect );
1118
- // allow ref of up_ in anonymous aspect inside entity
1119
- // (TODO: complain if used and the managed composition is included into
1120
- // another entity - might induce auto-redirection):
1121
- if (inEntity && !targetAspect.elements.up_) {
1122
- const up = {
1123
- name: { id: 'up_' },
1124
- kind: '$navElement',
1125
- location: obj.location,
1126
- };
1127
- setLink( up, '_parent', targetAspect );
1128
- setLink( up, '_main', targetAspect ); // used on main artifact
1129
- // recompilation case: both target and targetAspect allow up_ in that case, too:
1130
- const name = obj.target && resolveUncheckedPath( obj.target, 'target', obj );
1131
- const entity = name && model.definitions[name];
1132
- if (entity && entity.elements)
1133
- setLink( up, '_origin', entity.elements.up_ );
1134
- // processAspectComposition/expand() sets _origin to element of
1135
- // generated target entity
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
- function init( elem, name, prop ) {
1142
- if (!elem.kind) // wrong CSN input
1143
- elem.kind = dictKinds[prop];
1144
- if (!elem.name && !elem._outer) {
1145
- const ref = elem.targetElement || elem.kind === 'element' && elem.value;
1146
- if (ref && ref.path) {
1147
- elem.name = Object.assign( { $inferred: 'as' },
1148
- ref.path[ref.path.length - 1] );
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
- // if (!kindProperties[ elem.kind ]) console.log(elem.kind,elem.name)
1155
- if ((elem.kind === 'extend' || elem.kind === 'annotate') && !initExtensions) {
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
- const bl = elem._block || block;
1161
- setLink( elem, '_block', bl );
1148
+ if (!elem._block)
1149
+ setLink( elem, '_block', parent._block );
1162
1150
 
1163
- // don't dump with `entity T {}; extend T with { extend e {}; e {}; e {} };`:
1164
- setMemberParent( elem, name, parent );
1165
- checkRedefinition( elem );
1166
- initMembers( elem, initExtensions );
1167
- if (elem.kind === 'action' || elem.kind === 'function')
1168
- initBoundSelfParam( elem.params, elem._main );
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
- // for a correct home path, setMemberParent needed to be called
1158
+ // for a correct home path, setMemberParent needed to be called
1171
1159
 
1172
- if (!elem.value || elem.kind !== 'element' ||
1173
- elem.$syntax === 'enum' && parent.kind === 'extend') // ambiguous in parse-cdl
1174
- return;
1175
- // -> it's a calculated element
1176
- if (!elem.type && elem.value.type) { // top-level CAST( expr AS type )
1177
- if (!elem.target)
1178
- elem.type = { ...elem.value.type, $inferred: 'cast' };
1179
- }
1180
- elem.$syntax = 'calc';
1181
- // TODO: it is not just "syntax" - maybe better test for `$calcDepElement`?
1182
- createAndLinkCalcDepElement( elem );
1183
-
1184
- // Special case (hack) for calculated elements that use composition+filter:
1185
- // See "Notes on `$enclosed`" in `ExposingAssocWithFilter.md` for details.
1186
- // TODO: hm, only for inferred type - then just do not infer it in that case
1187
- if (elem.target && elem.value.path?.[elem.value.path.length - 1]?.where) {
1188
- delete elem.type;
1189
- delete elem.on;
1190
- delete elem.target;
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