@sap/cds-compiler 6.4.2 → 6.5.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 (71) hide show
  1. package/CHANGELOG.md +87 -1159
  2. package/README.md +1 -10
  3. package/doc/IncompatibleChanges_v5.md +436 -0
  4. package/doc/IncompatibleChanges_v6.md +659 -0
  5. package/doc/Versioning.md +3 -7
  6. package/lib/api/main.js +1 -0
  7. package/lib/api/options.js +5 -0
  8. package/lib/api/validate.js +3 -0
  9. package/lib/base/message-registry.js +25 -2
  10. package/lib/base/messages.js +1 -1
  11. package/lib/base/model.js +3 -2
  12. package/lib/checks/actionsFunctions.js +6 -3
  13. package/lib/checks/existsExpressionsOnlyForeignKeys.js +16 -10
  14. package/lib/checks/existsInForbiddenPlaces.js +32 -0
  15. package/lib/checks/existsMustEndInAssoc.js +1 -1
  16. package/lib/checks/existsMustNotStartWithDollarSelf.js +31 -0
  17. package/lib/checks/validator.js +6 -2
  18. package/lib/compiler/assert-consistency.js +5 -7
  19. package/lib/compiler/builtins.js +5 -6
  20. package/lib/compiler/checks.js +4 -8
  21. package/lib/compiler/define.js +244 -459
  22. package/lib/compiler/extend.js +297 -11
  23. package/lib/compiler/finalize-parse-cdl.js +2 -10
  24. package/lib/compiler/generate.js +29 -1
  25. package/lib/compiler/populate.js +21 -63
  26. package/lib/compiler/propagator.js +1 -2
  27. package/lib/compiler/resolve.js +2 -12
  28. package/lib/compiler/shared.js +145 -114
  29. package/lib/compiler/tweak-assocs.js +14 -10
  30. package/lib/compiler/utils.js +97 -0
  31. package/lib/compiler/xpr-rewrite.js +113 -140
  32. package/lib/edm/annotations/edmJson.js +9 -6
  33. package/lib/edm/annotations/genericTranslation.js +8 -4
  34. package/lib/edm/csn2edm.js +3 -4
  35. package/lib/edm/edmInboundChecks.js +1 -2
  36. package/lib/edm/edmPreprocessor.js +3 -3
  37. package/lib/gen/CdlGrammar.checksum +1 -1
  38. package/lib/gen/CdlParser.js +4 -3
  39. package/lib/gen/Dictionary.json +16 -1
  40. package/lib/json/from-csn.js +4 -6
  41. package/lib/json/to-csn.js +3 -3
  42. package/lib/model/csnRefs.js +13 -4
  43. package/lib/model/enrichCsn.js +4 -2
  44. package/lib/optionProcessor.js +8 -4
  45. package/lib/parsers/AstBuildingParser.js +1 -1
  46. package/lib/render/utils/sql.js +3 -2
  47. package/lib/transform/db/applyTransformations.js +1 -1
  48. package/lib/transform/db/assertUnique.js +3 -3
  49. package/lib/transform/db/assocsToQueries/normalizeFrom.js +33 -0
  50. package/lib/transform/db/assocsToQueries/transformExists.js +17 -13
  51. package/lib/transform/db/assocsToQueries/utils.js +1 -6
  52. package/lib/transform/db/backlinks.js +4 -4
  53. package/lib/transform/db/cdsPersistence.js +4 -4
  54. package/lib/transform/db/constraints.js +4 -4
  55. package/lib/transform/db/expansion.js +5 -5
  56. package/lib/transform/db/flattening.js +4 -5
  57. package/lib/transform/db/rewriteCalculatedElements.js +3 -3
  58. package/lib/transform/db/temporal.js +11 -11
  59. package/lib/transform/draft/db.js +2 -0
  60. package/lib/transform/draft/odata.js +5 -7
  61. package/lib/transform/effective/flattening.js +1 -2
  62. package/lib/transform/forOdata.js +3 -3
  63. package/lib/transform/forRelationalDB.js +1 -1
  64. package/lib/transform/localized.js +13 -20
  65. package/lib/transform/odata/createForeignKeys.js +1 -2
  66. package/lib/transform/odata/flattening.js +1 -2
  67. package/lib/transform/odata/toFinalBaseType.js +52 -55
  68. package/lib/transform/transformUtils.js +3 -4
  69. package/package.json +3 -3
  70. package/doc/CHANGELOG_BETA.md +0 -464
  71. package/doc/CHANGELOG_DEPRECATED.md +0 -235
