@sap/cds-compiler 6.2.2 → 6.3.4

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 (63) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/bin/cdsc.js +11 -4
  3. package/lib/api/options.js +1 -1
  4. package/lib/base/message-registry.js +36 -7
  5. package/lib/base/messages.js +11 -4
  6. package/lib/base/model.js +0 -1
  7. package/lib/checks/assocOutsideService.js +17 -30
  8. package/lib/checks/checkForTypes.js +0 -18
  9. package/lib/checks/checkPathsInStoredCalcElement.js +2 -1
  10. package/lib/checks/enricher.js +15 -3
  11. package/lib/checks/onConditions.js +2 -2
  12. package/lib/checks/queryNoDbArtifacts.js +16 -15
  13. package/lib/checks/types.js +1 -1
  14. package/lib/checks/utils.js +30 -6
  15. package/lib/checks/validator.js +36 -37
  16. package/lib/compiler/assert-consistency.js +1 -1
  17. package/lib/compiler/checks.js +47 -18
  18. package/lib/compiler/extend.js +1 -1
  19. package/lib/compiler/index.js +88 -6
  20. package/lib/compiler/populate.js +1 -1
  21. package/lib/compiler/resolve.js +7 -7
  22. package/lib/compiler/tweak-assocs.js +48 -25
  23. package/lib/edm/annotations/edmJson.js +19 -19
  24. package/lib/gen/BaseParser.js +1 -1
  25. package/lib/gen/CdlGrammar.checksum +1 -1
  26. package/lib/gen/CdlParser.js +384 -383
  27. package/lib/gen/Dictionary.json +0 -2
  28. package/lib/json/to-csn.js +3 -2
  29. package/lib/model/csnRefs.js +9 -4
  30. package/lib/model/csnUtils.js +67 -2
  31. package/lib/optionProcessor.js +2 -3
  32. package/lib/parsers/AstBuildingParser.js +12 -11
  33. package/lib/render/toCdl.js +10 -4
  34. package/lib/render/utils/common.js +4 -2
  35. package/lib/transform/db/assertUnique.js +2 -1
  36. package/lib/transform/db/associations.js +37 -1
  37. package/lib/transform/db/assocsToQueries/transformExists.js +21 -32
  38. package/lib/transform/db/assocsToQueries/utils.js +1 -1
  39. package/lib/transform/db/cdsPersistence.js +1 -1
  40. package/lib/transform/db/expansion.js +37 -36
  41. package/lib/transform/draft/db.js +20 -20
  42. package/lib/transform/draft/odata.js +38 -40
  43. package/lib/transform/effective/associations.js +1 -1
  44. package/lib/transform/effective/flattening.js +40 -47
  45. package/lib/transform/effective/main.js +6 -4
  46. package/lib/transform/forOdata.js +135 -115
  47. package/lib/transform/forRelationalDB.js +151 -142
  48. package/lib/transform/localized.js +116 -109
  49. package/lib/transform/odata/adaptAnnotationRefs.js +21 -16
  50. package/lib/transform/odata/createForeignKeys.js +73 -70
  51. package/lib/transform/odata/flattening.js +216 -200
  52. package/lib/transform/odata/foreignKeyRefsInXprAnnos.js +47 -45
  53. package/lib/transform/odata/toFinalBaseType.js +40 -39
  54. package/lib/transform/odata/typesExposure.js +151 -133
  55. package/lib/transform/odata/utils.js +7 -6
  56. package/lib/transform/parseExpr.js +165 -162
  57. package/lib/transform/transformUtils.js +184 -551
  58. package/lib/transform/translateAssocsToJoins.js +510 -571
  59. package/lib/transform/tupleExpansion.js +495 -0
  60. package/lib/transform/universalCsn/universalCsnEnricher.js +1 -0
  61. package/package.json +1 -1
  62. package/lib/base/cleanSymbols.js +0 -17
  63. package/lib/checks/nonexpandableStructured.js +0 -39
@@ -1,13 +1,17 @@
1
1
  'use strict';
2
2
 
3
- const { forEachDefinition,
3
+ const {
4
+ forEachDefinition,
4
5
  copyAnnotations, forEachMemberRecursively,
5
- transformExpression, transformAnnotationExpression } = require('../../model/csnUtils');
6
+ transformExpression, transformAnnotationExpression,
7
+ } = require('../../model/csnUtils');
6
8
  const { isBuiltinType, isMagicVariable } = require('../../base/builtins');
7
9
  const transformUtils = require('../transformUtils');
8
10
  const { setProp, forEachGeneric } = require('../../base/model');
9
- const { applyTransformationsOnDictionary,
10
- applyTransformationsOnNonDictionary } = require('../db/applyTransformations.js');
11
+ const {
12
+ applyTransformationsOnDictionary,
13
+ applyTransformationsOnNonDictionary,
14
+ } = require('../db/applyTransformations.js');
11
15
  const { handleManagedAssociationsAndCreateForeignKeys } = require('../db/flattening');
12
16
  const { cloneCsnNonDict } = require('../../model/cloneCsn');
13
17
  const { forEach } = require('../../utils/objectUtils');
@@ -17,10 +21,10 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
17
21
  const allMgdAssocDefs = [];
