@sap/cds-compiler 2.15.8 → 3.1.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 (127) hide show
  1. package/CHANGELOG.md +102 -1590
  2. package/bin/.eslintrc.json +2 -1
  3. package/bin/cdsc.js +61 -46
  4. package/doc/API.md +11 -0
  5. package/doc/CHANGELOG_ARCHIVE.md +1592 -0
  6. package/doc/CHANGELOG_BETA.md +26 -5
  7. package/doc/CHANGELOG_DEPRECATED.md +55 -1
  8. package/doc/{DeprecatedOptions.md → DeprecatedOptions_v2.md} +3 -1
  9. package/doc/Versioning.md +20 -1
  10. package/lib/api/.eslintrc.json +2 -2
  11. package/lib/api/main.js +282 -156
  12. package/lib/api/options.js +17 -88
  13. package/lib/api/validate.js +6 -10
  14. package/lib/base/keywords.js +280 -110
  15. package/lib/base/message-registry.js +85 -25
  16. package/lib/base/messages.js +119 -89
  17. package/lib/base/model.js +46 -2
  18. package/lib/base/optionProcessorHelper.js +53 -21
  19. package/lib/checks/actionsFunctions.js +15 -12
  20. package/lib/checks/annotationsOData.js +1 -1
  21. package/lib/checks/cdsPersistence.js +1 -0
  22. package/lib/checks/elements.js +6 -6
  23. package/lib/checks/invalidTarget.js +1 -1
  24. package/lib/checks/nonexpandableStructured.js +1 -1
  25. package/lib/checks/queryNoDbArtifacts.js +2 -1
  26. package/lib/checks/selectItems.js +101 -15
  27. package/lib/checks/types.js +7 -8
  28. package/lib/checks/utils.js +2 -2
  29. package/lib/checks/validator.js +3 -3
  30. package/lib/compiler/assert-consistency.js +78 -21
  31. package/lib/compiler/base.js +6 -4
  32. package/lib/compiler/builtins.js +177 -10
  33. package/lib/compiler/checks.js +1 -1
  34. package/lib/compiler/define.js +28 -23
  35. package/lib/compiler/extend.js +75 -18
  36. package/lib/compiler/finalize-parse-cdl.js +25 -18
  37. package/lib/compiler/index.js +27 -11
  38. package/lib/compiler/moduleLayers.js +7 -0
  39. package/lib/compiler/populate.js +26 -39
  40. package/lib/compiler/propagator.js +12 -7
  41. package/lib/compiler/resolve.js +207 -236
  42. package/lib/compiler/shared.js +100 -93
  43. package/lib/compiler/tweak-assocs.js +13 -20
  44. package/lib/compiler/utils.js +20 -6
  45. package/lib/edm/annotations/preprocessAnnotations.js +12 -13
  46. package/lib/edm/csn2edm.js +35 -37
  47. package/lib/edm/edm.js +22 -13
  48. package/lib/edm/edmAnnoPreprocessor.js +349 -0
  49. package/lib/edm/edmInboundChecks.js +85 -0
  50. package/lib/edm/edmPreprocessor.js +338 -689
  51. package/lib/edm/edmUtils.js +97 -67
  52. package/lib/gen/Dictionary.json +29 -9
  53. package/lib/gen/language.checksum +1 -1
  54. package/lib/gen/language.interp +8 -31
  55. package/lib/gen/language.tokens +105 -114
  56. package/lib/gen/languageLexer.interp +1 -34
  57. package/lib/gen/languageLexer.js +892 -1007
  58. package/lib/gen/languageLexer.tokens +95 -106
  59. package/lib/gen/languageParser.js +20629 -22474
  60. package/lib/inspect/.eslintrc.json +4 -0
  61. package/lib/inspect/index.js +14 -0
  62. package/lib/inspect/inspectModelStatistics.js +81 -0
  63. package/lib/inspect/inspectPropagation.js +189 -0
  64. package/lib/inspect/inspectUtils.js +44 -0
  65. package/lib/json/from-csn.js +74 -69
  66. package/lib/json/to-csn.js +17 -14
  67. package/lib/language/antlrParser.js +2 -2
  68. package/lib/language/docCommentParser.js +61 -38
  69. package/lib/language/errorStrategy.js +52 -40
  70. package/lib/language/genericAntlrParser.js +424 -292
  71. package/lib/language/language.g4 +604 -687
  72. package/lib/language/multiLineStringParser.js +14 -42
  73. package/lib/language/textUtils.js +44 -0
  74. package/lib/main.d.ts +28 -42
  75. package/lib/main.js +104 -81
  76. package/lib/model/api.js +1 -1
  77. package/lib/model/csnRefs.js +57 -30
  78. package/lib/model/csnUtils.js +189 -287
  79. package/lib/model/revealInternalProperties.js +32 -10
  80. package/lib/model/sortViews.js +32 -31
  81. package/lib/modelCompare/compare.js +3 -0
  82. package/lib/optionProcessor.js +91 -57
  83. package/lib/render/.eslintrc.json +1 -1
  84. package/lib/render/DuplicateChecker.js +4 -7
  85. package/lib/render/manageConstraints.js +70 -2
  86. package/lib/render/toCdl.js +387 -367
  87. package/lib/render/toHdbcds.js +20 -16
  88. package/lib/render/toRename.js +44 -22
  89. package/lib/render/toSql.js +81 -59
  90. package/lib/render/utils/common.js +16 -3
  91. package/lib/render/utils/sql.js +20 -19
  92. package/lib/sql-identifier.js +6 -0
  93. package/lib/transform/db/.eslintrc.json +3 -2
  94. package/lib/transform/db/associations.js +43 -35
  95. package/lib/transform/db/cdsPersistence.js +5 -16
  96. package/lib/transform/db/constraints.js +1 -1
  97. package/lib/transform/db/expansion.js +7 -6
  98. package/lib/transform/db/flattening.js +16 -18
  99. package/lib/transform/db/transformExists.js +7 -5
  100. package/lib/transform/db/views.js +3 -3
  101. package/lib/transform/draft/.eslintrc.json +2 -2
  102. package/lib/transform/draft/db.js +6 -6
  103. package/lib/transform/draft/odata.js +6 -7
  104. package/lib/transform/forHanaNew.js +30 -24
  105. package/lib/transform/forOdataNew.js +14 -16
  106. package/lib/transform/localized.js +35 -25
  107. package/lib/transform/odata/toFinalBaseType.js +10 -10
  108. package/lib/transform/odata/typesExposure.js +17 -8
  109. package/lib/transform/odata/utils.js +1 -38
  110. package/lib/transform/transformUtilsNew.js +63 -77
  111. package/lib/transform/translateAssocsToJoins.js +2 -2
  112. package/lib/transform/universalCsn/.eslintrc.json +2 -2
  113. package/lib/transform/universalCsn/coreComputed.js +11 -6
  114. package/lib/transform/universalCsn/universalCsnEnricher.js +33 -5
  115. package/lib/utils/file.js +31 -21
  116. package/lib/utils/moduleResolve.js +0 -1
  117. package/lib/utils/timetrace.js +20 -21
  118. package/package.json +34 -4
  119. package/share/messages/syntax-expected-integer.md +9 -8
  120. package/doc/ApiMigration.md +0 -237
  121. package/doc/CommandLineMigration.md +0 -58
  122. package/doc/ErrorMessages.md +0 -175
  123. package/doc/FioriAnnotations.md +0 -94
  124. package/doc/ODataTransformation.md +0 -273
  125. package/lib/backends.js +0 -529
  126. package/lib/checks/unknownMagic.js +0 -41
  127. package/lib/fix_antlr4-8_warning.js +0 -56