@@ -124,7 +124,7 @@ function expandStructureReferences( csn, options, pathDelimiter, messageFunction
124
124
  }
125
125
 
126
126
  /**
127
- * Turn .expand/.inline into normal refs. @cds.persistence.skip .expand with to-many (and all transitive views).
127
+ * Turn .expand/.inline into normal refs. `@cds.persistence.skip` .expand with to-many (and all transitive views).
128
128
  * For such skipped things, error for usage of assoc pointing to them and ignore publishing of assoc pointing to them.
129
129
  */
130
130
  function rewriteExpandInline() {
@@ -269,7 +269,7 @@ function expandStructureReferences( csn, options, pathDelimiter, messageFunction
269
269
 
270
270
  /**
271
271
  * Mark the given artifact and all (transitively) dependent artifacts as `toDummify`.
272
- * This means that they will be replaced with simple dummy views in @dummify
272
+ * This means that they will be replaced with simple dummy views in `@dummify`
273
273
  *
274
274
  * @param {CSN.Artifact} artifact
275
275
  * @param {string} name
@@ -544,7 +544,7 @@ function expandStructureReferences( csn, options, pathDelimiter, messageFunction
544
544
  }
545
545
 
546
546
  /**
547
- * Create a simple dummy view marked with @cds.persistence.skip
547
+ * Create a simple dummy view marked with `@cds.persistence.skip`
548
548
  *
549
549
  * @param {string} source
550
550
  * @returns {CSN.Artifact}
@@ -646,14 +646,14 @@ function expandStructureReferences( csn, options, pathDelimiter, messageFunction
646
646
  * leafs `a_b` and `a_c`, if `art` has elements `b` and `c`.
647
647
  * @param {string[]} colTypeRef
648
648
  * Expanded type for the column. Basically the path to the to-be-expanded `art`.
649
- * @param {(currentRef: any[], currentAlias: string[]) => object} leafCallback
649
+ * @param {(currentRef: CSN.Ref, currentAlias: string[]) => object} leafCallback
650
650
  * Callback when leaf nodes are reached. currentRef is the type reference for the expanded
651
651
  * column. currentAlias is the columns calculated alias.
652
652
  * @returns {object[]}
653
653
  */
654
654
  function _expandStructCol( art, colName, colTypeRef, leafCallback ) {
655
655
  const expanded = [];
656
- /** @type {Array<[CSN.Element, any[], string[]]>} */
656
+ /** @type {Array<[CSN.Element, CSN.Column, string[]]>} */
657
657
  const stack = [ [ art, colTypeRef, [ colName ] ] ];
658
658
  while (stack.length > 0) {
659
659
  const [ current, currentRef, currentAlias ] = stack.pop();
@@ -468,9 +468,9 @@ function handleManagedAssociationsAndCreateForeignKeys( csn, options, messageFun
468
468
  *
469
469
  * If a structure contains an assoc, this will also be resolved and vice versa
470
470
  *
471
- * @param {*} assoc
472
- * @param {*} assocName
473
- * @param {*} path
471
+ * @param {CSN.Association} assoc
472
+ * @param {string} assocName
473
+ * @param {CSN.Path} path
474
474
  */
475
475
  function flattenFKs( assoc, assocName, path ) {
476
476
  if (!assoc.keys)
@@ -697,7 +697,6 @@ function handleManagedAssociationsAndCreateForeignKeys( csn, options, messageFun
697
697
  * @returns {Array[]} First element of every sub-array is the foreign key name, second is the foreign key definition
698
698
  */
699
699
  function createForeignKeys( csnUtils, path, element, prefix, csn, options, pathDelimiter, lvl = 0, originalKey = { }) {
700
- const special$self = !csn?.definitions?.$self && '$self';
701
700
  const isInspectRefResult = !Array.isArray(path);
702
701
 
703
702
  let fks = [];
@@ -707,7 +706,7 @@ function createForeignKeys( csnUtils, path, element, prefix, csn, options, pathD
707
706
  let finalElement = element;
708
707
  let finalTypeName; // TODO: Find a way to not rely on $path?
709
708
  // TODO: effectiveType's return value is 'path' for the next inspectRef
710
- if (element.type && !isBuiltinType(element.type) && element.type !== special$self) {
709
+ if (element.type && !isBuiltinType(element.type)) {
711
710
  const tmpElt = csnUtils.effectiveType(element);
712
711
  // effective type resolves to structs and enums only but not scalars
713
712
  if (Object.keys(tmpElt).length) {
@@ -141,9 +141,9 @@ function rewriteCalculatedElementsInViews( csn, options, csnUtils, pathDelimiter
141
141
  /**
142
142
  * @param {object} parent
143
143
  * @param {string} prop
144
- * @param ref
145
- * @param p
146
- * @param root
144
+ * @param {CSN.Ref} ref
145
+ * @param {CSN.Path} p
146
+ * @param {CSN.Element} root
147
147
  */
148
148
  function transformRef(parent, prop, ref, p, root) {
149
149
  const {
@@ -11,8 +11,8 @@ const validToString = '@cds.valid.to';
11
11
  const validFromString = '@cds.valid.from';
12
12
  /**
13
13
  * Get the forEachDefinition callback function that adds a where condition to views that
14
- * - are annotated with @cds.valid.from and @cds.valid.to,
15
- * - have only one @cds.valid.from and @cds.valid.to,
14
+ * - are annotated with `@cds.valid.from` and `@cds.valid.to`,
15
+ * - have only one `@cds.valid.from` and `@cds.valid.to`,
16
16
  * - and both annotations come from the same entity
17
17
  *
18
18
  * If the view has one of the annotations but the other conditions are not met, an error will be raised.
@@ -30,8 +30,8 @@ function getViewDecorator( csn, messageFunctions, csnUtils, options ) {
30
30
  return addTemporalWhereConditionToView;
31
31
  /**
32
32
  * Add a where condition to views that
33
- * - are annotated with @cds.valid.from and @cds.valid.to,
34
- * - have only one @cds.valid.from and @cds.valid.to,
33
+ * - are annotated with `@cds.valid.from` and `@cds.valid.to`,
34
+ * - have only one `@cds.valid.from` and `@cds.valid.to`,
35
35
  * - and both annotations come from the same entity
36
36
  *
37
37
  * If the view has one of the annotations but the other conditions are not met, an error will be raised.
@@ -97,10 +97,10 @@ function getViewDecorator( csn, messageFunctions, csnUtils, options ) {
97
97
  }
98
98
 
99
99
  /**
100
- * Get all elements tagged with @cds.valid.from/to from the union of all entities of the from-clause.
100
+ * Get all elements tagged with `@cds.valid.from/to` from the union of all entities of the from-clause.
101
101
  *
102
- * @param {any} combined union of all entities of the from-clause
103
- * @returns {Array[]} Array where first field is array of elements with @cds.valid.from, second field is array of elements with @cds.valid.to.
102
+ * @param {CSN.QueryFrom} combined union of all entities of the from-clause
103
+ * @returns {Array[]} Array where first field is array of elements with `@cds.valid.from`, second field is array of elements with `@cds.valid.to`.
104
104
  */
105
105
  function getFromToElements( combined ) {
106
106
  const from = [];
@@ -121,7 +121,7 @@ function getViewDecorator( csn, messageFunctions, csnUtils, options ) {
121
121
  }
122
122
 
123
123
  /**
124
- * Check if the given SELECT has a falsy @cds.valid.from and a falsy @cds.valid.to
124
+ * Check if the given SELECT has a falsy `@cds.valid.from` and a falsy `@cds.valid.to`
125
125
  *
126
126
  * @param {CSN.QuerySelect} SELECT
127
127
  * @param {CSN.Elements} elements
@@ -150,13 +150,13 @@ function getViewDecorator( csn, messageFunctions, csnUtils, options ) {
150
150
  }
151
151
 
152
152
  /**
153
- * Get the forEachDefinition callback function that collects all usages of @cds.valid.from/to/key and checks that
153
+ * Get the forEachDefinition callback function that collects all usages of `@cds.valid.from/to/key` and checks that
154
154
  * - the assignment is on a valid element
155
155
  * - the annotation is only assigned once
156
156
  * - key is only used in conjunction with from and to
157
157
  *
158
- * Furthermore, @cds.valid.from and @cds.valid.key is processed - @cds.valid.from is marked as key or marked as unique if @cds.valid.key is used.
159
- * If @cds.valid.key is used, the real key-elements have their key-property removed (set non-enumerable as $key) and instead the @cds.valid.key-marked elements have it added.
158
+ * Furthermore, `@cds.valid.from` and `@cds.valid.key` is processed - `@cds.valid.from` is marked as key or marked as unique if `@cds.valid.key` is used.
159
+ * If `@cds.valid.key` is used, the real key-elements have their key-property removed (set non-enumerable as $key) and instead the `@cds.valid.key`-marked elements have it added.
160
160
  *
161
161
  * @param {CSN.Model} csn
162
162
  * @param {CSN.Options} options
@@ -188,6 +188,8 @@ function generateDrafts( csn, options, pathDelimiter, messageFunctions ) {
188
188
  // Copy all elements
189
189
  for (const elemName in artifact.elements) {
190
190
  const origElem = artifact.elements[elemName];
191
+ // elements with $calc are rendered as usual
192
+
191
193
  if (origElem.value?.stored) {
192
194
  calcOnWriteElements.push(elemName);
193
195
  }
@@ -27,11 +27,12 @@ const { makeMessageFunction } = require('../../base/messages');
27
27
  * @param {CSN.Options} options
28
28
  * @param {string[]|undefined} services Will be calculated JIT if not provided
29
29
  * @param {object} [messageFunctions]
30
+ * @param {function} [isExternalServiceMember]
30
31
  * @returns {CSN.Model} Returns the transformed input model
31
32
  * @todo should be done by the compiler - Check associations for valid foreign keys
32
33
  * @todo check if needed at all: Remove '$projection' from paths in the element's ON-condition
33
34
  */
34
- function generateDrafts( csn, options, services, messageFunctions ) {
35
+ function generateDrafts( csn, options, services, messageFunctions, isExternalServiceMember ) {
35
36
  // TEMP(2024-02-26): Temporary! Umbrella uses this file directly in cds/lib/compile/for/drafts.js#L1
36
37
  messageFunctions ??= makeMessageFunction(csn, options, 'odata-drafts');
37
38
 
@@ -53,14 +54,11 @@ function generateDrafts( csn, options, services, messageFunctions ) {
53
54
  services = getServiceNames(csn);
54
55
 
55
56
  const visitedArtifacts = Object.create(null);
56
- // @ts-ignore
57
- const externalServices = services.filter(serviceName => csn.definitions[serviceName]['@cds.external']);
58
- // @ts-ignore
59
- const isExternalServiceMember = (_art, name) => externalServices.includes(getServiceName(name));
57
+
60
58
  const filterDict = Object.create(null);
61
59
 
62
60
  // validate the 'DRAFT.DraftAdministrativeData_DraftMessage' type if already present in the model
63
- if (options.draftMessages) {
61
+ if (options.draftMessages && options.odataVersion === 'v4') {
64
62
  const draftAdminDataMessagesType = csn.definitions['DRAFT.DraftAdministrativeData_DraftMessage'];
65
63
  if (draftAdminDataMessagesType && !isValidDraftAdminDataMessagesType(draftAdminDataMessagesType)) {
66
64
  error(null, [ 'definitions', 'DRAFT.DraftAdministrativeData_DraftMessage' ], { name: 'DRAFT.DraftAdministrativeData_DraftMessage' },
@@ -181,7 +179,7 @@ function generateDrafts( csn, options, services, messageFunctions ) {
181
179
  // ... on SiblingEntity.IsActiveEntity != IsActiveEntity ...
182
180
  siblingEntity.SiblingEntity.on = createAssociationPathComparison('SiblingEntity', 'IsActiveEntity', '!=', 'IsActiveEntity');
183
181
 
184
- if (options.draftMessages) {
182
+ if (options.draftMessages && options.odataVersion === 'v4') {
185
183
  const draftMessages = { DraftMessages: { '@Core.Computed': true, virtual: true, items: { type: 'DRAFT.DraftAdministrativeData_DraftMessage' } } };
186
184
  addElement(draftMessages, artifact, artifactName);
187
185
 
@@ -62,13 +62,12 @@ function flattenRefs(csn, options, csnUtils, messageFunctions) {
62
62
 
63
63
  // explicit binding parameter of bound action
64
64
  if (def.actions) {
65
- const special$self = !csn?.definitions?.$self && '$self';
66
65
  Object.entries(def.actions).forEach(([ an, a ]) => {
67
66
  if (a.params) {
68
67
  const params = Object.entries(a.params);
69
68
  const firstParam = params[0][1];
70
69
  const type = firstParam?.items?.type || firstParam?.type;
71
- if (type === special$self) {
70
+ if (type === '$self') {
72
71
  const bindingParamName = params[0][0];
73
72
  const markBindingParam = {
74
73
  ref: (parent, prop, xpr) => {
@@ -117,9 +117,9 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
117
117
  // use the array when there is a need to identify if an artifact is in a service or not
118
118
  const services = getServiceNames(csn);
119
119
  // @ts-ignore
120
- const externalServices = services.filter(serviceName => csn.definitions[serviceName]['@cds.external']);
120
+ const externalServices = services.filter(serviceName => csn.definitions[serviceName]['@cds.external'] && csn.definitions[serviceName]['@cds.external'] !== 2);
121
121
  // @ts-ignore
122
- const isExternalServiceMember = (art, name) => !!(externalServices.includes(getServiceName(name)) || (art && art['@cds.external']));
122
+ const isExternalServiceMember = (art, name) => !!(externalServices.includes(getServiceName(name)) || (art && art['@cds.external'] && art['@cds.external'] !== 2));
123
123
 
124
124
  if (options.csnFlavor === 'universal' && isBetaEnabled(options, 'enableUniversalCsn'))
125
125
  enrichUniversalCsn(csn, options);
@@ -127,7 +127,7 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
127
127
  // - Generate artificial draft fields on a structured CSN if requested, flattening and struct
128
128
  // expansion do their magic including foreign key generation and annotation propagation.
129
129
  // Tenantenizer has to decorate the DraftAdministrativeData, so draft decoration must be done before.
130
- generateDrafts(csn, options, services, messageFunctions);
130
+ generateDrafts(csn, options, services, messageFunctions, isExternalServiceMember);
131
131
 
132
132
  if (options.tenantDiscriminator)
133
133
  addTenantFields(csn, options);
@@ -49,7 +49,7 @@ function forEachDefinition(csn, cb) {
49
49
  * such as flattening, wildcard expansion, etc.
50
50
  *
51
51
  * @param {CSN.Model} csn
52
- * @param {CSN.SqlOptions} options
52
+ * @param {SqlOptions} options
53
53
  * @param {object} messageFunctions Message functions such as `error()`, `info()`, …
54
54
  */
55
55
  function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
@@ -58,23 +58,7 @@ const annoPersistenceSkip = '@cds.persistence.skip';
58
58
  * @param {CSN.Model} csn
59
59
  * Input CSN model. Should not have existing convenience views.
60
60
  *
61
- * @param {object} options
62
- * CSN options. Only few options are used, see below for important ones.
63
- * Options such as `testMode` or `testSortCsn` can also be set.
64
- *
65
- * @param {string} [options.localizedLanguageFallback]
66
- * Valid values (if set): 'none', 'coalesce' (default)
67
- * Whether to use a `coalesce()` function when selecting from `.texts` entities.
68
- * If not set, untranslated strings may not return any value. If 'coalesce'
69
- * is used, it will fall back to the original string.
70
- *
71
- * @param {boolean} [options.localizedWithoutCoalesce]
72
- * Deprecated version of localizedLanguageFallback. Do not use.
73
- *
74
- * @param {boolean} [options.fewerLocalizedViews]
75
- * Default: true
76
- *
77
- * @param {boolean} [options.testMode]
61
+ * @param {CSN.Options} options
78
62
  *
79
63
  * @param {object} config
80
64
  * Configuration for creating convenience views. Non-user visible options.
@@ -252,12 +236,14 @@ function _addLocalizationViews(csn, options, config) {
252
236
  }
253
237
 
254
238
  function createJoinConditionFromLocaleElement() {
239
+ const targetAlias = 'localized_1';
240
+ const sourceAlias = 'L_0';
255
241
  return adaptExpr(entity.elements.localized.on);
256
242
 
257
243
  function adaptExpr(expr) {
258
244
  // We only support a few specific ON-conditions, not generic expressions.
259
245
  // In case of unsupported ON-conditions, we emit an error.
260
- return expr.map((x) => {
246
+ const res = expr.map((x) => {
261
247
  if (!x || typeof x === 'string')
262
248
  return x;
263
249
  if (x.xpr)
@@ -273,14 +259,21 @@ function _addLocalizationViews(csn, options, config) {
273
259
  );
274
260
  return x;
275
261
  });
262
+
263
+ // the `localized` association does not contain the `tenant` element, so we need to add it here
264
+ const addTenantCol = options.tenantDiscriminator && entity.elements.tenant?.key;
265
+ if (addTenantCol)
266
+ return [ { ref: [ targetAlias, 'tenant' ] }, '=', { ref: [ sourceAlias, 'tenant' ] }, 'AND', { xpr: [ ...res ] } ];
267
+
268
+ return res;
276
269
  }
277
270
 
278
271
  function adaptRef(expr) {
279
272
  if (expr.ref[0].charAt(0) === '$') // variable
280
273
  return { ref: [ ...expr.ref ] };
281
274
  if (expr.ref[0] === 'localized') // target side
282
- return { ref: [ 'localized_1', ...expr.ref.slice(1) ] };
283
- return { ref: [ 'L_0', ...expr.ref ] }; // source side
275
+ return { ref: [ targetAlias, ...expr.ref.slice(1) ] };
276
+ return { ref: [ sourceAlias, ...expr.ref ] }; // source side
284
277
  }
285
278
  }
286
279
  }
@@ -76,7 +76,6 @@ function createForeignKeyElements(csn, options, messageFunctions, csnUtils, iter
76
76
  }
77
77
 
78
78
  function createForeignKeysForElement(path, element, prefix, csn, options, pathDelimiter, lvl = 0, originalKey = {} ) {
79
- const special$self = !csn?.definitions?.$self && '$self';
80
79
  const isInspectRefResult = !Array.isArray(path);
81
80
 
82
81
  let fks = [];
@@ -87,7 +86,7 @@ function createForeignKeyElements(csn, options, messageFunctions, csnUtils, iter
87
86
  let finalTypeName;
88
87
 
89
88
  // resolve derived type
90
- if (element.type && !isBuiltinType(element.type) && element.type !== special$self) {
89
+ if (element.type && !isBuiltinType(element.type)) {
91
90
  const tmpElt = csnUtils.effectiveType(element);
92
91
  // effective type resolves to structs and enums only but not scalars
93
92
  if (Object.keys(tmpElt).length) {
@@ -102,13 +102,12 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
102
102
  setProp(def, '$flatAnnotations', flatAnnos);
103
103
  // explicit binding parameter of bound action
104
104
  if (def.actions) {
105
- const special$self = !csn?.definitions?.$self && '$self';
106
105
  Object.entries(def.actions).forEach(([ actionName, action ]) => {
107
106
  if (action.params) {
108
107
  const params = Object.entries(action.params);
109
108
  const firstParam = params[0][1];
110
109
  const type = firstParam?.items?.type || firstParam?.type;
111
- if (type === special$self) {
110
+ if (type === '$self') {
112
111
  const bindingParamName = params[0][0];
113
112
  const markBindingParam = {
114
113
  ref: (parent, prop, xpr) => {
@@ -13,7 +13,6 @@ const { cloneCsnDict, cloneCsnNonDict } = require('../../model/cloneCsn');
13
13
 
14
14
  function expandToFinalBaseType(csn, transformers, csnUtils, services, options, error) {
15
15
  const isV4 = options.odataVersion === 'v4';
16
- const special$self = !csn?.definitions?.$self && '$self';
17
16
  forEachDefinition(csn, (def, defName) => {
18
17
  // Unravel derived type chains to final one for elements, actions, action parameters (propagating annotations)
19
18
  forEachMemberRecursively(def, (member, _memberName) => {
@@ -112,65 +111,63 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, e
112
111
  else {
113
112
  if (isExpandable(finalBaseType) || node.kind === 'type') {
114
113
  // 1. Get the final type of the node (resolve derived type chain)
115
- if (finalBaseType.type !== special$self) {
116
- // The type replacement depends on whether 'node' is a definition or a member[element].
117
- if (node.kind) {
118
- /*
119
- It is a definition and we expand to builtin type and to elements
120
- type T: S; --> Integer;
121
- type S: X; --> Integer;
122
- type X: Integer;
114
+ // The type replacement depends on whether 'node' is a definition or a member[element].
115
+ if (node.kind) {
116
+ /*
117
+ It is a definition and we expand to builtin type and to elements
118
+ type T: S; --> Integer;
119
+ type S: X; --> Integer;
120
+ type X: Integer;
123
121
 
124
- type A: B; -> {...}
125
- type B: C; -> { ... }
126
- type C { .... };
122
+ type A: B; -> {...}
123
+ type B: C; -> { ... }
124
+ type C { .... };
125
+ */
126
+ if (isBuiltinType(finalBaseType.type)) {
127
+ /*
128
+ use transformUtils::toFinalBaseType for the moment,
129
+ as it is collects along the chain of types
130
+ attributes that need to be propagated
131
+ enum, length, scale, etc.
127
132
  */
128
- if (isBuiltinType(finalBaseType.type)) {
129
- /*
130
- use transformUtils::toFinalBaseType for the moment,
131
- as it is collects along the chain of types
132
- attributes that need to be propagated
133
- enum, length, scale, etc.
134
- */
135
- transformers.toFinalBaseType(node);
136
- }
137
- else if (csnUtils.isStructured(finalBaseType)) {
138
- cloneElements(node, finalBaseType);
139
- }
140
- else if (node.type && node.items) {
141
- delete node.type;
142
- }
133
+ transformers.toFinalBaseType(node);
143
134
  }
144
- else {
145
- /*
146
- this is a member and we expand to final base only if builtin
147
- type T: S; --> Integer;
148
- type S: X; --> Integer;
149
- type X: Integer;
135
+ else if (csnUtils.isStructured(finalBaseType)) {
136
+ cloneElements(node, finalBaseType);
137
+ }
138
+ else if (node.type && node.items) {
139
+ delete node.type;
140
+ }
141
+ }
142
+ else {
143
+ /*
144
+ this is a member and we expand to final base only if builtin
145
+ type T: S; --> Integer;
146
+ type S: X; --> Integer;
147
+ type X: Integer;
150
148
 
151
- type {
152
- struct_elt: many A; ---> stays the same
153
- scalar_elt: T; ---> Integer;
154
- type_ref_elt: type of struct_elt;
155
- };
156
- type A: B; -> {...}
157
- type B: C; -> { ... }
158
- type C { .... };
149
+ type {
150
+ struct_elt: many A; ---> stays the same
151
+ scalar_elt: T; ---> Integer;
152
+ type_ref_elt: type of struct_elt;
153
+ };
154
+ type A: B; -> {...}
155
+ type B: C; -> { ... }
156
+ type C { .... };
157
+ */
158
+ // eslint-disable-next-line no-lonely-if
159
+ if (isBuiltinType(finalBaseType.type)) {
160
+ /*
161
+ use transformUtils::toFinalBaseType for the moment,
162
+ as it is collects along the chain of types
163
+ attributes that need to be propagated
164
+ enum, length, scale, etc.
159
165
  */
160
- // eslint-disable-next-line no-lonely-if
161
- if (isBuiltinType(finalBaseType.type)) {
162
- /*
163
- use transformUtils::toFinalBaseType for the moment,
164
- as it is collects along the chain of types
165
- attributes that need to be propagated
166
- enum, length, scale, etc.
167
- */
168
- transformers.toFinalBaseType(node);
169
- // node.type = finalType;
170
- }
171
- else if (node.type.ref) {
172
- cloneElements(node, finalBaseType);
173
- }
166
+ transformers.toFinalBaseType(node);
167
+ // node.type = finalType;
168
+ }
169
+ else if (node.type.ref) {
170
+ cloneElements(node, finalBaseType);
174
171
  }
175
172
  }
176
173
  }
@@ -397,7 +397,7 @@ function getTransformers(model, options, msgFunctions, pathDelimiter = '_') {
397
397
  if (!draftAdminDataEntity) {
398
398
  draftAdminDataEntity = createAndAddDraftAdminDataEntity();
399
399
  model.definitions['DRAFT.DraftAdministrativeData'] = draftAdminDataEntity;
400
- if (options.draftMessages && options.transformation === 'odata' &&
400
+ if (options.draftMessages && options.transformation === 'odata' && options.odataVersion === 'v4' &&
401
401
  !model.definitions['DRAFT.DraftAdministrativeData_DraftMessage'])
402
402
  model.definitions['DRAFT.DraftAdministrativeData_DraftMessage'] = createDraftAdminDataMessagesType();
403
403
 
@@ -493,7 +493,7 @@ function getTransformers(model, options, msgFunctions, pathDelimiter = '_') {
493
493
  draftIsProcessedByMe.DraftIsProcessedByMe['@Common.Label'] = '{i18n>Draft_DraftIsProcessedByMe}';
494
494
  addElement(draftIsProcessedByMe, artifact, artifactName);
495
495
 
496
- if (options.transformation !== 'odata' || options.draftMessages) {
496
+ if (options.transformation !== 'odata' || (options.draftMessages && options.odataVersion === 'v4')) {
497
497
  const messages = { DraftMessages: { } };
498
498
  if (options.transformation === 'odata')
499
499
  messages.DraftMessages = { items: { type: 'DRAFT.DraftAdministrativeData_DraftMessage' } };
@@ -888,12 +888,11 @@ function getTransformers(model, options, msgFunctions, pathDelimiter = '_') {
888
888
  * @param {CSN.Model} csn
889
889
  */
890
890
  function rewriteBuiltinTypeRef(csn) {
891
- const special$self = !csn?.definitions?.$self && '$self';
892
891
  applyTransformations(csn, {
893
892
  type: (parent, _prop, type) => {
894
893
  if (type?.ref && (
895
894
  isBuiltinType(type.ref[0]) ||
896
- type.ref[0] === special$self)
895
+ type.ref[0] === '$self')
897
896
  )
898
897
  parent.type = type.ref[0];
899
898
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds-compiler",
3
- "version": "6.4.2",
3
+ "version": "6.5.0",
4
4
  "description": "CDS (Core Data Services) compiler and backends",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "author": "SAP SE (https://www.sap.com)",
@@ -33,8 +33,8 @@
33
33
  "deployHdbcdsGitDiffs": "CDS_COMPILER_DEPLOY_HANA=1 mocha --reporter-option maxDiffSize=0 --extensions .hdbcds test3/test.deploy.git-diffs.js",
34
34
  "deployHdiGitDiffs": "CDS_COMPILER_DEPLOY_HANA=1 mocha --reporter-option maxDiffSize=0 --extensions .hdi test3/test.deploy.git-diffs.js",
35
35
  "gentest3": "cross-env MAKEREFS=${MAKEREFS:-'true'} mocha --reporter-option maxDiffSize=0 test3/testRefFiles.js",
36
- "coverage": "cross-env nyc mocha --reporter-option maxDiffSize=0 test/ test3/testRefFiles.js && nyc report --reporter=lcov",
37
- "coverage:piper": "cross-env nyc mocha --reporter test/TestMochaReporter.js --reporter-options mochaFile=./coverage/TEST-results.xml --reporter-option maxDiffSize=0 --timeout 10000 test/ test3/ && nyc report --reporter=cobertura && nyc report --reporter=lcov",
36
+ "coverage": "cross-env npx nyc mocha --reporter-option maxDiffSize=0 test/ test3/testRefFiles.js && npx nyc report --reporter=lcov",
37
+ "coverage:piper": "cross-env npx nyc mocha --reporter test/TestMochaReporter.js --reporter-options mochaFile=./coverage/TEST-results.xml --reporter-option maxDiffSize=0 --timeout 10000 test/ test3/ && npx nyc report --reporter=cobertura && npx nyc report --reporter=lcov",
38
38
  "lint": "eslint bin/ benchmark/ lib/ test/ test3/ scripts/ && node scripts/linter/lintConstants.js && node scripts/linter/lintGrammar.js && node scripts/linter/lintTests.js test3/ && node scripts/linter/lintMessages.js && node scripts/linter/lintMessageIdCoverage.js lib/ && markdownlint README.md CHANGELOG.md doc/ internalDoc/ && cd share/messages && markdownlint . && cd ../../ && node scripts/check-changelog.js",
39
39
  "lint:edmx": "node scripts/odata/lint-edmx-v4.js",
40
40
  "tslint": "tsc --pretty -p .",