18
22
  forEachDefinition(csn, (def, defName) => {
19
23
  if (def.kind === 'entity' && !isExternalServiceMember(def, defName)) {
20
- ['elements', 'params'].forEach(dictName => {
24
+ [ 'elements', 'params' ].forEach((dictName) => {
21
25
  const dict = def[dictName];
22
26
  if (dict) {
23
- const csnPath = ['definitions', defName, dictName];
27
+ const csnPath = [ 'definitions', defName, dictName ];
24
28
  const orderedElementList = [];
25
29
 
26
30
  forEach(dict, (childName, child) => {
@@ -34,23 +38,26 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
34
38
  typeIdx = rootPrefix.length + 1;
35
39
  }
36
40
  if (resolvedElt.elements) {
37
- const flattenedSubTree = recurseIntoElement(dictName, child, resolvedElt,
38
- !!child.notNull, location, [ ...rootPrefix, childName ], typeIdx);
41
+ const flattenedSubTree = recurseIntoElement(
42
+ dictName, child, resolvedElt,
43
+ !!child.notNull, location, [ ...rootPrefix, childName ], typeIdx
44
+ );
39
45
 
40
- flattenedSubTree.forEach(([flatEltName, flatElt]) => {
41
- if (dict[flatEltName] || orderedElementList.some(elt => elt[0] === flatEltName))
46
+ flattenedSubTree.forEach(([ flatEltName, flatElt ]) => {
47
+ if (dict[flatEltName] || orderedElementList.some(elt => elt[0] === flatEltName)) {
42
48
  error('name-duplicate-element', location,
43
49
  { '#': 'flatten-element-exist', name: flatEltName });
50
+ }
44
51
  propagateToFlatElem(child, flatElt);
45
52
  rewriteOnCondition(flatElt, flattenedSubTree);
46
53
  adaptManagedAssociationSpecialFields(flatElt, flatEltName, flattenedSubTree);
47
- orderedElementList.push([flatEltName, flatElt]);
54
+ orderedElementList.push([ flatEltName, flatElt ]);
48
55
  });
49
56
  }
50
57
  else {
51
58
  // TODO: run adaptManagedAssociationSpecialFields here as well
52
59
  const flatElt = cloneElt(dictName, child, location, [ defName, childName ]);
53
- orderedElementList.push([childName, flatElt]);
60
+ orderedElementList.push([ childName, flatElt ]);
54
61
  }
55
62
  });
56
63
 
@@ -60,18 +67,17 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
60
67
  forEachMemberRecursively(flatElt.items, (elt, eltName, _prop, path) => {
61
68
  const exprAnnos = Object.keys(elt).filter(pn => pn[0] === '@');
62
69
  flattenAndPrefixExprPaths(elt, exprAnnos, elt.$path, path, 0, true);
63
- if (csnUtils.isManagedAssociation(elt)) {
70
+ if (csnUtils.isManagedAssociation(elt))
64
71
  allMgdAssocDefs.push(elt);
65
- }
66
72
  }, [ flatEltName ], true, { pathWithoutProp: true } );
67
- } else if (flatElt.targetAspect) {
73
+ }
74
+ else if (flatElt.targetAspect) {
68
75
  forEachMemberRecursively(flatElt.targetAspect, (elt, _eltName, _prop, _path) => {
69
76
  // TODO: check whether that needs to be done for targetAspects as well
70
77
  // const exprAnnos = Object.keys(elt).filter(pn => pn[0] === '@');
71
78
  // flattenAndPrefixExprPaths(elt, exprAnnos, elt.$path, path, 0, true);
72
- if (csnUtils.isManagedAssociation(elt)) {
79
+ if (csnUtils.isManagedAssociation(elt))
73
80
  allMgdAssocDefs.push(elt);
74
- }
75
81
  }, [ flatEltName ], true, { pathWithoutProp: true } );
76
82
  }
77
83
  setProp(flatElt, '$pathInStructuredModel', flatElt.$path);
@@ -79,13 +85,14 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
79
85
  elements[flatEltName] = flatElt;
80
86
  return elements;
81
87
  }, Object.create(null));
82
- setProp(def, `$flat${dictName}`, flatDict);
88
+ setProp(def, `$flat${ dictName }`, flatDict);
83
89
  orderedElementList.reduce(
84
90
  (mgdAssocs, [ _flatEltName, flatElt ]) => {
85
- if(csnUtils.isManagedAssociation(flatElt))
91
+ if (csnUtils.isManagedAssociation(flatElt))
86
92
  mgdAssocs.push(flatElt);
87
93
  return mgdAssocs;
88
- }, allMgdAssocDefs);
94
+ }, allMgdAssocDefs
95
+ );
89
96
  }
90
97
  });
91
98
  // entity annotations
@@ -96,18 +103,17 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
96
103
  // explicit binding parameter of bound action
97
104
  if (def.actions) {
98
105
  const special$self = !csn?.definitions?.$self && '$self';
99
- Object.entries(def.actions).forEach(([actionName, action]) => {
106
+ Object.entries(def.actions).forEach(([ actionName, action ]) => {
100
107
  if (action.params) {
101
108
  const params = Object.entries(action.params);
102
109
  const firstParam = params[0][1];
103
110
  const type = firstParam?.items?.type || firstParam?.type;
104
111
  if (type === special$self) {
105
-
106
112
  const bindingParamName = params[0][0];
107
113
  const markBindingParam = {
108
114
  ref: (parent, prop, xpr) => {
109
115
  if ((xpr[0].id || xpr[0]) === bindingParamName)
110
- setProp(parent, '$bparam', true)
116
+ setProp(parent, '$bparam', true);
111
117
  },
112
118
  };
113
119
  const refCheck = {
@@ -115,21 +121,22 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
115
121
  const { art, scope } = inspectRef(path);
116
122
  if (scope !== '$magic' && art) {
117
123
  const ft = csnUtils.getFinalTypeInfo(art.type);
118
- if (!isBuiltinType(ft?.type) && refCheck.anno !== 'value') {
124
+ if (!isBuiltinType(ft?.type) && refCheck.anno !== 'value')
119
125
  error('odata-anno-xpr-ref', path, { anno: refCheck.anno, elemref, '#': 'flatten_builtin_type' });
120
- }
121
126
  }
122
- }
127
+ },
123
128
  };
124
129
 
125
130
  const flatAnnos = Object.create(null);
126
131
  const annoNames = copyAnnotations(action, flatAnnos).filter(pn => pn[0] === '@');
127
132
  annoNames.forEach((an) => {
128
133
  refCheck.anno = an;
129
- transformAnnotationExpression(flatAnnos, an,
134
+ transformAnnotationExpression(
135
+ flatAnnos, an,
130
136
  [ markBindingParam, refCheck, refFlattener ],
131
- [ 'definitions', defName, 'actions', actionName ]);
132
- adaptRefs.forEach(fn => fn(true, 1, (parent) => parent.$bparam));
137
+ [ 'definitions', defName, 'actions', actionName ]
138
+ );
139
+ adaptRefs.forEach(fn => fn(true, 1, parent => parent.$bparam));
133
140
  adaptRefs.length = 0;
134
141
  });
135
142
  setProp(action, '$flatAnnotations', flatAnnos);
@@ -139,11 +146,10 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
139
146
  exprAnnos.forEach((pn) => {
140
147
  refCheck.anno = pn;
141
148
  transformAnnotationExpression(member, pn, [ markBindingParam, refCheck, refFlattener ], path);
142
- adaptRefs.forEach(fn => fn(true, 1, (parent) => parent.$bparam));
149
+ adaptRefs.forEach(fn => fn(true, 1, parent => parent.$bparam));
143
150
  adaptRefs.length = 0;
144
151
  });
145
- },
146
- [ 'definitions', defName, 'actions', actionName ]);
152
+ }, [ 'definitions', defName, 'actions', actionName ]);
147
153
  }
148
154
  }