@@ -5,12 +5,14 @@
5
5
 
6
6
  const { searchName } = require('../base/messages');
7
7
  const { dictAddArray } = require('../base/dictionaries');
8
+ const { isDeprecatedEnabled } = require('../base/model');
8
9
 
9
10
  const {
10
11
  setLink,
11
12
  setArtifactLink,
12
13
  dependsOn,
13
14
  pathName,
15
+ annotationHasEllipsis,
14
16
  } = require('./utils');
15
17
 
16
18
  function artifactsEnv( art ) {
@@ -143,6 +145,13 @@ function fns( model ) {
143
145
  rewrite: {
144
146
  next: '_$next', dollar: true, escape: 'param', noDep: true, rewrite: true,
145
147
  }, // TODO: assertion that there is no next/escape used
148
+ 'order-by': {
149
+ next: '_$next',
150
+ dollar: true,
151
+ escape: 'param',
152
+ assoc: 'nav',
153
+ deprecatedSourceRefs: true,
154
+ },
146
155
  'order-by-union': {
147
156
  next: '_$next', dollar: true, escape: 'param', noDep: true, noExt: true,
148
157
  },
@@ -159,6 +168,7 @@ function fns( model ) {
159
168
  resolveUncheckedPath,
160
169
  resolveTypeArgumentsUnchecked,
161
170
  resolvePath,
171
+ checkAnnotate,
162
172
  defineAnnotations,
163
173
  attachAndEmitValidNames,
164
174
  } );
@@ -512,7 +522,7 @@ function fns( model ) {
512
522
  if (args.length > 0) {
513
523
  const loc = [ args[args.length - 1].location, user ];
514
524
  if (typeArtifact.builtin)
515
- warning( 'type-ignoring-argument', loc, { art: typeArtifact } );
525
+ message( 'type-ignoring-argument', loc, { art: typeArtifact } );
516
526
  else
517
527
  error( 'type-unexpected-argument', loc, { '#': 'std', art: typeArtifact });
518
528
  }
@@ -601,6 +611,21 @@ function fns( model ) {
601
611
  else if (r) {
602
612
  return setArtifactLink( head, r );
603
613
  }
614
+ else if (spec.deprecatedSourceRefs && env._combined &&
615
+ isDeprecatedEnabled( options, 'autoCorrectOrderBySourceRefs' )) {
616
+ // User has provided a source element without table alias where a query
617
+ // element is expected. Possible on many DBs (and compiler v1), in CAP
618
+ // only with table alias. Auto-correct it if no duplicate.
619
+ // TODO: we could use that info also in messages when the deprecated flag is not set
620
+ const s = env._combined[head.id];
621
+ if (s && !Array.isArray(s)) {
622
+ path.$prefix = s.name.alias; // pushing it to path directly could be problematic
623
+ warning( null, [ head.location, user ],
624
+ { id: head.id, newcode: `${ s.name.alias }.${ head.id }` },
625
+ 'Replace source element reference $(ID) by $(NEWCODE); auto-corrected' );
626
+ return setArtifactLink( head, s );
627
+ }
628
+ }
604
629
  }
605
630
  if (spec.noMessage || msgArt === true && extDict === model.definitions)
606
631
  return null;
@@ -673,6 +698,9 @@ function fns( model ) {
673
698
  art = item._artifact;
674
699
  if (Array.isArray(art))
675
700
  return false;
701
+ if (art.$requireElementAccess && path.length === 1)
702
+ // Path with only one item, but we expect an element, e.g. `$at.from`.
703
+ signalMissingElementAccess(art, [ item.location, user ]);
676
704
  continue;
677
705
  }
678
706
 
@@ -808,11 +836,30 @@ function fns( model ) {
808
836
  attachAndEmitValidNames(err, ...valid.reverse());
809
837
  }
810
838
 
839
+ /**
840
+ * Emit a 'ref-expected-element' error for magic variable references
841
+ * that require element accesses but don't do.
842
+ * For example: `$at`, but `$at.from` or `$at.to` is required.
843
+ *
844
+ * @param {object} art
845
+ * @param {any} location
846
+ */
847
+ function signalMissingElementAccess(art, location) {
848
+ const err = message( 'ref-expected-element', location,
849
+ { '#': 'magicVar', id: art.name.id } );
850
+ // Mapping for better valid names: from -> $at.from
851
+ const valid = Object.keys(art.elements || {}).reduce((prev, curr) => {
852
+ prev[`${ art.name.id }.${ curr }`] = true;
853
+ return prev;
854
+ }, Object.create(null));
855
+ attachAndEmitValidNames(err, valid);
856
+ }
857
+
811
858
  /**
812
859
  * Attaches a dictionary of valid names to the given compiler message.
813
860
  * In test mode, an info message is emitted with a list of valid names.
814
861
  *
815
- * @param {CSN.Message} msg CDS Compiler message
862
+ * @param {CompileMessage} msg CDS Compiler message
816
863
  * @param {...object} validDicts One ore more artifact dictionaries such as in `_block`.
817
864
  */
818
865
  function attachAndEmitValidNames(msg, ...validDicts) {
@@ -838,101 +885,61 @@ function fns( model ) {
838
885
  }
839
886
  }
840
887
 
841
- // Resolve all annotation assignments for the node `art`. Set `art.@` to all
842
- // flattened assignments. This function might issue error message for
843
- // duplicate assignments.
844
- // TODOs:
845
- // * do something for extensions by CSN or Properties parsers
846
- // * make sure that we do not issue repeated warnings due to flattening if an
847
- // annotation definition is missing
848
- function defineAnnotations( construct, art, block, priority = 'define' ) {
849
- if (!options.parseCdl && construct.kind === 'annotate') {
850
- // Namespaces cannot be annotated in CSN but because they exist as XSN artifacts
851
- // they can still be applied. Namespace annotations are extracted in to-csn.js
852
- // In parseCdl mode USINGs and other unknown references are generated as
853
- // namespaces which would lead to false positives.
854
- // TODO: should this really be different to annotate-unknown?
855
- if (art.kind === 'namespace') {
856
- info( 'anno-namespace', [ construct.name.location, construct ], {},
857
- 'Namespaces can\'t be annotated' );
858
- }
859
- // Builtin annotations would also get lost. Same as for namespaces:
860
- // extracted in to-csn.js
861
- else if (art.builtin === true) {
862
- info( 'anno-builtin', [ construct.name.location, construct ], {},
863
- 'Builtin types should not be annotated. Use custom type instead' );
864
- }
865
- }
866
- // TODO: block should be construct._block
867
- if (construct.$annotations && construct.$annotations.doc )
868
- art.doc = construct.$annotations.doc; // e.g. through `annotate` statement in CDL
869
- else if (construct.doc)
870
- art.doc = construct.doc; // e.g. through `extensions` array in CSN
871
- if (!construct.$annotations) {
872
- if (!block || block.$frontend !== 'json')
873
- return; // namespace, or in CDL source without @annos:
874
- // CSN input: set _block and $priority, shallow-copy from extension
875
- for (const annoProp in construct) {
876
- if (annoProp.charAt(0) === '@') {
877
- let annos = construct[annoProp];
878
- if (!(Array.isArray(annos)))
879
- annos = [ annos ];
880
- for (const a of annos) {
881
- setLink( a, '_block', block );
882
- a.$priority = priority;
883
- if (construct !== art)
884
- addAnnotation( art, annoProp, a );
885
- }
886
- }
887
- }
888
- return;
888
+ // Issue messages for annotations on namespaces and builtins
889
+ // (TODO: really here?, probably split main artifacts vs returns)
890
+ // see also lateExtensions() where similar messages are reported
891
+ function checkAnnotate( construct, art ) {
892
+ // Namespaces cannot be annotated in CSN but because they exist as XSN artifacts
893
+ // they can still be applied. Namespace annotations are extracted in to-csn.js
894
+ // In parseCdl mode USINGs and other unknown references are generated as
895
+ // namespaces which would lead to false positives.
896
+ // TODO: should this really be different to annotate-unknown?
897
+ if (art.kind === 'namespace') {
898
+ info( 'anno-namespace', [ construct.name.location, construct ], {},
899
+ 'Namespaces can\'t be annotated' );
900
+ }
901
+ // Builtin annotations would also get lost. Same as for namespaces:
902
+ // extracted in to-csn.js
903
+ else if (art.builtin === true) {
904
+ info( 'anno-builtin', [ construct.name.location, construct ], {},
905
+ 'Builtin types should not be annotated. Use custom type instead' );
906
+ }
907
+ else if (construct.$syntax === 'returns' && art._block && art.kind !== 'action' &&
908
+ art.kind !== 'function' ) {
909
+ // `annotate ABC with returns {}` is handled just like `elements`. Warn if it is used
910
+ // for non-actions. We can't only check for !art.returns, because `action A();` is valid.
911
+ // `art._block` ensures that `art` is a defined def.
912
+ warning('anno-unexpected-returns', [ construct.name.location, construct ],
913
+ { keyword: 'returns', kind: art.kind }, 'Unexpected $(KEYWORD) for $(KIND)');
889
914
  }
890
- for (const anno of construct.$annotations) {
891
- const ref = anno.name;
892
- const name = resolveUncheckedPath( ref, 'annotation', { _block: block } );
893
- const annoProp = (anno.name.variant)
894
- ? `@${ name }#${ anno.name.variant.id }`
895
- : `@${ name }`;
896
- flatten( ref.path, annoProp, anno.value || {}, anno.name.variant, anno.name.location );
897
- }
898
- return;
899
-
900
- function flatten( path, annoProp, value, iHaveVariant, location ) {
901
- // Be robust if struct value has duplicate element names
902
- if (Array.isArray(value)) // TODO: do that differently in CDL parser
903
- return; // discard duplicates in flattened form
904
-
905
- if (value.literal === 'struct') {
906
- for (const item of value._struct || []) {
907
- let prop = pathName(item.name.path);
908
- if (item.name.variant) {
909
- if (iHaveVariant) {
910
- error( 'anno-duplicate-variant', [ item.name.variant.location, construct ],
911
- {}, // TODO: params
912
- 'Annotation variant has been already provided' );
913
- }
914
- prop = `${ prop }#${ item.name.variant.id }`; // TODO: check for double variants
915
+ }
916
+
917
+ // Set _block links for annotations (necessary for layering).
918
+ // Also copy annotations from `construct` to `art` (TODO: separate that functionality).
919
+ function defineAnnotations( construct, art, block, priority = false ) {
920
+ if (construct.doc)
921
+ art.doc = construct.doc; // e.g. through `extensions` array in CSN
922
+
923
+ // set _block (for layering) and $priority, shallow-copy from extension
924
+ // TODO: think of removing $priority, then
925
+ // no _block: define, _block: annotate/extend/edmx
926
+ // would fit with extending defs with props like length
927
+ for (const annoProp in construct) {
928
+ if (annoProp.charAt(0) === '@') {
929
+ let annos = construct[annoProp];
930
+ if (!(Array.isArray(annos)))
931
+ annos = [ annos ];
932
+ for (const a of annos) {
933
+ setLink( a, '_block', block );
934
+ a.$priority = priority; // is now: undefined (auto-set) | false | 'annotate' | 'extend'
935
+ if (construct !== art)
936
+ addAnnotation( art, annoProp, a );
937
+ if (!priority && annotationHasEllipsis( a )) {
938
+ error( 'anno-unexpected-ellipsis',
939
+ [ a.name.location, art ], { code: '...' } );
915
940
  }
916
- flatten( [ ...path, ...item.name.path ], `${ annoProp }.${ prop }`, item, iHaveVariant || item.name.variant);
917
941
  }
918
- for (const prop in value.struct) {
919
- const item = value.struct[prop];
920
- flatten( [ ...path, item.name ], `${ annoProp }.${ prop }`, item, iHaveVariant );
921
- }
922
- return;
923
942
  }
924
- const anno = Object.assign( {}, value ); // shallow copy
925
- anno.name = {
926
- path,
927
- location: location ||
928
- value.name && value.name.location ||
929
- value.path && value.path.location,
930
- };
931
- setLink( anno, '_block', block );
932
- // TODO: _parent, _main is set later (if we have ElementRef), or do we
933
- // set _artifact?
934
- anno.$priority = priority;
935
- addAnnotation( art, annoProp, anno );
936
943
  }
937
944
  }
938
945
  }
@@ -3,7 +3,6 @@
3
3
  'use strict';
4
4
 
5
5
  const {
6
- isDeprecatedEnabled,
7
6
  forEachDefinition,
8
7
  forEachGeneric,
9
8
  forEachInOrder,
@@ -26,7 +25,6 @@ const $location = Symbol.for('cds.$location');
26
25
 
27
26
  // Export function of this file.
28
27
  function tweakAssocs( model ) {
29
- const { options } = model;
30
28
  // Get shared functionality and the message function:
31
29
  const {
32
30
  info, warning, error,
@@ -38,11 +36,6 @@ function tweakAssocs( model ) {
38
36
  } = model.$functions;
39
37
  const { environment } = model.$volatileFunctions;
40
38
 
41
- // behavior depending on option `deprecated`:
42
- const enableExpandElements = !isDeprecatedEnabled( options, 'noElementsExpansion' );
43
- // TODO: we should get rid of noElementsExpansion soon; both
44
- // beta.nestedProjections and beta.universalCsn do not work with it.
45
-
46
39
  // Phase 5: rewrite associations
47
40
  forEachDefinition( model, rewriteSimple );
48
41
  // TODO: sequence not good enough with derived type of structure with
@@ -95,15 +88,14 @@ function tweakAssocs( model ) {
95
88
  if (!target || target._service) // assoc to other service is OK
96
89
  return;
97
90
  if (!elem.$inferred) { // && !elem.target.$inferred
98
- // TODO: spec meeting 2021-01-22: no warning
99
- warning( 'assoc-target-not-in-service', [ elem.target.location, elem ],
100
- { target, '#': (elem._main.query ? 'select' : 'define') }, {
101
- std: 'Target $(TARGET) of association is outside any service', // not used
102
- // eslint-disable-next-line max-len
103
- define: 'Target $(TARGET) of explicitly defined association is outside any service',
104
- // eslint-disable-next-line max-len
105
- select: 'Target $(TARGET) of explicitly selected association is outside any service',
106
- } );
91
+ info( 'assoc-target-not-in-service', [ elem.target.location, elem ],
92
+ { target, '#': (elem._main.query ? 'select' : 'define') }, {
93
+ std: 'Target $(TARGET) of association is outside any service', // not used
94
+ // eslint-disable-next-line max-len
95
+ define: 'Target $(TARGET) of explicitly defined association is outside any service',
96
+ // eslint-disable-next-line max-len
97
+ select: 'Target $(TARGET) of explicitly selected association is outside any service',
98
+ } );
107
99
  }
108
100
  else {
109
101
  info( 'assoc-outside-service', [ elem.target.location, elem ],
@@ -114,7 +106,7 @@ function tweakAssocs( model ) {
114
106
 
115
107
  function rewriteAssociationCheck( element ) {
116
108
  const elem = element.items || element; // TODO v2: nested items
117
- if (elem.elements && enableExpandElements)
109
+ if (elem.elements)
118
110
  forEachGeneric( elem, 'elements', rewriteAssociationCheck );
119
111
  if (!elem.target)
120
112
  return;
@@ -208,7 +200,7 @@ function tweakAssocs( model ) {
208
200
 
209
201
  function rewriteAssociation( element ) {
210
202
  let elem = element.items || element; // TODO v2: nested items
211
- if (elem.elements && enableExpandElements)
203
+ if (elem.elements)
212
204
  forEachGeneric( elem, 'elements', rewriteAssociation );
213
205
  if (!originTarget( elem ))
214
206
  return;
@@ -287,7 +279,7 @@ function tweakAssocs( model ) {
287
279
  // same (TODO later: set status whether rewrite changes anything),
288
280
  // especially problematic are refs starting with $self:
289
281
  setExpandStatus( elem, 'target' );
290
- if (enableExpandElements && elem._parent && elem._parent.kind === 'element') {
282
+ if (elem._parent && elem._parent.kind === 'element') {
291
283
  // managed association as sub element not supported yet
292
284
  error( null, [ elem.location, elem ], {},
293
285
  // eslint-disable-next-line max-len
@@ -370,7 +362,8 @@ function tweakAssocs( model ) {
370
362
  const item = expr.path[root.kind === '$self' ? 1 : 0];
371
363
  if (!item)
372
364
  return; // just $self
373
- const elem = assoc._main.elements[item.id]; // corresponding elem in including structure
365
+ // corresponding elem in including structure
366
+ const elem = (assoc._main.items || assoc._main).elements[item.id];
374
367
  if (!(Array.isArray(elem) || // no msg for redefs
375
368
  elem === item._artifact || // redirection for explicit def
376
369
  elem._origin === item._artifact)) {
@@ -31,6 +31,10 @@ function annotationVal( anno ) {
31
31
  function annotationIsFalse( anno ) { // falsy, but not null (unset)
32
32
  return anno && (anno.val === false || anno.val === 0 || anno.val === '');
33
33
  }
34
+ function annotationHasEllipsis( anno ) {
35
+ const { val } = anno || {};
36
+ return Array.isArray( val ) && val.some( v => v.literal === 'token' && v.val === '...' );
37
+ }
34
38
 
35
39
  /**
36
40
  * Set compiler-calculated annotation value.
@@ -91,6 +95,14 @@ function linkToOrigin( origin, name, parent, prop, location, silentDep ) {
91
95
  return elem;
92
96
  }
93
97
 
98
+ /**
99
+ * Set the member `elem` to have a _parent link to `parent` and a corresponding
100
+ * _main link. Also set the member's name accordingly, where argument `name`
101
+ * is most often the property `elem.name.id`.
102
+ *
103
+ * If argument `prop` is provided, add `elem` to the dictionary of that name,
104
+ * e.g. `elements`.
105
+ */
94
106
  function setMemberParent( elem, name, parent, prop ) {
95
107
  if (prop) { // extension or structure include
96
108
  // TODO: consider nested ARRAY OF and RETURNS, COMPOSITION OF type
@@ -103,9 +115,10 @@ function setMemberParent( elem, name, parent, prop ) {
103
115
  parent = parent._outer;
104
116
  setLink( elem, '_parent', parent );
105
117
  setLink( elem, '_main', parent._main || parent );
106
- const parentName = parent.name || parent._outer.name;
107
- elem.name.absolute = parentName.absolute;
108
- if (name == null)
118
+ const parentName = parent.name || parent._outer?.name;
119
+ if (parentName) // may not be available in e.g. cast() - TODO recheck (#9503)
120
+ elem.name.absolute = parentName.absolute;
121
+ if (!parentName || name == null)
109
122
  return;
110
123
  const normalized = kindProperties[elem.kind].normalized || elem.kind;
111
124
  [ 'element', 'alias', 'select', 'param', 'action' ].forEach( ( kind ) => {
@@ -184,8 +197,8 @@ function withAssociation( ref, test = testFunctionPlaceholder, alsoTestLast = fa
184
197
  *
185
198
  * @param {XSN.Path} path
186
199
  */
187
- function pathName(path) {
188
- return (path.broken) ? '' : path.map( id => id.id ).join('.');
200
+ function pathName( path ) {
201
+ return (path && !path.broken) ? path.map( id => id.id ).join('.') : '';
189
202
  }
190
203
 
191
204
  /**
@@ -353,7 +366,7 @@ function traverseQueryExtra( main, callback ) {
353
366
  // that value is only on elements, types, and params -> no other members
354
367
  // when set, only on elem/art with expanded elements
355
368
  // - 'target': all expanded (sub) elements might only have new target/on, but
356
- // no indivual annotations on any (sub) member
369
+ // no individual annotations on any (sub) member
357
370
  // when set, traverse all parents where the value has been 'origin' before
358
371
  // - 'annotate': at least one inferred (sub) member has an individual annotation,
359
372
  // not counting propagated ones; set up to the definition (main artifact)
@@ -381,6 +394,7 @@ module.exports = {
381
394
  pushLink,
382
395
  annotationVal,
383
396
  annotationIsFalse,
397
+ annotationHasEllipsis,
384
398
  annotateWith,
385
399
  setLink,
386
400
  setArtifactLink,
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- const edmUtils = require('../edmUtils.js');
4
3
  const { makeMessageFunction } = require('../../base/messages.js');
4
+ const { forEachDefinition } = require('../../model/csnUtils.js');
5
5
 
6
6
 
7
7
  /**************************************************************************************************
@@ -37,15 +37,14 @@ function preprocessAnnotations(csn, serviceName, options) {
37
37
  let targetName = (typeof assoc.target === 'object') ? assoc.target.name : assoc.target;
38
38
  let target = (typeof assoc.target === 'object') ? assoc.target : csn.definitions[assoc.target];
39
39
 
40
- let keyNames = Object.keys(target.elements).filter(x => target.elements[x].key);
40
+ let keyNames = Object.keys(target.elements).filter(x => target.elements[x].key && !target.elements[x].target);
41
41
  if (keyNames.length === 0) {
42
42
  keyNames.push('MISSING');
43
43
  warning(null, null, `in annotation preprocessing: target ${targetName} has no key`);
44
44
  }
45
45
  else if (keyNames.length > 1)
46
46
  warning(null, null, `in annotation preprocessing: target ${targetName} has multiple key elements`);
47
-
48
- // TODO: what happens if key of target is itself a managed association?
47
+
49
48
  return keyNames[0];
50
49
  }
51
50
 
@@ -58,15 +57,15 @@ function preprocessAnnotations(csn, serviceName, options) {
58
57
  function resolveShortcuts() {
59
58
  let art = null;
60
59
 
61
- edmUtils.forAll(csn.definitions, (artifact, artifactName) => {
62
- if(artifactName == serviceName || artifactName.startsWith(serviceName + '.')) {
60
+ forEachDefinition(csn, (artifact, artifactName) => {
61
+ if(artifactName === serviceName || artifactName.startsWith(serviceName + '.')) {
63
62
  art = artifactName;
64
63
  handleAnnotations(artifactName, artifact);
65
- edmUtils.forAll(artifact.elements, (element, elementName) => {
64
+ artifact.elements && Object.entries(artifact.elements).forEach(([elementName, element]) => {
66
65
  handleAnnotations(elementName, element);
67
66
  });
68
- edmUtils.forAll(artifact.actions, (action) => {
69
- edmUtils.forAll(action.params, (param, paramName) => {
67
+ artifact.actions && Object.values(artifact.actions).forEach(action => {
68
+ action.params && Object.entries(action.params).forEach(([paramName, param]) => {
70
69
  handleAnnotations(paramName, param);
71
70
  });
72
71
  });
@@ -155,7 +154,7 @@ function preprocessAnnotations(csn, serviceName, options) {
155
154
  return false;
156
155
  }
157
156
  let assoc = csn.definitions[art].elements[assocName];
158
- if (!assoc || !(assoc.type === 'cds.Association' || assoc.type === 'cds.Composition')) {
157
+ if (!assoc || !assoc.target) {
159
158
  warning(null, null, `in annotation preprocessing/${aNameWithoutQualifier}: there is no association "${assocName}", ${ctx}`);
160
159
  return false;
161
160
  }
@@ -165,7 +164,7 @@ function preprocessAnnotations(csn, serviceName, options) {
165
164
  }
166
165
  else if (aNameWithoutQualifier === '@Common.ValueList.entity') {
167
166
  // if both annotations are present, ignore 'entity' and raise a message
168
- if (annoNames.map(x=>x.split('#')[0]).find(x=>(x=='@Common.ValueList.viaAssociation'))) {
167
+ if (annoNames.map(x=>x.split('#')[0]).find(x=>(x==='@Common.ValueList.viaAssociation'))) {
169
168
  warning(null, null, `in annotation preprocessing/@Common.ValueList: 'entity' is ignored, as 'viaAssociation' is present, ${ctx}`);
170
169
  return false;
171
170
  }
@@ -196,7 +195,7 @@ function preprocessAnnotations(csn, serviceName, options) {
196
195
  // name of the element carrying the value help annotation
197
196
  // if this is a managed assoc, use fk field instead (if there is a single one)
198
197
  let localDataProp = carrierName.split('/').pop();
199
- if (edmUtils.isManagedAssociation(carrier)) {
198
+ if (carrier.target && carrier.on === undefined) {
200
199
  localDataProp = localDataProp + fkSeparator + getKeyOfTargetOfManagedAssoc(carrier);
201
200
  }
202
201
 
@@ -212,7 +211,7 @@ function preprocessAnnotations(csn, serviceName, options) {
212
211
  // valueListProp: the (single) key field of the value list entity
213
212
  // if no key or multiple keys -> warning
214
213
  let valueListProp = null;
215
- let keys = Object.keys(vlEntity.elements).filter( x => vlEntity.elements[x].key );
214
+ let keys = Object.keys(vlEntity.elements).filter( x => vlEntity.elements[x].key && !vlEntity.elements[x].target );
216
215
  if (keys.length === 0) {
217
216
  warning(null, null, `in annotation preprocessing/value help shortcut: entity "${enameFull}" has no key, ${ctx}`);
218
217
  return false;