@sap/cds-compiler 3.9.4 → 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.
Files changed (94) hide show
  1. package/CHANGELOG.md +92 -4
  2. package/README.md +0 -1
  3. package/bin/cdsc.js +11 -23
  4. package/bin/cdsse.js +3 -3
  5. package/doc/API.md +5 -0
  6. package/doc/CHANGELOG_ARCHIVE.md +1 -1
  7. package/doc/CHANGELOG_BETA.md +17 -1
  8. package/doc/CHANGELOG_DEPRECATED.md +28 -0
  9. package/lib/api/.eslintrc.json +1 -1
  10. package/lib/api/main.js +26 -8
  11. package/lib/api/options.js +2 -0
  12. package/lib/base/error.js +2 -0
  13. package/lib/base/message-registry.js +143 -64
  14. package/lib/base/messages.js +213 -107
  15. package/lib/base/model.js +11 -11
  16. package/lib/checks/.eslintrc.json +1 -1
  17. package/lib/checks/annotationsOData.js +2 -2
  18. package/lib/checks/elements.js +1 -1
  19. package/lib/checks/enricher.js +26 -3
  20. package/lib/checks/onConditions.js +67 -12
  21. package/lib/checks/queryNoDbArtifacts.js +106 -105
  22. package/lib/checks/sql-snippets.js +2 -0
  23. package/lib/checks/types.js +12 -6
  24. package/lib/checks/validator.js +2 -2
  25. package/lib/compiler/assert-consistency.js +10 -8
  26. package/lib/compiler/builtins.js +8 -2
  27. package/lib/compiler/checks.js +52 -35
  28. package/lib/compiler/define.js +31 -26
  29. package/lib/compiler/extend.js +120 -65
  30. package/lib/compiler/finalize-parse-cdl.js +12 -43
  31. package/lib/compiler/generate.js +16 -5
  32. package/lib/compiler/index.js +8 -5
  33. package/lib/compiler/kick-start.js +4 -3
  34. package/lib/compiler/populate.js +96 -95
  35. package/lib/compiler/propagator.js +7 -8
  36. package/lib/compiler/resolve.js +377 -103
  37. package/lib/compiler/shared.js +794 -517
  38. package/lib/compiler/tweak-assocs.js +8 -6
  39. package/lib/compiler/utils.js +44 -0
  40. package/lib/edm/annotations/genericTranslation.js +12 -4
  41. package/lib/edm/csn2edm.js +34 -32
  42. package/lib/edm/edm.js +34 -31
  43. package/lib/edm/edmAnnoPreprocessor.js +0 -23
  44. package/lib/edm/edmInboundChecks.js +7 -2
  45. package/lib/edm/edmPreprocessor.js +18 -17
  46. package/lib/edm/edmUtils.js +8 -4
  47. package/lib/gen/Dictionary.json +18 -0
  48. package/lib/gen/language.checksum +1 -1
  49. package/lib/gen/language.interp +4 -2
  50. package/lib/gen/languageParser.js +5006 -4582
  51. package/lib/json/from-csn.js +157 -112
  52. package/lib/json/to-csn.js +60 -89
  53. package/lib/language/antlrParser.js +17 -13
  54. package/lib/language/docCommentParser.js +11 -1
  55. package/lib/language/genericAntlrParser.js +13 -10
  56. package/lib/language/language.g4 +168 -97
  57. package/lib/main.d.ts +128 -36
  58. package/lib/main.js +1 -1
  59. package/lib/model/csnRefs.js +24 -5
  60. package/lib/model/csnUtils.js +9 -8
  61. package/lib/model/revealInternalProperties.js +7 -12
  62. package/lib/modelCompare/compare.js +1 -1
  63. package/lib/modelCompare/utils/filter.js +40 -2
  64. package/lib/optionProcessor.js +0 -3
  65. package/lib/render/toCdl.js +247 -214
  66. package/lib/render/toHdbcds.js +197 -181
  67. package/lib/render/toSql.js +325 -289
  68. package/lib/render/utils/common.js +42 -4
  69. package/lib/render/utils/delta.js +1 -1
  70. package/lib/render/utils/sql.js +3 -3
  71. package/lib/transform/braceExpression.js +2 -2
  72. package/lib/transform/db/.eslintrc.json +1 -1
  73. package/lib/transform/db/applyTransformations.js +3 -3
  74. package/lib/transform/db/associations.js +24 -12
  75. package/lib/transform/db/expansion.js +17 -18
  76. package/lib/transform/db/flattening.js +17 -21
  77. package/lib/transform/db/rewriteCalculatedElements.js +171 -64
  78. package/lib/transform/db/views.js +3 -4
  79. package/lib/transform/draft/db.js +21 -12
  80. package/lib/transform/draft/odata.js +4 -0
  81. package/lib/transform/forOdataNew.js +11 -10
  82. package/lib/transform/forRelationalDB.js +12 -7
  83. package/lib/transform/localized.js +4 -2
  84. package/lib/transform/odata/toFinalBaseType.js +5 -5
  85. package/lib/transform/odata/typesExposure.js +3 -3
  86. package/lib/transform/parseExpr.js +3 -0
  87. package/lib/transform/transformUtilsNew.js +43 -23
  88. package/lib/transform/translateAssocsToJoins.js +7 -6
  89. package/lib/transform/universalCsn/.eslintrc.json +1 -1
  90. package/lib/transform/universalCsn/coreComputed.js +7 -5
  91. package/lib/transform/universalCsn/universalCsnEnricher.js +12 -12
  92. package/package.json +2 -2
  93. package/share/messages/{duplicate-autoexposed.md → def-duplicate-autoexposed.md} +5 -1
  94. package/share/messages/message-explanations.json +1 -1
@@ -16,7 +16,9 @@
16
16
  // const { hasArtifactTypeInformation } = require('../model/csnUtils')
17
17
  const builtins = require('../compiler/builtins');
18
18
  const {
19
- forEachGeneric, forEachDefinition, forEachMember, isBetaEnabled,
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
- if (isStructuredElement(xpr._artifact))
617
- error('ref-unexpected-structured', [ xpr.location, elem ], { '#': 'expr' } );
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', [ xpr.location, elem ], { '#': 'expr' });
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
- // Calc elements must not refer to keys, because that may lead to another key
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 here');
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 }, 'A string value is required for type $(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 }, 'A hexadecimal string value is required for type $(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 }, 'A numerical value is required for type $(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 }, 'A date/time value or a string is required for type $(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 }, 'A boolean value is required for type $(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 }, 'Type $(TYPE) can\'t be assigned a value');
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
- // .. but no such constant
937
- warning(null, loc, { id: `#${ value.sym.id }` }, 'Enum symbol $(ID) not found in enum');
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 }, 'Can\'t use enum symbol $(ID) for non-enum type $(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 here');
968
+ warning(null, loc, { anno }, 'An enum value is required for annotation $(ANNO)');
952
969
  }
953
970
  }
954
971
  }
@@ -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, 'extend', ext );
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 init( sub ) {
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, null ], { name }, // TODO: semantic
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
- // if art is $tableAlias, set to embedding query
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
- warning( 'name-invalid-dollar-alias', [ table.name.location, table ], {
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
- warning( 'name-invalid-dollar-alias', [ mixin.name.location, mixin ],
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
- if (type?.path?.length === 1 && type?.path[0]?.id === '$self') // TODO: no where: ?
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( 'extend-action', [ construct.location, construct ], { '#': parent.kind }, {
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, 'compositionTarget', elem );
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
  }