149
155
  });
@@ -151,24 +157,24 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
151
157
  }
152
158
  // loop through types as well in order to collect the managaed associations
153
159
  // that reside in types definitions
154
- if ((def.kind === 'action' || def.kind === 'function' || def.kind === 'type' || def.kind === 'aspect' || def.kind === 'event')
155
- && !isExternalServiceMember(def, defName)) {
156
- if (def.kind === 'type' && csnUtils.isManagedAssociation(def))
160
+ if ((def.kind === 'action' || def.kind === 'function' || def.kind === 'type' || def.kind === 'aspect' || def.kind === 'event') &&
161
+ !isExternalServiceMember(def, defName)) {
162
+ if (def.kind === 'type' && csnUtils.isManagedAssociation(def)) {
157
163
  allMgdAssocDefs.push(def);
158
- else
164
+ }
165
+ else {
159
166
  forEachMemberRecursively(def, (elt, _eltName, _prop, _path) => {
160
- if (csnUtils.isManagedAssociation(elt)) {
167
+ if (csnUtils.isManagedAssociation(elt))
161
168
  allMgdAssocDefs.push(elt);
162
- }
163
169
  });
170
+ }
164
171
  }
165
172
  // loop through actions/functions and action/function parameters as well
166
173
  if (def.kind === 'entity' && def.actions && !isExternalServiceMember(def, defName)) {
167
174
  forEachGeneric(def, 'actions', (act) => {
168
175
  forEachMemberRecursively(act, (elt, _eltName, _prop, _path) => {
169
- if (csnUtils.isManagedAssociation(elt)) {
176
+ if (csnUtils.isManagedAssociation(elt))
170
177
  allMgdAssocDefs.push(elt);
171
- }
172
178
  });
173
179
  });
174
180
  }
@@ -176,46 +182,44 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
176
182
  return allMgdAssocDefs;
177
183
 
178
184
  function recurseIntoElement(scope, elt, resolvedElt, rootPathIsNotNull, location, rootPrefix = [], typeIdx = 0) {
179
- const eltName = rootPrefix[rootPrefix.length-1];
185
+ const eltName = rootPrefix[rootPrefix.length - 1];
180
186
  if (!resolvedElt.elements) {
181
187
  const flatElt = cloneElt(scope, elt, location, rootPrefix, typeIdx);
182
188
  if (rootPathIsNotNull)
183
189
  flatElt.notNull = true;
184
190
  else
185
191
  delete flatElt.notNull;
186
- return [[ eltName, flatElt ]];
187
- }
188
- else {
189
- let flattenedSubTree = [];
190
- forEach(resolvedElt.elements, (childName, child) => {
191
- resolvedElt = child;
192
- if (child.type && !child.elements) {
193
- resolvedElt = getFinalTypeInfo(child.type);
194
- if (resolvedElt.elements)
195
- typeIdx = rootPrefix.length + 1;
196
- }
197
- flattenedSubTree = flattenedSubTree.concat(recurseIntoElement(scope, child, resolvedElt,
198
- !!(child.notNull && rootPathIsNotNull),
199
- [... location, 'elements', childName],
200
- [ ...rootPrefix, childName ], typeIdx));
201
- });
202
- // 1) rename, 2) filter duplicates and finalize new elements
203
- const duplicateDict = Object.create(null);
204
- return flattenedSubTree.map(([flatEltName, flatElt]) => {
205
- return [ `${eltName}_${flatEltName}`, flatElt ];
206
- }).filter(([name, flatElt]) =>{
207
- if (duplicateDict[name]) {
208
- error('name-duplicate-element', location,
209
- { '#': 'flatten-element-gen', name });
210
- return false;
211
- }
212
- else {
213
- propagateToFlatElem(elt, flatElt, rootPrefix, typeIdx);
214
- duplicateDict[name] = flatElt;
215
- return true;
216
- }
217
- })
192
+ return [ [ eltName, flatElt ] ];
218
193
  }
194
+
195
+ let flattenedSubTree = [];
196
+ forEach(resolvedElt.elements, (childName, child) => {
197
+ resolvedElt = child;
198
+ if (child.type && !child.elements) {
199
+ resolvedElt = getFinalTypeInfo(child.type);
200
+ if (resolvedElt.elements)
201
+ typeIdx = rootPrefix.length + 1;
202
+ }
203
+ flattenedSubTree = flattenedSubTree.concat(recurseIntoElement(
204
+ scope, child, resolvedElt,
205
+ !!(child.notNull && rootPathIsNotNull),
206
+ [ ...location, 'elements', childName ],
207
+ [ ...rootPrefix, childName ], typeIdx
208
+ ));
209
+ });
210
+ // 1) rename, 2) filter duplicates and finalize new elements
211
+ const duplicateDict = Object.create(null);
212
+ return flattenedSubTree.map(([ flatEltName, flatElt ]) => [ `${ eltName }_${ flatEltName }`, flatElt ]).filter(([ name, flatElt ]) => {
213
+ if (duplicateDict[name]) {
214
+ error('name-duplicate-element', location,
215
+ { '#': 'flatten-element-gen', name });
216
+ return false;
217
+ }
218
+
219
+ propagateToFlatElem(elt, flatElt, rootPrefix, typeIdx);
220
+ duplicateDict[name] = flatElt;
221
+ return true;
222
+ });
219
223
  }
220
224
 
221
225
  function propagateToFlatElem(elt, flatElt, rootPrefix = [], typeIdx = 0) {
@@ -243,7 +247,7 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
243
247
  const exprAnnoNames = copyAnnotations(elt, flatElt, false, excludes).filter(pn => pn[0] === '@');
244
248
  flattenAndPrefixExprPaths(flatElt, exprAnnoNames, elt.$path, rootPrefix, typeIdx);
245
249
  // Copy selected type properties
246
- ['key', 'virtual', 'masked', 'viaAll', 'localized'].forEach(p => {
250
+ [ 'key', 'virtual', 'masked', 'viaAll', 'localized' ].forEach((p) => {
247
251
  if (elt[p] != null)
248
252
  flatElt[p] = elt[p];
249
253
  });
@@ -251,28 +255,28 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
251
255
 
252
256
  // Copy the original element
253
257
  function cloneElt(scope, elt, location, rootPrefix = [], typeIdx = 0) {
254
- const flatElt = cloneCsnNonDict(elt,
255
- { ...options,
256
- hiddenPropertiesToClone: [ '$structRef', '$fkExtensions', '$generatedForeignKeys' ]
257
- } );
258
+ const flatElt = cloneCsnNonDict(elt, {
259
+ ...options,
260
+ hiddenPropertiesToClone: [ '$structRef', '$fkExtensions', '$generatedForeignKeys' ],
261
+ } );
258
262
 
259
263
  // needed for @cds.persistence.name
260
264
  setProp(flatElt, '$defPath', rootPrefix);
261
265
  setProp(flatElt, '$scope', scope);
262
266
  retypeCloneWithFinalBaseType(flatElt, location);
263
- if((elt._type || elt).type === 'cds.Map') {
267
+ if ((elt._type || elt).type === 'cds.Map')
264
268
  assignAnnotation(flatElt, '@open', elt['@open'] || true);
265
- }
269
+
266
270
  const [ nonAnnoProps, exprAnnoProps ] = Object.keys(flatElt).reduce((acc, pn) => {
267
271
  if (pn[0] !== '@' && pn !== 'value')
268
272
  acc[0].push(pn);
269
273
  else
270
274
  acc[1].push(pn);
271
275
  return acc;
272
- }, [[],[]]);
276
+ }, [ [], [] ]);
273
277
  // transform all non annotation properties for that flat element with the generic transformer
274
278
  // we don't know what's inside the element clone (like anonymous sub elements behind 'items' etc.)
275
- nonAnnoProps.forEach(pn => applyTransformationsOnNonDictionary(flatElt, pn, refFlattener, {}, elt.$path || location))
279
+ nonAnnoProps.forEach(pn => applyTransformationsOnNonDictionary(flatElt, pn, refFlattener, {}, elt.$path || location));
276
280
  adaptRefs.forEach(fn => fn());
277
281
  adaptRefs.length = 0;
278
282
  // flatten and prefix annotations and 'value' paths
@@ -282,8 +286,8 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
282
286
  function retypeCloneWithFinalBaseType(elt, location) {
283
287
  if (elt.type &&
284
288
  !isBuiltinType(elt.type) &&
285
- !isODataV4BuiltinFromService(elt.type, location)
286
- && !isItemsType(elt.type)) {
289
+ !isODataV4BuiltinFromService(elt.type, location) &&
290
+ !isItemsType(elt.type)) {
287
291
  const resolvedType = csnUtils.getFinalTypeInfo(elt);
288
292
 
289
293
  delete resolvedType.kind;
@@ -295,16 +299,16 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
295
299
  elt.items = resolvedType;
296
300
  delete elt.items.type;
297
301
  }
298
- else
302
+ else {
299
303
  elt.items.type = resolvedType;
304
+ }
305
+ }
306
+ else if (resolvedType.items) {
307
+ elt.items = resolvedType.items;
308
+ delete elt.type;
300
309
  }
301
310
  else {
302
- if (resolvedType.items) {
303
- elt.items = resolvedType.items;
304
- delete elt.type;
305
- }
306
- else
307
- elt.type = resolvedType;
311
+ elt.type = resolvedType;
308
312
  }
309
313
  }
310
314
 
@@ -338,98 +342,97 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
338
342
  // Later, the query can/must be rewritten as long as a flat OData CSN is published
339
343
  // but this then operates on the entity/view which has all struct infos available
340
344
  function flattenAndPrefixExprPaths(carrier, propNames, csnPath, rootPrefix, typeIdx, refParentIsItems = false) {
341
-
342
345
  const refCheck = {
343
346
  ref: (elemref, prop, xpr, path) => {
344
347
  const { links, art, scope } = inspectRef(path);
345
348
  if (scope !== '$magic' && art) {
346
349
  // try to find rightmost 'items', terminate if association comes first.
347
- let i = links.length-1;
348
- const getProp = (propName) => links[i].art?.[propName];
350
+ let i = links.length - 1;
351
+ const getProp = propName => links[i].art?.[propName];
349
352
 
350
353
  let hasItems = false;
351
- for(; i >= 0 && !getProp('target') && !hasItems; i--) {
352
- const art = links[i].art;
353
- hasItems = !!getProp('items') || (art.type && !!csnUtils.getFinalTypeInfo(art.type)?.items)
354
+ for (; i >= 0 && !getProp('target') && !hasItems; i--) {
355
+ const { art } = links[i];
356
+ hasItems = !!getProp('items') || (art.type && !!csnUtils.getFinalTypeInfo(art.type)?.items);
354
357
  }
355
- if(!hasItems) {
358
+ if (!hasItems) {
356
359
  const ft = csnUtils.getFinalTypeInfo(art.type);
357
360
  if (!isBuiltinType(ft?.items?.type || ft?.type) && refCheck.anno !== 'value') {
358
- error('odata-anno-xpr-ref', path,
359
- {
360
- anno: refCheck.anno,
361
- elemref,
362
- name: refCheck.eltLocationStr,
363
- '#': 'flatten_builtin'
364
- });
361
+ error('odata-anno-xpr-ref', path, {
362
+ anno: refCheck.anno,
363
+ elemref,
364
+ name: refCheck.eltLocationStr,
365
+ '#': 'flatten_builtin',
366
+ });
365
367
  }
366
368
  }
367
369
  }
368
- }
369
- }
370
+ },
371
+ };
370
372
 
371
- refCheck.eltLocationStr = (function() {
372
- const [head, ...tail ] = rootPrefix;
373
- if(tail.length)
374
- return `${head}:${tail.join('.')}`;
375
- else
376
- return `${head}`;
377
- })();
373
+ refCheck.eltLocationStr = (function getEltLocationStr() {
374
+ const [ head, ...tail ] = rootPrefix;
375
+ if (tail.length)
376
+ return `${ head }:${ tail.join('.') }`;
377
+ return `${ head }`;
378
+ }());
378
379
 
379
380
  const absolutifier = {
380
- ref : (parent, prop, xpr, _path, _p, _ppn, ctx) => {
381
+ ref: (parent, prop, xpr, _path, _p, _ppn, ctx) => {
381
382
  const head = xpr[0].id || xpr[0];
382
383
  let isPrefixed = false;
383
- if(!isMagicVariable(head)) {
384
+ if (!isMagicVariable(head)) {
384
385
  if (head === '$self' && typeIdx < rootPrefix.length) {
385
386
  isPrefixed = true;
386
- const [xprHead, ...xprTail] = xpr.slice(1, xpr.length);
387
- if(xprHead) {
387
+ const [ xprHead, ...xprTail ] = xpr.slice(1, xpr.length);
388
+ if (xprHead) {
388
389
  if (xprHead.id) {
389
390
  xprHead.id = rootPrefix.slice(1, typeIdx).concat(xprHead.id).join('_');
390
391
  parent[prop] = [ xprHead, ...xprTail ];
391
392
  }
392
- else
393
- parent[prop] = [ rootPrefix.slice(1, typeIdx).concat(xprHead).join('_'), ...xprTail];
393
+ else {
394
+ parent[prop] = [ rootPrefix.slice(1, typeIdx).concat(xprHead).join('_'), ...xprTail ];
395
+ }
394
396
  }
395
397
  }
396
398
  else if (head !== '$self' && !parent.param && rootPrefix.length > 2) {
397
399
  isPrefixed = true;
398
- const [xprHead, ...xprTail] = xpr;
400
+ const [ xprHead, ...xprTail ] = xpr;
399
401
  if (!refParentIsItems) {
400
402
  if (xprHead.id) {
401
403
  xprHead.id = rootPrefix.slice(1, -1).concat(xprHead.id).join('_');
402
404
  parent[prop] = [ xprHead, ...xprTail ];
403
405
  }
404
- else
405
- parent[prop] = [ rootPrefix.slice(1, -1).concat(xprHead).join('_'), ...xprTail];
406
+ else {
407
+ parent[prop] = [ rootPrefix.slice(1, -1).concat(xprHead).join('_'), ...xprTail ];
408
+ }
409
+ }
410
+ else {
411
+ parent[prop] = [ ...rootPrefix.slice(0, rootPrefix.length - 1), ...xpr ];
406
412
  }
407
- else
408
- parent[prop] = [ ...rootPrefix.slice(0, rootPrefix.length-1), ...xpr];
409
413
  }
410
- if(isPrefixed) {
414
+ if (isPrefixed) {
411
415
  if (carrier.$scope === 'params')
412
416
  parent.param = true;
413
417
  else
414
418
  parent[prop].unshift('$self');
415
419
  }
416
420
  }
417
- if(isPrefixed && ctx?.annoExpr?.['=']) {
421
+ if (isPrefixed && ctx?.annoExpr?.['='])
418
422
  ctx.annoExpr['='] = true;
419
- }
420
- }
421
- }
423
+ },
424
+ };
422
425
 
423
426
  refFlattener.$fnArgs = [ refParentIsItems ];
424
- propNames.forEach(pn => {
427
+ propNames.forEach((pn) => {
425
428
  refCheck.anno = pn;
426
- if(pn[0] === '@') {
429
+ if (pn[0] === '@') {
427
430
  transformAnnotationExpression(carrier, pn, [ refCheck, refFlattener ], csnPath);
428
431
  adaptRefs.forEach(fn => fn(refParentIsItems));
429
432
  adaptRefs.length = 0;
430
433
  transformAnnotationExpression(carrier, pn, absolutifier, csnPath);
431
434
  }
432
- if(pn === 'value') {
435
+ if (pn === 'value') {
433
436
  transformExpression(carrier, pn, [ refCheck, refFlattener ], csnPath);
434
437
  adaptRefs.forEach(fn => fn(refParentIsItems));
435
438
  adaptRefs.length = 0;
@@ -448,10 +451,10 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
448
451
  transformExpression(flatElt, 'on', {
449
452
  ref: (parent, prop, xpr) => {
450
453
  const prefix = flatElt.$defPath.slice(1, -1).join('_');
451
- const possibleFlatName = `${prefix}_${xpr[0]}`;
454
+ const possibleFlatName = `${ prefix }_${ xpr[0] }`;
452
455
  if (flattenedSubTree.find(entry => entry[0] === possibleFlatName))
453
456
  xpr[0] = possibleFlatName;
454
- }
457
+ },
455
458
  });
456
459
  }
457
460
  }
@@ -463,42 +466,50 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
463
466
  return;
464
467
  const structuredAssocName = flatElt.$defPath[flatElt.$defPath.length - 1];
465
468
  const generatedForeignKeysForAssoc = flattenedSubTree
466
- .filter(se => {
469
+ .filter((se) => {
467
470
  // compare $defPath without the last element
468
- let comeFromSameDef = flatElt.$defPath.slice(0, flatElt.$defPath.length - 1).join('.') === se[1].$defPath.slice(0, se[1].$defPath.length - 1).join('.');
469
- return (comeFromSameDef && (se[1]['@odata.foreignKey4'] && se[1]['@odata.foreignKey4'] === structuredAssocName) && se[0].startsWith(flatEltName))
471
+ const comeFromSameDef = flatElt.$defPath.slice(0, flatElt.$defPath.length - 1).join('.') === se[1].$defPath.slice(0, se[1].$defPath.length - 1).join('.');
472
+ return (comeFromSameDef && (se[1]['@odata.foreignKey4'] && se[1]['@odata.foreignKey4'] === structuredAssocName) && se[0].startsWith(flatEltName));
470
473
  });
471
474
 
472
- generatedForeignKeysForAssoc.forEach(gfk => gfk[1]['@odata.foreignKey4'] = flatEltName);
475
+ generatedForeignKeysForAssoc.forEach((gfk) => {
476
+ gfk[1]['@odata.foreignKey4'] = flatEltName;
477
+ });
473
478
  // reassign the generated foreign keys for current assoc in order to assign
474
479
  // correct values for $generatedFieldName later on during flattenManagedAssocsAsKeys();
475
- // eslint-disable-next-line @stylistic/max-statements-per-line
476
- setProp(flatElt, '$generatedForeignKeys', generatedForeignKeysForAssoc.map(gfk => { return { name: gfk[0] }}));
480
+
481
+ setProp(flatElt, '$generatedForeignKeys', generatedForeignKeysForAssoc.map(gfk => ({ name: gfk[0] })));
477
482
  }
478
483
  }
479
484
 
480
485
  function flattenAllStructStepsInRefs( csn, refFlattener, adaptRefs, inspectRef, effectiveType,
481
- csnUtils, error, options, iterateOptions = {} ) {
482
-
486
+ csnUtils, error, options, iterateOptions = {} ) {
483
487
  // All anno path flattening is already done, don't do it on locations where we don't want it!
484
488
  const typeNames = [];
485
489
  forEachDefinition(csn, (def, defName) => {
486
490
  if (def.kind === 'entity') {
487
- ['query', 'projection'].forEach(dictName => {
488
- applyTransformationsOnNonDictionary(csn.definitions[defName],
489
- dictName, refFlattener, iterateOptions,
490
- [ 'definitions', defName ]);
491
- })
492
- if (csn.definitions[defName].actions)
493
- applyTransformationsOnDictionary(csn.definitions[defName].actions,
491
+ [ 'query', 'projection' ].forEach((dictName) => {
492
+ applyTransformationsOnNonDictionary(
493
+ csn.definitions[defName],
494
+ dictName, refFlattener, iterateOptions,
495
+ [ 'definitions', defName ]
496
+ );
497
+ });
498
+ if (csn.definitions[defName].actions) {
499
+ applyTransformationsOnDictionary(
500
+ csn.definitions[defName].actions,
494
501
  refFlattener, iterateOptions,
495
- [ 'definitions', defName, 'actions' ]);
502
+ [ 'definitions', defName, 'actions' ]
503
+ );
504
+ }
496
505
  }
497
506
 
498
- if (['type'].includes(def.kind)) {
507
+ if (def.kind === 'type') {
499
508
  typeNames.push(defName);
500
- applyTransformationsOnNonDictionary(csn.definitions,
501
- defName, refFlattener, iterateOptions, [ 'definitions' ]);
509
+ applyTransformationsOnNonDictionary(
510
+ csn.definitions,
511
+ defName, refFlattener, iterateOptions, [ 'definitions' ]
512
+ );
502
513
  }
503
514
  });
504
515
  adaptRefs.forEach(fn => fn());
@@ -509,34 +520,33 @@ function flattenAllStructStepsInRefs( csn, refFlattener, adaptRefs, inspectRef,
509
520
  const { links, art, scope } = inspectRef(path);
510
521
 
511
522
  if (scope !== '$magic' && art) {
512
- let i = links.length-2;
513
- const getProp = (propName) =>
514
- (links[i].art?.[propName] ||
523
+ let i = links.length - 2;
524
+ const getProp = propName => (links[i].art?.[propName] ||
515
525
  effectiveType(links[i].art)[propName]);
516
526
 
517
- let target = undefined;
518
- for(; i >= 0 && !getProp('items') && !target; i--) {
527
+ let target;
528
+ for (; i >= 0 && !getProp('items') && !target; i--)
519
529
  target = getProp('target');
520
- }
530
+
521
531
  const ft = csnUtils.getFinalTypeInfo(art.type);
522
- if (target && csn.definitions[target].$flatelements
523
- && !isBuiltinType(ft?.type) && refCheck.anno !== 'value') {
532
+ if (target && csn.definitions[target].$flatelements &&
533
+ !isBuiltinType(ft?.type) && refCheck.anno !== 'value') {
524
534
  error('odata-anno-xpr-ref', path,
525
- { anno: refCheck.anno, elemref, '#': 'flatten_builtin_type' });
535
+ { anno: refCheck.anno, elemref, '#': 'flatten_builtin_type' });
526
536
  }
527
537
  }
528
- }
529
- }
530
- typeNames.forEach(tn => {
538
+ },
539
+ };
540
+ typeNames.forEach((tn) => {
531
541
  forEachMemberRecursively(csn.definitions[tn], (member, memberName, prop, csnPath) => {
532
- Object.keys(member).filter(pn => pn[0] === '@').forEach(pn => {
542
+ Object.keys(member).filter(pn => pn[0] === '@').forEach((pn) => {
533
543
  refCheck.anno = pn;
534
544
  transformAnnotationExpression(member, pn, [ refCheck, refFlattener ], csnPath);
535
545
  adaptRefs.forEach(fn => fn(true, 1));
536
546
  adaptRefs.length = 0;
537
547
  });
538
548
  }, [ 'definitions', tn ]);
539
- })
549
+ });
540
550
  }
541
551
 
542
552
  function getStructRefFlatteningTransformer(csn, inspectRef, effectiveType, options, resolved, pathDelimiter) {
@@ -568,7 +578,7 @@ function getStructRefFlatteningTransformer(csn, inspectRef, effectiveType, optio
568
578
  setProp(parent, '_art', art);
569
579
  const lastRef = ref[ref.length - 1];
570
580
  const fn = (suspend = false, suspendPos = 0,
571
- refFilter = (_parent) => true) => {
581
+ refFilter = _parent => true) => {
572
582
  if (refFilter(parent)) {
573
583
  const scopedPath = [ ...parent.$path ];
574
584
  // TODO: If foreign key annotations should be assigned via
@@ -576,10 +586,12 @@ function getStructRefFlatteningTransformer(csn, inspectRef, effectiveType, optio
576
586
  // comment/remove setProp in expansion.js
577
587
  // setProp(parent, '$structRef', parent.ref);
578
588
  const flattenParameters = true; // structured parameters are flattened
579
- const [ newRef, refChanged ] = flattenStructStepsInRef(ref,
580
- scopedPath, links, scope, resolvedLinkTypes,
581
- suspend, suspendPos, parent.$bparam,
582
- flattenParameters);
589
+ const [ newRef, refChanged ] = flattenStructStepsInRef(
590
+ ref,
591
+ scopedPath, links, scope, resolvedLinkTypes,
592
+ suspend, suspendPos, parent.$bparam,
593
+ flattenParameters
594
+ );
583
595
  parent.ref = newRef;
584
596
  resolved.set(parent, { links, art, scope });
585
597
  // Explicitly set implicit alias for things that are now flattened - but only in columns
@@ -605,10 +617,10 @@ function getStructRefFlatteningTransformer(csn, inspectRef, effectiveType, optio
605
617
  * @returns {boolean}
606
618
  */
607
619
  function insideColumns( path ) {
608
- return path.length >= 3
609
- && (path[path.length - 3] === 'SELECT'
610
- || path[path.length - 3] === 'projection')
611
- && path[path.length - 2] === 'columns';
620
+ return path.length >= 3 &&
621
+ (path[path.length - 3] === 'SELECT' ||
622
+ path[path.length - 3] === 'projection') &&
623
+ path[path.length - 2] === 'columns';
612
624
  }
613
625
  };
614
626
  /**
@@ -618,31 +630,34 @@ function getStructRefFlatteningTransformer(csn, inspectRef, effectiveType, optio
618
630
  * @returns {boolean}
619
631
  */
620
632
  function insideKeys( path ) {
621
- return path.length >= 3
622
- && path[path.length - 2] === 'keys'
623
- && typeof path[path.length - 1] === 'number';
633
+ return path.length >= 3 &&
634
+ path[path.length - 2] === 'keys' &&
635
+ typeof path[path.length - 1] === 'number';
624
636
  }
625
637
 
626
638
 
627
639
  // adapt queries later
628
- if(ctx?.annoExpr?.['=']) {
629
- const annoExpr = ctx.annoExpr;
640
+ if (ctx?.annoExpr?.['=']) {
641
+ const { annoExpr } = ctx;
630
642
  adaptRefs.push((...args) => {
631
- if(fn(...args))
643
+ if (fn(...args))
632
644
  annoExpr['='] = true;
633
645
  });
634
646
  }
635
- else
647
+ else {
636
648
  adaptRefs.push(fn);
649
+ }
637
650
  },
638
- }
651
+ };
639
652
 
640
- return { adaptRefs, transformer, inspectRef, effectiveType };
653
+ return {
654
+ adaptRefs, transformer, inspectRef, effectiveType,
655
+ };
641
656
  }
642
657
 
643
658
  // replace managed associations in key refs with their respective foreing keys
644
659
  function replaceManagedAssocsAsKeys(allFlatManagedAssocDefinitions, csnUtils) {
645
- allFlatManagedAssocDefinitions.forEach( assoc => {
660
+ allFlatManagedAssocDefinitions.forEach( (assoc) => {
646
661
  let finished = false;
647
662
 
648
663
  if (!assoc.keys)
@@ -656,43 +671,44 @@ function replaceManagedAssocsAsKeys(allFlatManagedAssocDefinitions, csnUtils) {
656
671
 
657
672
  function processKeys(collector) {
658
673
  let done = true;
659
- assoc.keys.forEach( key => {
674
+ assoc.keys.forEach( (key) => {
660
675
  const art = key._art;
661
676
  if (art && csnUtils.isManagedAssociation(art)) {
662
677
  done = false;
663
678
  // key._art is the artifact from the structured model, because of that we need to look
664
679
  // for the flat representation in the allFlatManagedAssocDefinitions
665
680
  allFlatManagedAssocDefinitions.find(fa => (fa.$pathInStructuredModel || fa.$path).join() === art.$path.join())
666
- .keys.forEach( keyAssocKey => {
667
- collector.push(cloneAndExtendRef(keyAssocKey, key));
668
- });
681
+ .keys.forEach( (keyAssocKey) => {
682
+ collector.push(cloneAndExtendRef(keyAssocKey, key));
683
+ });
669
684
  }
670
- else if (art && !art.on){
685
+ else if (art && !art.on) {
671
686
  if (!key.$generatedFieldName) {
672
687
  const flatAssocName = assoc.$path[assoc.$path.length - 1];
673
688
  // When we have a definition like type "<type_name>: Association to <target_name>",
674
689
  // we do not generate foreign keys in the definition, therefore no $generatedForeignKeys,
675
690
  // respectively we do not assign $generatedFieldName
676
691
  if (assoc.$generatedForeignKeys) {
677
- const generatedForeignKey = assoc.$generatedForeignKeys.find(gfk => gfk.name === `${flatAssocName}_${key.as || key.ref.join('_')}`);
692
+ const generatedForeignKey = assoc.$generatedForeignKeys.find(gfk => gfk.name === `${ flatAssocName }_${ key.as || key.ref.join('_') }`);
678
693
  key.$generatedFieldName = generatedForeignKey.name;
679
694
  }
680
695
  }
681
- if (key.as && key.as === key.ref[0]) delete key.as;
696
+ if (key.as && key.as === key.ref[0])
697
+ delete key.as;
682
698
  collector.push(key);
683
699
  }
684
- })
700
+ });
685
701
 
686
702
  return done;
687
703
  }
688
704
  });
689
705
 
690
706
  function cloneAndExtendRef(keyAssocKey, key) {
691
- let newKey = { ref: [`${key.ref.join('_')}_${keyAssocKey.as || keyAssocKey.ref.join('_')}`] };
707
+ const newKey = { ref: [ `${ key.ref.join('_') }_${ keyAssocKey.as || keyAssocKey.ref.join('_') }` ] };
692
708
  setProp(newKey, '_art', keyAssocKey._art);
693
- if (key.as) {
694
- newKey.as = `${key.as}_${keyAssocKey.as || keyAssocKey.ref.join('_')}`;
695
- }
709
+ if (key.as)
710
+ newKey.as = `${ key.as }_${ keyAssocKey.as || keyAssocKey.ref.join('_') }`;
711
+
696
712
  return newKey;
697
713
  }
698
714
  }
@@ -702,5 +718,5 @@ module.exports = {
702
718
  flattenAllStructStepsInRefs,
703
719
  handleManagedAssociationsAndCreateForeignKeys,
704
720
  getStructRefFlatteningTransformer,
705
- replaceManagedAssocsAsKeys
721
+ replaceManagedAssocsAsKeys,
706
722
  };