@sap/cds-compiler 4.1.2 → 4.2.2

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 (74) hide show
  1. package/CHANGELOG.md +101 -1
  2. package/bin/cdsc.js +6 -3
  3. package/doc/CHANGELOG_BETA.md +5 -0
  4. package/doc/CHANGELOG_DEPRECATED.md +15 -0
  5. package/lib/api/main.js +2 -2
  6. package/lib/api/options.js +2 -2
  7. package/lib/api/validate.js +24 -24
  8. package/lib/base/message-registry.js +41 -6
  9. package/lib/base/messages.js +7 -0
  10. package/lib/base/model.js +37 -8
  11. package/lib/checks/elements.js +11 -10
  12. package/lib/checks/manyNavigations.js +33 -0
  13. package/lib/checks/onConditions.js +5 -2
  14. package/lib/checks/queryNoDbArtifacts.js +2 -3
  15. package/lib/checks/selectItems.js +4 -55
  16. package/lib/checks/utils.js +3 -2
  17. package/lib/checks/validator.js +3 -1
  18. package/lib/compiler/.eslintrc.json +2 -1
  19. package/lib/compiler/assert-consistency.js +27 -24
  20. package/lib/compiler/base.js +6 -2
  21. package/lib/compiler/builtins.js +34 -34
  22. package/lib/compiler/checks.js +179 -208
  23. package/lib/compiler/classes.js +2 -2
  24. package/lib/compiler/cycle-detector.js +6 -6
  25. package/lib/compiler/define.js +66 -45
  26. package/lib/compiler/extend.js +81 -72
  27. package/lib/compiler/finalize-parse-cdl.js +26 -26
  28. package/lib/compiler/generate.js +61 -45
  29. package/lib/compiler/index.js +47 -49
  30. package/lib/compiler/kick-start.js +8 -7
  31. package/lib/compiler/moduleLayers.js +1 -1
  32. package/lib/compiler/populate.js +42 -35
  33. package/lib/compiler/propagator.js +6 -6
  34. package/lib/compiler/resolve.js +170 -126
  35. package/lib/compiler/shared.js +122 -45
  36. package/lib/compiler/tweak-assocs.js +93 -40
  37. package/lib/compiler/utils.js +15 -12
  38. package/lib/edm/.eslintrc.json +40 -1
  39. package/lib/edm/annotations/genericTranslation.js +721 -707
  40. package/lib/edm/annotations/preprocessAnnotations.js +88 -77
  41. package/lib/edm/csn2edm.js +389 -378
  42. package/lib/edm/edm.js +678 -772
  43. package/lib/edm/edmAnnoPreprocessor.js +132 -146
  44. package/lib/edm/edmInboundChecks.js +29 -27
  45. package/lib/edm/edmPreprocessor.js +686 -646
  46. package/lib/edm/edmUtils.js +277 -296
  47. package/lib/gen/language.checksum +1 -1
  48. package/lib/gen/language.interp +1 -1
  49. package/lib/gen/languageParser.js +1253 -1276
  50. package/lib/json/from-csn.js +34 -4
  51. package/lib/json/to-csn.js +4 -4
  52. package/lib/language/language.g4 +2 -5
  53. package/lib/main.d.ts +61 -1
  54. package/lib/model/csnUtils.js +31 -2
  55. package/lib/model/revealInternalProperties.js +1 -1
  56. package/lib/modelCompare/compare.js +37 -2
  57. package/lib/modelCompare/utils/filter.js +1 -1
  58. package/lib/optionProcessor.js +15 -3
  59. package/lib/render/toCdl.js +30 -4
  60. package/lib/render/toSql.js +5 -9
  61. package/lib/render/utils/common.js +8 -6
  62. package/lib/transform/db/applyTransformations.js +1 -1
  63. package/lib/transform/db/cdsPersistence.js +1 -1
  64. package/lib/transform/db/constraints.js +47 -17
  65. package/lib/transform/db/expansion.js +121 -47
  66. package/lib/transform/db/flattening.js +75 -7
  67. package/lib/transform/forOdata.js +4 -1
  68. package/lib/transform/forRelationalDB.js +80 -62
  69. package/lib/transform/localized.js +91 -54
  70. package/lib/transform/transformUtils.js +9 -10
  71. package/lib/utils/file.js +7 -7
  72. package/lib/utils/moduleResolve.js +210 -121
  73. package/lib/utils/objectUtils.js +1 -1
  74. package/package.json +5 -5
@@ -1,4 +1,5 @@
1
1
  'use strict';
2
+
2
3
  /* eslint max-statements-per-line:off */
3
4
  const { setProp, isDeprecatedEnabled, isBetaEnabled } = require('../base/model');
4
5
  const {
@@ -15,10 +16,10 @@ const expandCSNToFinalBaseType = require('../transform/odata/toFinalBaseType');
15
16
  const NavResAnno = '@Capabilities.NavigationRestrictions.RestrictedProperties';
16
17
 
17
18
  // Capabilities that can be pulled up to NavigationRestrictions
18
- const capabilities = Object.keys(require('../gen/Dictionary.json').
19
- types['Capabilities.NavigationPropertyRestriction'].Properties).
20
- filter(c => !['NavigationProperty', 'Navigability'].includes(c)).
21
- map(c => '@Capabilities.'+c);
19
+ const capabilities = Object.keys(require('../gen/Dictionary.json')
20
+ .types['Capabilities.NavigationPropertyRestriction'].Properties)
21
+ .filter(c => ![ 'NavigationProperty', 'Navigability' ].includes(c))
22
+ .map(c => `@Capabilities.${c}`);
22
23
 
23
24
  /**
24
25
  * edmPreprocessor warms up the model so that it can be converted into an EDM document and
@@ -30,9 +31,10 @@ const capabilities = Object.keys(require('../gen/Dictionary.json').
30
31
  * @param {CSN.Model} csn
31
32
  * @param {object} _options
32
33
  */
33
- function initializeModel(csn, _options, messageFunctions, requestedServiceNames=undefined)
34
- {
35
- const { info, warning, error, message } = messageFunctions;
34
+ function initializeModel( csn, _options, messageFunctions, requestedServiceNames = undefined ) {
35
+ const {
36
+ info, warning, error, message,
37
+ } = messageFunctions;
36
38
  const special$self = !csn?.definitions?.$self && '$self';
37
39
  const csnUtils = getUtils(csn);
38
40
 
@@ -45,36 +47,36 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
45
47
 
46
48
 
47
49
  // make sure options are complete
48
- let options = edmUtils.validateOptions(_options);
50
+ const options = edmUtils.validateOptions(_options);
49
51
 
50
52
  const [ serviceRoots,
51
53
  serviceRootNames,
52
54
  fallBackSchemaName,
53
- whatsMyServiceRootName ] = getAnOverviewOnTheServices(csn);
55
+ whatsMyServiceRootName ] = getAnOverviewOnTheServices();
56
+
57
+ if (serviceRootNames.length === 0)
58
+ return [ serviceRoots, Object.create(null), reqDefs, whatsMyServiceRootName, fallBackSchemaName, options ];
54
59
 
55
- if(serviceRootNames.length === 0) {
56
- return [serviceRoots, Object.create(null), reqDefs, whatsMyServiceRootName, fallBackSchemaName, options];
57
- }
58
60
 
59
- if(requestedServiceNames === undefined)
61
+ if (requestedServiceNames === undefined)
60
62
  requestedServiceNames = options.serviceNames;
61
- if(requestedServiceNames === undefined) {
63
+ if (requestedServiceNames === undefined)
62
64
  requestedServiceNames = serviceRootNames;
63
- }
64
65
 
65
- function isMyServiceRequested(n) {
66
+
67
+ function isMyServiceRequested( n ) {
66
68
  return requestedServiceNames.includes(whatsMyServiceRootName(n));
67
69
  }
68
70
 
69
71
  // Structural CSN inbound QA checks
70
72
  inboundQualificationChecks(csn, options, messageFunctions,
71
- serviceRootNames, requestedServiceNames, isMyServiceRequested, whatsMyServiceRootName, csnUtils);
73
+ serviceRootNames, requestedServiceNames, isMyServiceRequested, whatsMyServiceRootName, csnUtils);
72
74
  // not needed at the moment
73
75
  // resolveForeignKeyRefs();
74
76
 
75
- if(isBetaEnabled(options, undefined)) {
77
+ if (isBetaEnabled(options, undefined))
76
78
  splitDottedDefinitionsIntoSeparateServices();
77
- }
79
+
78
80
  else
79
81
  /*
80
82
  Replace dots with underscores for all definitions below a context
@@ -94,7 +96,8 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
94
96
  as a step in the OData transformer with the goal to have a protocol agnostic OData CSN.
95
97
  */
96
98
  if (csn.meta && csn.meta.options && csn.meta.options.odataVersion === 'v4' && options.isV2()) {
97
- const { toFinalBaseType }= require('../transform/transformUtils').getTransformers(csn, options);
99
+ // eslint-disable-next-line global-require
100
+ const { toFinalBaseType } = require('../transform/transformUtils').getTransformers(csn, options);
98
101
  expandCSNToFinalBaseType(csn, { toFinalBaseType }, csnUtils, serviceRootNames, options);
99
102
  }
100
103
 
@@ -102,31 +105,33 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
102
105
  Enrich the CSN by de-anonymizing and exposing types that are required to make the service self contained.
103
106
  */
104
107
  const schemas = typesExposure(csn, whatsMyServiceRootName, requestedServiceNames,
105
- fallBackSchemaName, options, csnUtils, { error });
108
+ fallBackSchemaName, options, csnUtils, { error });
106
109
 
107
110
  // Get an overview about all schemas (including the services)
108
- const schemaNames = [...serviceRootNames];
111
+ const schemaNames = [ ...serviceRootNames ];
109
112
  schemaNames.push(...Object.keys(schemas));
110
113
  // sort schemas in reverse order to allow longest match in whatsMySchemaName function
111
- schemaNames.sort((a,b) => b.length-a.length);
112
- function whatsMySchemaName(n) {
113
- return schemaNames.reduce((rc, sn) => !rc && n && n.startsWith(sn + '.') ? sn : rc, undefined);
114
+ schemaNames.sort((a, b) => b.length - a.length);
115
+ function whatsMySchemaName( n ) {
116
+ return schemaNames.reduce((rc, sn) => (!rc && n && n.startsWith(`${sn}.`) ? sn : rc), undefined);
114
117
  }
115
118
 
116
- if(schemaNames.length) {
119
+ if (schemaNames.length) {
117
120
  forEachDefinition(csn, [
118
121
  attachNameProperty,
119
122
  (def, defName) => {
120
123
  const mySchemaName = whatsMySchemaName(defName);
121
- mySchemaName && setProp(def, '$mySchemaName', mySchemaName);
122
- if(isMyServiceRequested(defName) && def.kind !== 'aspect')
124
+ if (mySchemaName)
125
+ setProp(def, '$mySchemaName', mySchemaName);
126
+ if (isMyServiceRequested(defName) && def.kind !== 'aspect')
123
127
  reqDefs.definitions[defName] = def;
124
128
  },
125
- linkAssociationTarget
129
+ linkAssociationTarget,
126
130
  ]);
127
131
  forEachGeneric(csn, 'vocabularies', (term, termName) => {
128
132
  const mySchemaName = whatsMySchemaName(termName);
129
- mySchemaName && setProp(term, '$mySchemaName', mySchemaName);
133
+ if (mySchemaName)
134
+ setProp(term, '$mySchemaName', mySchemaName);
130
135
  });
131
136
  // initialize requested services
132
137
  const skip = { skipArtifact: (_def, defName) => !isMyServiceRequested(defName) };
@@ -140,7 +145,7 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
140
145
  // Initialize associations after _parent linking
141
146
  forEachDefinition(reqDefs, initConstraints);
142
147
  // Mute V4 elements depending on constraint preparation
143
- if(options.isV4())
148
+ if (options.isV4())
144
149
  forEachDefinition(reqDefs, ignoreProperties);
145
150
  // calculate constraints based on ignoreProperties and initConstraints
146
151
  forEachDefinition(reqDefs, finalizeConstraints);
@@ -151,19 +156,20 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
151
156
  // Decide if an entity set needs to be constructed or not
152
157
  forEachDefinition(reqDefs, [
153
158
  exposeTargetsAsProxiesOrSchemaRefs,
154
- determineEntitySet
159
+ determineEntitySet,
155
160
  ]);
156
161
  // finalize proxy creation
157
162
  mergeProxiesIntoModel();
158
163
 
159
164
  // Calculate NavPropBinding Target paths
160
165
  // Rewrite @Capabilities for containment mode
161
- if(options.isV4())
166
+ if (options.isV4()) {
162
167
  forEachDefinition(reqDefs, [
163
168
  initEdmNavPropBindingTargets,
164
169
  pullupCapabilitiesAnnotations,
165
- annotateOptionalActFuncParams
170
+ annotateOptionalActFuncParams,
166
171
  ]);
172
+ }
167
173
 
168
174
  // Things that can be done in one pass
169
175
  // Create edmKeyRefPaths
@@ -172,7 +178,7 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
172
178
  forEachDefinition(reqDefs, [
173
179
  initEdmKeyRefPaths,
174
180
  initEdmNavPropBindingPaths,
175
- finalize
181
+ finalize,
176
182
  ]);
177
183
  }
178
184
  return [
@@ -181,47 +187,47 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
181
187
  reqDefs,
182
188
  whatsMyServiceRootName,
183
189
  fallBackSchemaName,
184
- options
190
+ options,
185
191
  ];
186
192
 
187
- //////////////////////////////////////////////////////////////////////
193
+ // ////////////////////////////////////////////////////////////////////
188
194
  //
189
195
  // Service initialization starts here
190
196
  //
191
197
 
192
- function getAnOverviewOnTheServices(csn) {
198
+ function getAnOverviewOnTheServices( ) {
193
199
  const defs = csn.definitions || {};
194
- const serviceRoots = Object.create(null);
195
- for(const defName in defs) {
200
+ const sroots = Object.create(null);
201
+ for (const defName in defs) {
196
202
  const def = defs[defName];
197
- if(def && def.kind === 'service')
198
- serviceRoots[defName] = Object.assign(def, { name: defName });
203
+ if (def && def.kind === 'service')
204
+ sroots[defName] = Object.assign(def, { name: defName });
199
205
  }
200
206
 
201
207
  // first of all we need to know about all 'real' user defined services
202
- const serviceRootNames = Object.keys(serviceRoots).sort((a,b)=>b.length-a.length);
208
+ const srootNames = Object.keys(sroots).sort((a, b) => b.length - a.length);
203
209
 
204
- function whatsMyServiceRootName(n, self=true) {
205
- return serviceRootNames.reduce((rc, sn) => !rc && n && n.startsWith(sn + '.') || (n === sn && self) ? sn : rc, undefined);
206
- }
207
210
 
208
211
  // find a globally unambiguous schema name to collect all top level 'root' types
209
212
  // TODO: work on service basis (this requires post exposure renaming)
210
- let fallBackSchemaName = 'root';
213
+ let fbSchemaName = 'root';
211
214
  let i = 1;
212
215
  const defNames = Object.keys(defs);
213
- while (defNames.some(artName => {
216
+ // eslint-disable-next-line no-loop-func
217
+ while (defNames.some((artName) => {
214
218
  const p = artName.split('.');
215
- return p.length === 2 && p[0] === fallBackSchemaName;
216
- })) {
217
- fallBackSchemaName = 'root' + i++;
218
- }
219
+ return p.length === 2 && p[0] === fbSchemaName;
220
+ }))
221
+ fbSchemaName = `root${i++}`;
222
+
219
223
 
220
224
  return [
221
- serviceRoots,
222
- serviceRootNames,
223
- fallBackSchemaName,
224
- whatsMyServiceRootName ];
225
+ sroots,
226
+ srootNames,
227
+ fbSchemaName,
228
+ // whatsMyServiceRootName
229
+ ( n, self = true ) => srootNames.reduce((rc, sn) => (!rc && n && n.startsWith(`${sn}.`) || (n === sn && self) ? sn : rc), undefined),
230
+ ];
225
231
  }
226
232
 
227
233
  /*
@@ -231,11 +237,10 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
231
237
  All type refs and assoc targets must also be adjusted to refer to the new names.
232
238
  */
233
239
  function renameDottedDefinitionsInsideServiceOrContext() {
234
-
235
240
  // Find the first definition above the current definition or undefined otherwise.
236
241
  // Definition can either be a context or a service
237
- function getRootDef(name) {
238
- const scopeKinds = {'service':1, 'context':1};
242
+ function getRootDef( name ) {
243
+ const scopeKinds = { service: 1, context: 1 };
239
244
  let pos = name.lastIndexOf('.');
240
245
  name = pos < 0 ? undefined : name.substring(0, pos);
241
246
  while (name && !((csn.definitions[name] && csn.definitions[name].kind) in scopeKinds)) {
@@ -247,24 +252,26 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
247
252
 
248
253
  const dotEntityNameMap = Object.create(null);
249
254
  const dotTypeNameMap = Object.create(null);
250
- const kinds = {'entity':1, 'type':1, 'action':1, 'function':1};
255
+ const kinds = {
256
+ entity: 1, type: 1, action: 1, function: 1,
257
+ };
251
258
  forEachDefinition(csn, (def, defName) => {
252
- if(def.kind in kinds) {
259
+ if (def.kind in kinds) {
253
260
  const rootDef = getRootDef(defName);
254
261
  // if this definition has a root def and the root def is not the service/schema name
255
262
  // => service C { type D.E }, replace the prefix dots with underscores
256
- if(rootDef && defName !== rootDef && rootDef !== edmUtils.getSchemaPrefix(defName)) {
257
- let newDefName = rootDef + '.' + defName.replace(rootDef + '.', '').replace(/\./g, '_');
263
+ if (rootDef && defName !== rootDef && rootDef !== edmUtils.getSchemaPrefix(defName)) {
264
+ const newDefName = `${rootDef}.${defName.replace(`${rootDef}.`, '').replace(/\./g, '_')}`;
258
265
  // store renamed types in correlation maps for later renaming
259
- if(def.kind === 'entity')
266
+ if (def.kind === 'entity')
260
267
  dotEntityNameMap[defName] = newDefName;
261
- if(def.kind === 'type')
268
+ if (def.kind === 'type')
262
269
  dotTypeNameMap[defName] = newDefName;
263
270
  // rename in csn.definitions
264
271
  const art = csn.definitions[newDefName];
265
- if(art !== undefined) {
272
+ if (art !== undefined) {
266
273
  error(null, [ 'definitions', defName ], { name: newDefName },
267
- 'Artifact name containing dots can\'t be mapped to an OData compliant name because it conflicts with existing definition $(NAME)');
274
+ 'Artifact name containing dots can\'t be mapped to an OData compliant name because it conflicts with existing definition $(NAME)');
268
275
  }
269
276
  else {
270
277
  csn.definitions[newDefName] = def;
@@ -276,32 +283,34 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
276
283
  });
277
284
  // rename type refs to new type names
278
285
  const rewrite = (def) => {
279
- const applyOnNode = (node) => {
280
- node = node.items || node;
281
- if(node.type && dotTypeNameMap[node.type]) {
282
- node.type = dotTypeNameMap[node.type];
283
- }
284
- if(node.target && dotEntityNameMap[node.target]) {
285
- node.target = dotEntityNameMap[node.target];
286
- }
287
- if(node.$path && dotEntityNameMap[node.$path[1]]) {
288
- node.$path[1] = dotEntityNameMap[node.$path[1]]
289
- }
290
- rewriteReferencesInActions(node);
291
- }
292
-
293
286
  const rewriteReferencesInActions = (act) => {
294
- act.params && Object.values(act.params).forEach(param => {
295
- param = param.items || param;
296
- if(param.type && (dotEntityNameMap[param.type] || dotTypeNameMap[param.type]))
297
- param.type = dotEntityNameMap[param.type] || dotTypeNameMap[param.type];
298
- });
299
- if(act.returns){
287
+ if (act.params) {
288
+ Object.values(act.params).forEach((param) => {
289
+ param = param.items || param;
290
+ if (param.type && (dotEntityNameMap[param.type] || dotTypeNameMap[param.type]))
291
+ param.type = dotEntityNameMap[param.type] || dotTypeNameMap[param.type];
292
+ });
293
+ }
294
+ if (act.returns) {
300
295
  const returnsObj = act.returns.items || act.returns;
301
296
  if (returnsObj.type && dotEntityNameMap[returnsObj.type] || dotTypeNameMap[returnsObj.type])
302
297
  returnsObj.type = dotEntityNameMap[returnsObj.type] || dotTypeNameMap[returnsObj.type];
303
298
  }
304
- }
299
+ };
300
+
301
+ const applyOnNode = (node) => {
302
+ node = node.items || node;
303
+ if (node.type && dotTypeNameMap[node.type])
304
+ node.type = dotTypeNameMap[node.type];
305
+
306
+ if (node.target && dotEntityNameMap[node.target])
307
+ node.target = dotEntityNameMap[node.target];
308
+
309
+ if (node.$path && dotEntityNameMap[node.$path[1]])
310
+ node.$path[1] = dotEntityNameMap[node.$path[1]];
311
+
312
+ rewriteReferencesInActions(node);
313
+ };
305
314
 
306
315
  forEachMemberRecursively(def, applyOnNode);
307
316
  applyOnNode(def);
@@ -321,11 +330,11 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
321
330
  */
322
331
  function splitDottedDefinitionsIntoSeparateServices() {
323
332
  forEachDefinition(csn, (def, defName) => {
324
- if(def.kind !== 'service') {
333
+ if (def.kind !== 'service') {
325
334
  const myServiceRoot = whatsMyServiceRootName(defName);
326
335
  const mySchemaPrefix = edmUtils.getSchemaPrefix(defName);
327
- if(myServiceRoot && options.isV4() &&
328
- /*(options.odataProxies || options.odataXServiceRefs) && options.isStructFormat && */
336
+ if (myServiceRoot && options.isV4() &&
337
+ /* (options.odataProxies || options.odataXServiceRefs) && options.isStructFormat && */
329
338
  defName !== myServiceRoot && myServiceRoot !== mySchemaPrefix) {
330
339
  const service = { kind: 'service', name: mySchemaPrefix };
331
340
  serviceRoots[mySchemaPrefix] = service;
@@ -333,42 +342,42 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
333
342
  }
334
343
  }
335
344
  });
336
- serviceRootNames.sort((a,b) => b.length-a.length);
345
+ serviceRootNames.sort((a, b) => b.length - a.length);
337
346
  }
338
347
 
339
- function attachNameProperty(def, defName) {
340
- edmUtils.assignProp (def, 'name', defName);
348
+ function attachNameProperty( def, defName ) {
349
+ edmUtils.assignProp(def, 'name', defName);
341
350
  // Attach name to bound actions, functions and parameters
342
- forEachGeneric(def, 'actions', (a, n) => {
343
- edmUtils.assignProp(a, 'name', n);
344
- forEachGeneric(a, 'params', (p, n) => {
345
- edmUtils.assignProp(p, 'name', n);
351
+ forEachGeneric(def, 'actions', (a, an) => {
352
+ edmUtils.assignProp(a, 'name', an);
353
+ forEachGeneric(a, 'params', (p, pn) => {
354
+ edmUtils.assignProp(p, 'name', pn);
346
355
  });
347
356
  });
348
357
  // Attach name unbound action parameters
349
- forEachGeneric(def, 'params', (p,n) => {
350
- edmUtils.assignProp(p, 'name', n);
358
+ forEachGeneric(def, 'params', (p, pn) => {
359
+ edmUtils.assignProp(p, 'name', pn);
351
360
  });
352
361
  }
353
362
 
354
363
  // initialize the service itself
355
- function initService(serviceRoot) {
364
+ function initService( serviceRoot ) {
356
365
  edmAnnoPreproc.setSAPSpecificV2AnnotationsToEntityContainer(options, serviceRoot);
357
366
  }
358
367
 
359
368
  // link association target to association and add @odata.contained to compositions in V4
360
- function linkAssociationTarget(struct) {
369
+ function linkAssociationTarget( struct ) {
361
370
  forEachMemberRecursively(struct, (element, name, prop, subpath) => {
362
- if(element.target && !element._target) {
363
- let target = csn.definitions[element.target];
364
- if(target) {
371
+ if (element.target && !element._target) {
372
+ const target = csn.definitions[element.target];
373
+ if (target) {
365
374
  setProp(element, '_target', target);
366
375
  // If target has parameters, xref assoc at target for redirection
367
- if(edmUtils.isParameterizedEntity(target)) {
368
- if(!target.$sources) {
376
+ if (edmUtils.isParameterizedEntity(target)) {
377
+ if (!target.$sources)
369
378
  setProp(target, '$sources', Object.create(null));
370
- }
371
- target.$sources[struct.name + '.' + name] = element;
379
+
380
+ target.$sources[`${struct.name}.${name}`] = element;
372
381
  }
373
382
  }
374
383
  else {
@@ -376,12 +385,11 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
376
385
  }
377
386
  }
378
387
  // in V4 tag all compositions to be containments
379
- if(options.odataContainment &&
388
+ if (options.odataContainment &&
380
389
  options.isV4() &&
381
390
  csnUtils.isComposition(element) &&
382
- element['@odata.contained'] === undefined) {
391
+ element['@odata.contained'] === undefined)
383
392
  element['@odata.contained'] = true;
384
- }
385
393
  });
386
394
  }
387
395
 
@@ -401,21 +409,21 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
401
409
  // $containeeAssociations stores the containees (children/outbound edges)
402
410
  // $containerNames stores the containers (parents/inbound edges)
403
411
 
404
- function initContainments(container) {
405
- if(container.kind === 'entity') {
406
- if(!container.$containeeAssociations)
412
+ function initContainments( container ) {
413
+ if (container.kind === 'entity') {
414
+ if (!container.$containeeAssociations)
407
415
  setProp(container, '$containeeAssociations', []);
408
- forEachMemberRecursively(container, initContainments,
409
- [], true, { pathWithoutProp: true, elementsOnly: true });
416
+ forEachMemberRecursively(container, eachAssoc,
417
+ [], true, { pathWithoutProp: true, elementsOnly: true });
410
418
  }
411
419
 
412
- function initContainments(elt, _memberName, _prop, path) {
413
- if(elt.target && elt['@odata.contained']) {
420
+ function eachAssoc( elt, _memberName, _prop, path ) {
421
+ if (elt.target && elt['@odata.contained']) {
414
422
  // store all containment associations, required to create the containment paths later on
415
423
  container.$containeeAssociations.push( { assoc: elt, path });
416
424
  // Let the containee know its container
417
425
  // (array because the contanee may contained more then once)
418
- let containee = elt._target;
426
+ const containee = elt._target;
419
427
  if (!containee.$containerNames)
420
428
  setProp(containee, '$containerNames', []);
421
429
  // add container only once per containee
@@ -423,39 +431,38 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
423
431
  containee.$containerNames.push(container.name);
424
432
  // Mark associations in the containee pointing to the container (i.e. to this entity)
425
433
  forEachMemberRecursively(containee, markToContainer,
426
- [ 'definitions', containee.name ], true, { elementsOnly: true });
434
+ [ 'definitions', containee.name ], true, { elementsOnly: true });
427
435
  }
428
- else if(elt.type && !elt.elements) {
436
+ else if (elt.type && !elt.elements) {
429
437
  // try to find elements to drill down further
430
- while(elt && !isBuiltinType(elt.type) && !elt.elements) {
438
+ while (elt && !isBuiltinType(elt.type) && !elt.elements)
431
439
  elt = csn.definitions[elt.type];
432
- }
433
- if(elt && elt.elements && !elt.$visited) {
440
+
441
+ if (elt && elt.elements && !elt.$visited) {
434
442
  setProp(elt, '$visited', true);
435
- forEachMemberRecursively(elt, initContainments,
436
- path, true, { pathWithoutProp: true, elementsOnly: true });
443
+ forEachMemberRecursively(elt, eachAssoc,
444
+ path, true, { pathWithoutProp: true, elementsOnly: true });
437
445
  delete elt.$visited;
438
446
  }
439
447
  }
440
448
  }
441
449
 
442
- function markToContainer(elt) {
443
- if(elt._target && elt._target.name) {
450
+ function markToContainer( elt ) {
451
+ if (elt._target && elt._target.name) {
444
452
  // If this is an association that points to the container (but is not by itself contained,
445
453
  // which would indicate the top role in a hierarchy) mark it with '_isToContainer'
446
- if(elt._target.name === container.name && !elt['odata.contained']) {
454
+ if (elt._target.name === container.name && !elt['odata.contained'])
447
455
  setProp(elt, '_isToContainer', true);
448
- }
449
456
  }
450
457
  else {
451
458
  // try to find elements to drill down further
452
- while(elt && !(isBuiltinType(elt.type) || elt.elements)) {
459
+ while (elt && !(isBuiltinType(elt.type) || elt.elements))
453
460
  elt = csn.definitions[elt.type];
454
- }
455
- if(elt && elt.elements && !elt.$visited) {
461
+
462
+ if (elt && elt.elements && !elt.$visited) {
456
463
  setProp(elt, '$visited', true);
457
464
  forEachMemberRecursively(elt, markToContainer,
458
- [], true, { elementsOnly: true });
465
+ [], true, { elementsOnly: true });
459
466
  delete elt.$visited;
460
467
  }
461
468
  }
@@ -470,9 +477,8 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
470
477
  // containment data structures must be manually added here.
471
478
  // As a param entity is a potential proxy candidate, this split must be performed on
472
479
  // all definitions
473
- function initParameterizedEntityOrView(entityCsn, entityName) {
474
-
475
- if(!edmUtils.isParameterizedEntity(entityCsn))
480
+ function initParameterizedEntityOrView( entityCsn, entityName ) {
481
+ if (!edmUtils.isParameterizedEntity(entityCsn))
476
482
  return;
477
483
 
478
484
  // Naming rules for aggregated views with parameters
@@ -487,10 +493,10 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
487
493
  // Backlink Navigation Property "Parameters" to <ViewName>Parameters
488
494
 
489
495
  // this code can be extended for aggregated views
490
- const typeEntityName = entityName + 'Type';
491
- const typeEntitySetName = entityName + 'Set';
496
+ const typeEntityName = `${entityName}Type`;
497
+ const typeEntitySetName = `${entityName}Set`;
492
498
  const typeToParameterAssocName = 'Parameters';
493
- let hasBacklink = true;
499
+ const hasBacklink = true;
494
500
 
495
501
 
496
502
  // create the Parameter Definition
@@ -498,8 +504,9 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
498
504
  setProp(parameterCsn, '_origin', entityCsn);
499
505
  // create the Type Definition
500
506
  // modify the original parameter entity with backlink and new name
501
- if(csn.definitions[typeEntityName])
502
- error('odata-definition-exists', [ 'definitions', entityName ], { '#': 'std', name: typeEntityName });
507
+ if (csn.definitions[typeEntityName]) {
508
+ error('odata-definition-exists', [ 'definitions', entityName ], { '#': 'std', name: typeEntityName });
509
+ }
503
510
  else {
504
511
  csn.definitions[typeEntityName] = entityCsn;
505
512
  reqDefs.definitions[typeEntityName] = entityCsn;
@@ -509,36 +516,38 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
509
516
  }
510
517
  setProp(entityCsn, '$entitySetName', typeEntitySetName);
511
518
  // add backlink association
512
- if(hasBacklink) {
519
+ if (hasBacklink) {
513
520
  entityCsn.elements[typeToParameterAssocName] = {
514
521
  name: typeToParameterAssocName,
515
522
  target: parameterCsn.name,
516
523
  type: 'cds.Association',
517
- on: [ { ref: [ 'Parameters', 'Set' ] }, '=', { ref: [ '$self' ] } ]
524
+ on: [ { ref: [ 'Parameters', 'Set' ] }, '=', { ref: [ '$self' ] } ],
518
525
  };
519
526
  setProp(entityCsn.elements[typeToParameterAssocName], '_selfReferences', []);
520
527
  setProp(entityCsn.elements[typeToParameterAssocName], '_target', parameterCsn);
521
528
  setProp(entityCsn.elements[typeToParameterAssocName], '$path',
522
- [ 'definitions', typeEntityName, 'elements', typeToParameterAssocName ] );
529
+ [ 'definitions', typeEntityName, 'elements', typeToParameterAssocName ] );
523
530
 
524
531
  // rewrite $path
525
- if(entityCsn.$path)
532
+ if (entityCsn.$path)
526
533
  entityCsn.$path[1] = typeEntityName;
527
534
  forEachMemberRecursively(entityCsn, (member) => {
528
- if(member.$path)
535
+ if (member.$path)
529
536
  member.$path[1] = typeEntityName;
530
537
  });
531
538
  }
532
539
 
533
- /*
540
+ /*
534
541
  <EntitySet Name="ZRHA_TEST_CDSSet" EntityType="ZRHA_TEST_CDS_CDS.ZRHA_TEST_CDSType" sap:creatable="false" sap:updatable="false"
535
542
  sap:deletable="false" sap:addressable="false" sap:content-version="1"/>
536
543
  */
537
544
  edmUtils.assignProp(entityCsn, '_SetAttributes',
538
- {'@sap.creatable': false, '@sap.updatable': false, '@sap.deletable': false, '@sap.addressable': false });
545
+ {
546
+ '@sap.creatable': false, '@sap.updatable': false, '@sap.deletable': false, '@sap.addressable': false,
547
+ });
539
548
 
540
549
  // redirect inbound associations/compositions to the parameter entity
541
- Object.keys(entityCsn.$sources || {}).forEach(n => {
550
+ Object.keys(entityCsn.$sources || {}).forEach((n) => {
542
551
  // preserve the original target for constraint calculation
543
552
  setProp(entityCsn.$sources[n], '_originalTarget', entityCsn.$sources[n]._target);
544
553
  entityCsn.$sources[n]._target = parameterCsn;
@@ -546,8 +555,8 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
546
555
  });
547
556
  }
548
557
 
549
- function createParameterEntity(entityCsn, entityName, isProxy) {
550
- const parameterEntityName = entityName + 'Parameters';
558
+ function createParameterEntity( entityCsn, entityName, isProxy ) {
559
+ const parameterEntityName = `${entityName}Parameters`;
551
560
  const parameterToTypeAssocName = 'Set';
552
561
 
553
562
  // Construct the parameter entity
@@ -557,11 +566,11 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
557
566
  elements: Object.create(null),
558
567
  '@sap.semantics': 'parameters',
559
568
  };
560
- if(!isProxy)
569
+ if (!isProxy)
561
570
  setProp(parameterCsn, '$entitySetName', entityName);
562
- if(entityCsn.$location){
571
+ if (entityCsn.$location)
563
572
  edmUtils.assignProp(parameterCsn, '$location', entityCsn.$location);
564
- }
573
+
565
574
 
566
575
  /*
567
576
  <EntitySet Name="ZRHA_TEST_CDS" EntityType="ZRHA_TEST_CDS_CDS.ZRHA_TEST_CDSParameters" sap:creatable="false" sap:updatable="false"
@@ -569,13 +578,15 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
569
578
  */
570
579
 
571
580
  edmUtils.assignProp(parameterCsn, '_SetAttributes',
572
- {'@sap.creatable': false, '@sap.updatable': false, '@sap.deletable': false, '@sap.pageable': false });
581
+ {
582
+ '@sap.creatable': false, '@sap.updatable': false, '@sap.deletable': false, '@sap.pageable': false,
583
+ });
573
584
 
574
585
  setProp(parameterCsn, '$isParamEntity', true);
575
586
  setProp(parameterCsn, '$mySchemaName', entityCsn.$mySchemaName);
576
587
 
577
- forEachGeneric(entityCsn, 'params', (p,n) => {
578
- let elt = cloneCsnNonDict(p, options);
588
+ forEachGeneric(entityCsn, 'params', (p, n) => {
589
+ const elt = cloneCsnNonDict(p, options);
579
590
  elt.name = n;
580
591
  delete elt.kind;
581
592
  setProp(elt, '$path', [ 'definitions', parameterEntityName, 'elements', n ]);
@@ -587,7 +598,7 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
587
598
  Only "mandatory" is allowed because in RAP all parameters are NOT NULL
588
599
  and so they are in CAP (all view parameters become primary keys which are not null).
589
600
  */
590
- if(options.isV2())
601
+ if (options.isV2())
591
602
  edmUtils.assignAnnotation(elt, '@sap.parameter', 'mandatory');
592
603
  else
593
604
  edmUtils.assignAnnotation(elt, '@Common.FieldControl', { '#': 'Mandatory' });
@@ -596,50 +607,52 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
596
607
  linkAssociationTarget(parameterCsn);
597
608
  initContainments(parameterCsn);
598
609
  // add assoc to result set, FIXME: is the cardinality correct?
599
- if(!isProxy) {
610
+ if (!isProxy) {
600
611
  parameterCsn.elements[parameterToTypeAssocName] = {
601
612
  '@odata.contained': true,
602
613
  name: parameterToTypeAssocName,
603
614
  target: entityCsn.name,
604
615
  type: 'cds.Association',
605
- cardinality: { src: 1, min: 0, max: '*' }
616
+ cardinality: { src: 1, min: 0, max: '*' },
606
617
  };
607
618
  setProp(parameterCsn.elements[parameterToTypeAssocName], '_target', entityCsn);
608
619
  setProp(parameterCsn.elements[parameterToTypeAssocName], '$path',
609
- [ 'definitions', parameterEntityName, 'elements', parameterToTypeAssocName ] );
620
+ [ 'definitions', parameterEntityName, 'elements', parameterToTypeAssocName ] );
610
621
  }
611
622
 
612
- [ '@odata.singleton', '@odata.singleton.nullable' ].forEach(a => {
613
- if(entityCsn[a] != null)
623
+ [ '@odata.singleton', '@odata.singleton.nullable' ].forEach((a) => {
624
+ if (entityCsn[a] != null)
614
625
  parameterCsn[a] = entityCsn[a];
615
626
  delete entityCsn[a];
616
627
  });
617
628
 
618
629
  // initialize containment
619
630
  // propagate containment information, if containment is recursive, use parameterCsn.name as $containerNames
620
- if(entityCsn.$containerNames) {
621
- if(!parameterCsn.$containerNames)
631
+ if (entityCsn.$containerNames) {
632
+ if (!parameterCsn.$containerNames)
622
633
  setProp(parameterCsn, '$containerNames', []);
623
- for(const c of entityCsn.$containerNames) {
634
+ for (const c of entityCsn.$containerNames)
624
635
  parameterCsn.$containerNames.push((c === entityCsn.name) ? parameterCsn.name : c);
625
- }
626
636
  }
627
637
  entityCsn.$containerNames = [ parameterCsn ];
628
638
 
629
- if(!parameterCsn.$containeeAssociations)
639
+ if (!parameterCsn.$containeeAssociations)
630
640
  setProp(parameterCsn, '$containeeAssociations', [ ]);
631
641
  parameterCsn.$containeeAssociations.push(
632
- { assoc: parameterCsn.elements[parameterToTypeAssocName],
633
- path: [ parameterToTypeAssocName ]
634
- });
642
+ {
643
+ assoc: parameterCsn.elements[parameterToTypeAssocName],
644
+ path: [ parameterToTypeAssocName ],
645
+ }
646
+ );
635
647
 
636
648
  // rewrite $path
637
649
  setProp(parameterCsn, '$path', [ 'definitions', parameterEntityName ]);
638
650
 
639
651
  // proxies are registered in model separately
640
- if(!isProxy) {
641
- if(csn.definitions[parameterCsn.name])
652
+ if (!isProxy) {
653
+ if (csn.definitions[parameterCsn.name]) {
642
654
  error('odata-definition-exists', [ 'definitions', entityName ], { '#': 'std', name: parameterCsn.name });
655
+ }
643
656
  else {
644
657
  csn.definitions[parameterCsn.name] = parameterCsn;
645
658
  reqDefs.definitions[parameterCsn.name] = parameterCsn;
@@ -648,13 +661,13 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
648
661
  return parameterCsn;
649
662
  }
650
663
 
651
- function initElement(element, name, struct) {
652
- setProp(element, 'name', name)
664
+ function initElement( element, name, struct ) {
665
+ setProp(element, 'name', name);
653
666
  setProp(element, '_parent', struct);
654
667
  }
655
668
 
656
669
  // convert $path to path starting at main artifact
657
- function $path2path(p) {
670
+ function $path2path( p ) {
658
671
  const path = [];
659
672
  /** @type {any} */
660
673
  let env = csn;
@@ -663,9 +676,13 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
663
676
  env = env[ps];
664
677
  if (env && env.constructor === Object) {
665
678
  path.push(ps);
666
- if(env.items)
679
+ // jump over many items but not if this is an element
680
+ if (env.items) {
667
681
  env = env.items;
668
- if(env.type && !isBuiltinType(env.type) && !env.elements)
682
+ if (p[i + 1] === 'items')
683
+ i++;
684
+ }
685
+ if (env.type && !isBuiltinType(env.type) && !env.elements)
669
686
  env = csn.definitions[env.type];
670
687
  }
671
688
  }
@@ -673,45 +690,49 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
673
690
  }
674
691
 
675
692
  // Initialize a structured artifact
676
- function initStructure(def) {
677
-
693
+ function initStructure( def ) {
678
694
  // Don't operate on any structured types other than type and entity
679
695
  // such as events and aspects
680
- if(!edmUtils.isStructuredArtifact(def))
696
+ if (!edmUtils.isStructuredArtifact(def))
681
697
  return;
682
698
 
683
699
  let keys = Object.create(null);
684
- let validFrom = [], validKey = [];
700
+ const validFrom = []; const
701
+ validKey = [];
685
702
 
686
703
  // Iterate all struct elements
687
704
  forEachMemberRecursively(def.items || def, (element, elementName, prop, _path, construct) => {
688
- if(prop !== 'elements')
705
+ if (prop !== 'elements')
689
706
  return;
690
707
 
691
708
  initElement(element, elementName, construct);
692
709
 
693
710
  // collect temporal information
694
- if(element['@cds.valid.key']) {
711
+ if (element['@cds.valid.key'])
695
712
  validKey.push(element);
696
- }
697
- if(element['@cds.valid.from']) {
713
+
714
+ if (element['@cds.valid.from'])
698
715
  validFrom.push(element);
699
- }
700
- //forward annotations from managed association element to its foreign keys
716
+
717
+ // forward annotations from managed association element to its foreign keys
718
+ // TODO: Try to eliminate this code by rearranging
719
+ // forOdata::addCommonValueListviaAssociation(member, memberName)
720
+ // such that the VL annotations are distributed to the associations *before*
721
+ // FK creation.
722
+ // The FK creation already propagates the annotations from the association
701
723
  const elements = construct.items && construct.items.elements || construct.elements;
702
724
  const fk = elements[element['@odata.foreignKey4']];
703
- for(const attrName in fk) {
725
+ for (const attrName in fk) {
704
726
  const attr = fk[attrName];
705
- if(attrName[0] === '@') {
706
- element[attrName] = attr;
707
- }
727
+ if (attrName[0] === '@')
728
+ edmUtils.assignAnnotation(element, attrName, attr);
708
729
  }
709
730
  // and eventually remove some afterwards
710
- if(options.isV2())
731
+ if (options.isV2())
711
732
  edmAnnoPreproc.setSAPSpecificV2AnnotationsToAssociation(element);
712
733
 
713
734
  // initialize an association
714
- if(element.target) {
735
+ if (element.target) {
715
736
  // in case this is a forward assoc, store the backlink partners here, _selfReferences.length > 1 => error
716
737
  edmUtils.assignProp(element, '_selfReferences', []);
717
738
  edmUtils.assignProp(element._target, '$proxies', []);
@@ -720,50 +741,48 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
720
741
  }
721
742
 
722
743
  // Collect keys
723
- if (element.key) {
744
+ if (element.key)
724
745
  keys[elementName] = element;
725
- }
746
+
726
747
  edmAnnoPreproc.applyAppSpecificLateCsnTransformationOnElement(options, element, def, error);
727
748
  }, [], true, { elementsOnly: true });
728
749
 
729
- if(!isDeprecatedEnabled(options, '_v1KeysForTemporal')) {
750
+ if (!isDeprecatedEnabled(options, '_v1KeysForTemporal')) {
730
751
  // if artifact has a cds.valid.key mention it as @Core.AlternateKey
731
- if(validKey.length) {
732
- let altKeys = [{ Key: [] }];
752
+ if (validKey.length) {
753
+ const altKeys = [ { Key: [] } ];
733
754
  validKey.forEach(vk => altKeys[0].Key.push( { Name: vk.name, Alias: vk.name } ) );
734
755
  edmUtils.assignAnnotation(def, '@Core.AlternateKeys', altKeys);
735
756
  }
736
757
  }
737
- else {
758
+ else if (validKey.length) {
738
759
  // if artifact has a cds.valid.key make this the only primary key and
739
760
  // add all @cds.valid.from + original primary keys as alternate keys
740
761
  // @Core.AlternateKeys: [{ Key: [ { Name: 'slID', Alias: 'slID' }, { Name: 'validFrom', Alias: 'validFrom'} ] }]
741
- if(validKey.length) {
742
- let altKeys = [{ Key: [] }];
743
- Object.entries(([kn, k]) => {
744
- altKeys[0].Key.push( { Name: kn, Alias: kn } );
745
- delete k.key;
746
- });
747
- validFrom.forEach(e => {
748
- altKeys[0].Key.push( { Name: e.name, Alias: e.name } );
749
- });
750
- edmUtils.assignAnnotation(def, '@Core.AlternateKeys', altKeys);
751
- keys = Object.create(null);
752
- validKey.forEach(e => {
753
- e.key = true;
754
- keys[e.name] = e;
755
- });
756
- }
757
- else {
758
- validFrom.forEach(e => {
759
- e.key = true;
760
- keys[e.name] = e;
761
- });
762
- }
762
+ const altKeys = [ { Key: [] } ];
763
+ Object.entries(([ kn, k ]) => {
764
+ altKeys[0].Key.push( { Name: kn, Alias: kn } );
765
+ delete k.key;
766
+ });
767
+ validFrom.forEach((e) => {
768
+ altKeys[0].Key.push( { Name: e.name, Alias: e.name } );
769
+ });
770
+ edmUtils.assignAnnotation(def, '@Core.AlternateKeys', altKeys);
771
+ keys = Object.create(null);
772
+ validKey.forEach((e) => {
773
+ e.key = true;
774
+ keys[e.name] = e;
775
+ });
776
+ }
777
+ else {
778
+ validFrom.forEach((e) => {
779
+ e.key = true;
780
+ keys[e.name] = e;
781
+ });
763
782
  }
764
783
 
765
784
  // prepare the structure itself
766
- if(def.kind === 'entity') {
785
+ if (def.kind === 'entity') {
767
786
  edmUtils.assignProp(def, '_SetAttributes', Object.create(null));
768
787
  edmUtils.assignProp(def, '$keys', keys);
769
788
  edmAnnoPreproc.applyAppSpecificLateCsnTransformationOnStructure(options, def, error);
@@ -772,17 +791,19 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
772
791
  }
773
792
 
774
793
  // Prepare the associations for the subsequent steps
775
- function initConstraints(def) {
776
- if(!edmUtils.isStructuredArtifact(def))
794
+ function initConstraints( def ) {
795
+ if (!edmUtils.isStructuredArtifact(def))
777
796
  return;
778
797
 
779
798
  forEachMemberRecursively(def.items || def, initConstraintsOnAssoc, [], true, { elementsOnly: true });
780
799
  }
781
- function initConstraintsOnAssoc(element) {
800
+ function initConstraintsOnAssoc( element ) {
782
801
  if (element.target && !element._constraints) {
783
- // setup the constraints object
784
- setProp(element, '_constraints', { constraints: Object.create(null), selfs: [], _origins: [], termCount: 0 });
785
- // and crack the ON condition
802
+ // setup the constraints object
803
+ setProp(element, '_constraints', {
804
+ constraints: Object.create(null), selfs: [], _origins: [], termCount: 0,
805
+ });
806
+ // and crack the ON condition
786
807
  edmUtils.resolveOnConditionAndPrepareConstraints(csn, element, messageFunctions);
787
808
  }
788
809
  }
@@ -799,53 +820,52 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
799
820
  active, assign @cds.api.ignore or @odata.navigable: false
800
821
  4) All of this can be revoked with options.renderForeignKeys.
801
822
  */
802
- function ignoreProperties(struct) {
803
- if(!edmUtils.isStructuredArtifact(struct))
823
+ function ignoreProperties( struct ) {
824
+ if (!edmUtils.isStructuredArtifact(struct))
804
825
  return;
805
826
 
806
827
  forEachMemberRecursively(struct.items || struct, (element) => {
807
- if(!element.target) {
808
- if(element['@odata.foreignKey4']) {
828
+ if (!element.target) {
829
+ if (element['@odata.foreignKey4']) {
809
830
  let isContainerAssoc = false;
810
- let elements = (struct.items || struct).elements;
811
- let assoc = undefined;
812
- const paths = element['@odata.foreignKey4'].split('.')
813
- for(let p of paths) {
831
+ let { elements } = struct.items || struct;
832
+ let assoc;
833
+ const paths = element['@odata.foreignKey4'].split('.');
834
+ for (const p of paths) {
814
835
  assoc = elements[p];
815
- if(assoc) // could be that the @odata.foreignKey4 was propagated...
836
+ if (assoc) // could be that the @odata.foreignKey4 was propagated...
816
837
  elements = assoc.elements;
817
838
  }
818
839
 
819
- if(assoc)
840
+ if (assoc)
820
841
  isContainerAssoc = !!(assoc._isToContainer && assoc._selfReferences.length || assoc['@odata.contained']);
821
842
  /*
822
843
  If this foreign key is NOT a container fk, let isEdmPropertyRendered() decide
823
844
  Else, if fk is container fk, omit it if it wasn't requested in structured mode
824
845
  */
825
- if((!isContainerAssoc && !isEdmPropertyRendered(element, options)) ||
846
+ if ((!isContainerAssoc && !isEdmPropertyRendered(element, options)) ||
826
847
  (isContainerAssoc && !options.renderForeignKeys))
827
848
  edmUtils.assignAnnotation(element, '@cds.api.ignore', true);
828
849
  // Only in containment:
829
850
  // If this element is a foreign key and if it is rendered, remove it from the key ref vector (if available)
830
- else if(options.odataContainment &&
851
+ else if (options.odataContainment &&
831
852
  isContainerAssoc &&
832
853
  options.renderForeignKeys &&
833
- struct.$keys) {
854
+ struct.$keys)
834
855
  delete struct.$keys[element.name];
835
- }
836
856
  }
837
857
  // Only in containment:
838
858
  // Ignore this (foreign key) element if renderForeignKeys is false
839
- if(options.odataContainment && element['@odata.containment.ignore']) {
840
- if(!options.renderForeignKeys)
859
+ if (options.odataContainment && element['@odata.containment.ignore']) {
860
+ if (!options.renderForeignKeys)
841
861
  edmUtils.assignAnnotation(element, '@cds.api.ignore', true);
842
- else if(struct.$keys)
862
+ else if (struct.$keys)
843
863
  // If foreign keys shall be rendered, remove it from key ref vector (if available)
844
864
  delete struct.$keys[element.name];
845
865
  }
846
866
  }
847
- // it's an association
848
- else if(element['@odata.containment.ignore'] && options.odataContainment && !options.renderForeignKeys) {
867
+ // it's an association
868
+ else if (element['@odata.containment.ignore'] && options.odataContainment && !options.renderForeignKeys) {
849
869
  // if this is an explicitly containment ignore tagged association,
850
870
  // ignore it if option odataContainment is true and no foreign keys should be rendered
851
871
  edmUtils.assignAnnotation(element, '@odata.navigable', false);
@@ -858,43 +878,44 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
858
878
  It may be that now a number of properties are not rendered and cannot act as constraints (see isConstraintCandidate())
859
879
  in edmUtils
860
880
  */
861
- function finalizeConstraints(def) {
862
- if(!edmUtils.isStructuredArtifact(def))
881
+ function finalizeConstraints( def ) {
882
+ if (!edmUtils.isStructuredArtifact(def))
863
883
  return;
864
884
 
865
885
  forEachMemberRecursively(def.items || def, finalizeConstraintsOnAssoc, [], true, { elementsOnly: true });
866
886
  }
867
- function finalizeConstraintsOnAssoc(element) {
887
+ function finalizeConstraintsOnAssoc( element ) {
868
888
  if (element.target && element._constraints) {
869
889
  edmUtils.finalizeReferentialConstraints(csn, element, options, info);
870
890
 
871
- if(element._constraints?._partnerCsn) {
891
+ if (element._constraints?._partnerCsn) {
872
892
  // if this is a partnership and this assoc has a set target cardinality, assign it as source cardinality to the partner
873
- if(element._constraints._partnerCsn.cardinality) {
893
+ if (element._constraints._partnerCsn.cardinality) {
874
894
  // if the forward association has set a src cardinality and it deviates from the backlink target cardinality raise a warning
875
895
  // in V2 only, in V4 the source cardinality is rendered implicitly at the Type property
876
- if(element._constraints._partnerCsn.cardinality.src) {
896
+ if (element._constraints._partnerCsn.cardinality.src) {
897
+ // eslint-disable-next-line eqeqeq
877
898
  const srcMult = (element._constraints._partnerCsn.cardinality.src == 1) ? '0..1' : '*';
878
- const newMult =
879
- (element.cardinality?.min == 1 && element.cardinality?.max == 1)
899
+ const newMult
900
+ = (element.cardinality?.min == 1 && element.cardinality?.max == 1) // eslint-disable-line eqeqeq
901
+
880
902
  ? '1'
881
903
  : (element.cardinality?.max === '*' || element.cardinality?.max > 1)
882
904
  ? '*'
883
905
  : '0..1';
884
- if(srcMult !== newMult) {
906
+ if (srcMult !== newMult)
885
907
  warning(null, element.$path, `Explicit source cardinality "${srcMult}" of "${element._constraints._partnerCsn._parent.name}/${element._constraints._partnerCsn.name}" conflicts with target cardinality "${newMult}"`);
886
- }
887
908
  }
888
909
  else {
889
910
  // .. but only if the original assoc hasn't set src yet
890
911
  element._constraints._partnerCsn.cardinality.src = element.cardinality?.max ? element.cardinality.max : 1;
891
- if(element.cardinality?.min !== undefined && element._constraints._partnerCsn.cardinality?.srcmin === undefined)
912
+ if (element.cardinality?.min !== undefined && element._constraints._partnerCsn.cardinality?.srcmin === undefined)
892
913
  element._constraints._partnerCsn.cardinality.srcmin = element.cardinality.min;
893
914
  }
894
915
  }
895
916
  else {
896
917
  element._constraints._partnerCsn.cardinality = { src: element.cardinality?.max ? element.cardinality.max : 1 };
897
- if(element.cardinality?.min !== undefined)
918
+ if (element.cardinality?.min !== undefined)
898
919
  element._constraints._partnerCsn.cardinality.srcmin = element.cardinality.min;
899
920
  }
900
921
  }
@@ -907,20 +928,20 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
907
928
  sub artifacts exposed by the initial type exposure
908
929
  */
909
930
  function convertExposedTypesOfOtherServicesIntoCrossReferences() {
910
- if(options.odataXServiceRefs && options.isV4()) {
911
- serviceRootNames.forEach(srn => {
912
- schemaNames.forEach(fqSchemaName => {
913
- if(fqSchemaName.startsWith(srn + '.')) {
914
- const targetSchemaName = fqSchemaName.replace(srn + '.', '');
915
- if(serviceRootNames.includes(targetSchemaName)) {
931
+ if (options.odataXServiceRefs && options.isV4()) {
932
+ serviceRootNames.forEach((srn) => {
933
+ schemaNames.forEach((fqSchemaName) => {
934
+ if (fqSchemaName.startsWith(`${srn}.`)) {
935
+ const targetSchemaName = fqSchemaName.replace(`${srn}.`, '');
936
+ if (serviceRootNames.includes(targetSchemaName)) {
916
937
  // remove all definitions starting with < fqSchemaName >. and add a schema reference
917
- Object.keys(csn.definitions).forEach(dn => {
918
- if(dn.startsWith(fqSchemaName)) {
938
+ Object.keys(csn.definitions).forEach((dn) => {
939
+ if (dn.startsWith(fqSchemaName)) {
919
940
  delete csn.definitions[dn];
920
941
  delete reqDefs.definitions[dn];
921
942
  }
922
943
  });
923
- if(!schemas[fqSchemaName])
944
+ if (!schemas[fqSchemaName])
924
945
  schemaNames.push(fqSchemaName);
925
946
  schemas[fqSchemaName] = edmUtils.createSchemaRef(serviceRoots, targetSchemaName);
926
947
  }
@@ -928,7 +949,7 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
928
949
  });
929
950
  });
930
951
  }
931
- schemaNames.sort((a,b)=>b.length-a.length);
952
+ schemaNames.sort((a, b) => b.length - a.length);
932
953
  }
933
954
 
934
955
  /*
@@ -953,8 +974,8 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
953
974
  or indirectly (via structured elements), these dependent entity types are (recursively) exposed
954
975
  (or referenced) as well to keep the navigation graph in tact.
955
976
  */
956
- function exposeTargetsAsProxiesOrSchemaRefs(struct) {
957
- if(struct.kind === 'context' || struct.kind === 'service' || struct.$proxy)
977
+ function exposeTargetsAsProxiesOrSchemaRefs( struct ) {
978
+ if (struct.kind === 'context' || struct.kind === 'service' || struct.$proxy)
958
979
  return;
959
980
 
960
981
  // globalSchemaPrefix is the prefix for all proxy registrations and must not change
@@ -962,9 +983,9 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
962
983
  // definitions which are directly below the root service ($mySchemaName is the root)
963
984
  const globalSchemaPrefix = whatsMyServiceRootName(struct.$mySchemaName);
964
985
  // if this artifact is a service member check its associations
965
- if(globalSchemaPrefix) {
966
- forEachGeneric(struct.items || struct, 'elements', element => {
967
- if(!edmUtils.isNavigable(element))
986
+ if (globalSchemaPrefix) {
987
+ forEachGeneric(struct.items || struct, 'elements', (element) => {
988
+ if (!edmUtils.isNavigable(element))
968
989
  return;
969
990
  /*
970
991
  * Consider everything @cds.autoexpose: falsy to be a proxy candidate for now
@@ -999,36 +1020,37 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
999
1020
  // 1 | 1 | Cross service references and proxies are generated
1000
1021
 
1001
1022
  const targetSchemaName = element._target.$mySchemaName;
1002
- if(isProxyRequired(element)) {
1003
- if(options.isV4() && (options.odataProxies || options.odataXServiceRefs)) {
1023
+ if (isProxyRequired(element)) {
1024
+ if (options.isV4() && (options.odataProxies || options.odataXServiceRefs)) {
1004
1025
  // must be a managed association with keys OR an unambiguous backlink to become a proxy
1005
- let assocOK = element.keys ||
1026
+ const assocOK = element.keys ||
1006
1027
  (element.on && element._constraints.selfs.length === 1 && element._constraints.termCount === 1);
1007
1028
  // reuse proxy if available
1008
1029
  let proxy = getProxyForTargetOf(element);
1009
- if(!proxy) {
1010
- if(targetSchemaName && options.odataXServiceRefs) {
1030
+ if (!proxy) {
1031
+ if (targetSchemaName && options.odataXServiceRefs)
1011
1032
  proxy = createSchemaRefFor(targetSchemaName);
1012
- }
1033
+
1013
1034
  // create a proxy for a 'good' association only
1014
- else if(options.odataProxies && assocOK) {
1035
+ else if (options.odataProxies && assocOK)
1015
1036
  proxy = createProxyFor(element, targetSchemaName);
1016
- }
1037
+
1017
1038
  proxy = registerProxy(proxy, element);
1018
- } else if(!assocOK) {
1039
+ }
1040
+ else if (!assocOK) {
1019
1041
  // if there is already a proxy (generated by a 'good' association)
1020
1042
  // and this association is not a good one, don't expose this association.
1021
1043
  muteNavProp(element, 'oncond');
1022
1044
  return;
1023
1045
  }
1024
- if(proxy) {
1046
+ if (proxy) {
1025
1047
  // if a proxy was either already created or could be created and
1026
1048
  // if it's a 'real' proxy, link the _target to it and remove constraints
1027
1049
  // otherwise proxy is a schema reference, then do nothing
1028
1050
  setProp(element, '$noPartner', true);
1029
1051
  element._constraints.constraints = Object.create(null);
1030
- if(proxy.kind === 'entity') {
1031
- if(!proxy.$isParamEntity)
1052
+ if (proxy.kind === 'entity') {
1053
+ if (!proxy.$isParamEntity)
1032
1054
  populateProxyElements(element, proxy, getForeignKeyDefinitions(element));
1033
1055
  element._target = proxy;
1034
1056
  }
@@ -1050,22 +1072,22 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1050
1072
  });
1051
1073
  }
1052
1074
 
1053
- function muteNavProp(elt, msg='std') {
1075
+ function muteNavProp( elt, msg = 'std' ) {
1054
1076
  edmUtils.assignAnnotation(elt, '@odata.navigable', false);
1055
- warning('odata-navigation', ['definitions', struct.name, 'elements', elt.name],
1056
- { target: elt._target.name, service: globalSchemaPrefix, '#': msg });
1077
+ warning('odata-navigation', [ 'definitions', struct.name, 'elements', elt.name ],
1078
+ { target: elt._target.name, service: globalSchemaPrefix, '#': msg });
1057
1079
  }
1058
1080
 
1059
- function createSchemaRefFor(targetSchemaName) {
1060
- let ref = csn.definitions[globalSchemaPrefix + '.' + targetSchemaName];
1061
- if(!ref) {
1081
+ function createSchemaRefFor( targetSchemaName ) {
1082
+ let ref = csn.definitions[`${globalSchemaPrefix}.${targetSchemaName}`];
1083
+ if (!ref)
1062
1084
  ref = edmUtils.createSchemaRef(serviceRoots, targetSchemaName);
1063
- }
1085
+
1064
1086
 
1065
1087
  return ref;
1066
1088
  }
1067
1089
 
1068
- function createProxyFor(assoc, targetSchemaName) {
1090
+ function createProxyFor( assoc, targetSchemaName ) {
1069
1091
  // If target is outside any service expose it in service of source entity
1070
1092
  // The proxySchemaName is not prepended with the service schema name to allow to share the proxy
1071
1093
  // if it is required in multiple services. The service schema name is prepended upon registration
@@ -1076,13 +1098,13 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1076
1098
 
1077
1099
  // 1) construct the proxy definition
1078
1100
  // proxyDefinitionName: strip the serviceName and replace '.' with '_'
1079
- let defName =
1080
- `${assoc._target.name.replace(proxySchemaName + '.', '').replace(/\./g, '_')}`;
1101
+ const defName
1102
+ = `${assoc._target.name.replace(`${proxySchemaName}.`, '').replace(/\./g, '_')}`;
1081
1103
 
1082
1104
  // fullName: Prepend serviceName and if in same service add '_proxy'
1083
1105
  const proxy = isParamProxy
1084
- ? createParameterEntity(assoc._target, proxySchemaName + '.' + defName, true)
1085
- : { name: proxySchemaName + '.' + defName, kind: 'entity', elements: Object.create(null) };
1106
+ ? createParameterEntity(assoc._target, `${proxySchemaName}.${defName}`, true)
1107
+ : { name: `${proxySchemaName}.${defName}`, kind: 'entity', elements: Object.create(null) };
1086
1108
 
1087
1109
  // Final proxyShortName for all further processing
1088
1110
  const proxyShortName = defName + (isParamProxy ? 'Parameters' : '');
@@ -1094,77 +1116,78 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1094
1116
  setProp(proxy, '$hasEntitySet', false);
1095
1117
  setProp(proxy, '$exposedTypes', Object.create(null));
1096
1118
  // copy all annotations of the target to the proxy
1097
- Object.entries(assoc._target).forEach(([k, v]) => {
1098
- if(k[0] === '@' && k !== '@open')
1119
+ Object.entries(assoc._target).forEach(([ k, v ]) => {
1120
+ if (k[0] === '@' && k !== '@open')
1099
1121
  proxy[k] = v;
1100
1122
  });
1101
1123
 
1102
1124
  // 2) create the elements and $keys
1103
- if(isParamProxy) {
1125
+ if (isParamProxy) {
1104
1126
  // Reset param proxy elements to expose element tree
1105
- const elements = proxy.elements;
1127
+ const { elements } = proxy;
1106
1128
  proxy.elements = Object.create(null);
1107
1129
  populateProxyElements(assoc, proxy, elements);
1108
1130
  }
1109
- else
1131
+ else {
1110
1132
  populateProxyElements(assoc, proxy, assoc._target.$keys);
1133
+ }
1111
1134
  return proxy;
1112
-
1113
1135
  }
1114
1136
 
1115
1137
  // Return top level foreign key element definitions. The full top level
1116
1138
  // element is exposed instead of merging partial trees into the exposed type
1117
1139
  // def structure.
1118
- function getForeignKeyDefinitions(e) {
1140
+ function getForeignKeyDefinitions( e ) {
1119
1141
  return e.keys ? e.keys.map(fk => e._target.elements[fk.ref[0]]) : [];
1120
1142
  }
1121
1143
 
1122
1144
  // copy over the primary keys of the target and trigger the type exposure
1123
1145
  // if the element already exists we assume it was fully exposed
1124
- function populateProxyElements(assoc, proxy, elements) {
1125
- Object.values(elements).forEach(e => {
1146
+ function populateProxyElements( assoc, proxy, elements ) {
1147
+ Object.values(elements).forEach((e) => {
1126
1148
  if (isEdmPropertyRendered(e, options)) {
1127
1149
  let newElt = proxy.elements[e.name];
1128
- if(!newElt) {
1129
- if(csnUtils.isAssocOrComposition(e)) {
1130
- if(!e.on && e.keys) {
1131
- if(options.odataNoTransitiveProxies)
1150
+ if (!newElt) {
1151
+ if (csnUtils.isAssocOrComposition(e)) {
1152
+ if (!e.on && e.keys) {
1153
+ if (options.odataNoTransitiveProxies)
1132
1154
  newElt = convertManagedAssocIntoStruct(e);
1133
1155
  else
1134
1156
  newElt = createProxyOrSchemaRefForManagedAssoc(e);
1135
1157
  }
1136
1158
  else {
1137
- info(null, ['definitions', struct.name, 'elements', assoc.name],
1138
- { name: proxy.nname, target: assoc._target.name },
1139
- 'Unmanaged associations are not supported as primary keys for proxy entity type $(NAME) of unexposed association target $(TARGET)');
1159
+ info(null, [ 'definitions', struct.name, 'elements', assoc.name ],
1160
+ { name: proxy.nname, target: assoc._target.name },
1161
+ 'Unmanaged associations are not supported as primary keys for proxy entity type $(NAME) of unexposed association target $(TARGET)');
1140
1162
  }
1141
1163
  }
1142
1164
  else {
1143
1165
  newElt = Object.create(null);
1144
- Object.keys(e).forEach(prop => newElt[prop] = e[prop])
1166
+ Object.keys(e).forEach((prop) => {
1167
+ newElt[prop] = e[prop];
1168
+ });
1145
1169
  }
1146
- if(newElt) {
1170
+ if (newElt) {
1147
1171
  initElement(newElt, e.name, proxy);
1148
1172
  proxy.elements[newElt.name] = newElt;
1149
1173
 
1150
- if(csnUtils.isStructured(newElt)) {
1174
+ if (csnUtils.isStructured(newElt)) {
1151
1175
  // argument proxySchemaName forces an anonymous type definition for newElt into the
1152
1176
  // proxy schema. If omitted, this exposure defaults to 'root', in case API flavor
1153
1177
  // of the day changes...
1154
- exposeStructTypeForProxyOf(proxy, newElt, proxy.$proxyShortName + '_' + newElt.name,
1155
- proxy.$mySchemaName, newElt.key, !!(newElt.key && newElt.elements));
1178
+ exposeStructTypeForProxyOf(newElt, `${proxy.$proxyShortName}_${newElt.name}`,
1179
+ proxy.$mySchemaName, newElt.key, !!(newElt.key && newElt.elements));
1156
1180
  }
1157
- if(newElt.key)
1181
+ if (newElt.key)
1158
1182
  proxy.$keys[newElt.name] = newElt;
1159
1183
  }
1160
1184
  }
1161
1185
  }
1162
-
1163
1186
  });
1164
1187
  // 3) sort the exposed types so that they appear lexicographically ordered in the EDM
1165
1188
  proxy.$exposedTypes = Object.keys(proxy.$exposedTypes).sort().reduce((dict, tn) => {
1166
1189
  dict[tn] = proxy.$exposedTypes[tn];
1167
- return dict
1190
+ return dict;
1168
1191
  }, Object.create(null));
1169
1192
 
1170
1193
  // If 'node' exists and has a structured type that is not exposed in 'service', (because the type is
@@ -1174,11 +1197,10 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1174
1197
  // isKey: Indicates top level element is key or not
1175
1198
  // forceToNotNull: if top level element is key, recursively set all anonymously exposed elements
1176
1199
  // to notNull until the first named type is exposed.
1177
- function exposeStructTypeForProxyOf(proxy, node, artificialName,
1178
- typeSchemaName=fallBackSchemaName,
1179
- isKey = false, forceToNotNull = false) {
1180
-
1181
- if(node.type && isBuiltinType(node.type))
1200
+ function exposeStructTypeForProxyOf( node, artificialName,
1201
+ typeSchemaName = fallBackSchemaName,
1202
+ isKey = false, forceToNotNull = false ) {
1203
+ if (node.type && isBuiltinType(node.type))
1182
1204
  return;
1183
1205
 
1184
1206
  // Always expose types referred to by a proxy, never reuse an eventually existing type
@@ -1191,43 +1213,46 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1191
1213
  // the type clone must be produced for each service as this type may
1192
1214
  // produce references and/or proxies into multiple services
1193
1215
  // (but only once per service, therefore cache it).
1194
- if(typeDef.$proxyTypes && typeDef.$proxyTypes[globalSchemaPrefix]) {
1195
- // if type has been exposed in a schema use this type
1216
+ if (typeDef.$proxyTypes && typeDef.$proxyTypes[globalSchemaPrefix]) {
1217
+ // if type has been exposed in a schema use this type
1196
1218
  typeClone = typeDef.$proxyTypes[globalSchemaPrefix];
1197
1219
  }
1198
1220
  else {
1199
- // Set the correct name
1221
+ // Set the correct name
1200
1222
  let typeId = artificialName; // the artificialName has no namespace, it's the element
1201
- if(node.type) {
1223
+ if (node.type) {
1202
1224
  // same as for proxies, use schema or namespace, 'root' is last resort
1203
1225
  typeSchemaName = typeDef.$mySchemaName || edmUtils.getSchemaPrefix(node.type);
1204
- typeId = node.type.replace(typeSchemaName + '.', '').replace(/\./g, '_');
1226
+ typeId = node.type.replace(`${typeSchemaName}.`, '').replace(/\./g, '_');
1205
1227
  // strip the service root of that type (if any)
1206
1228
  const myServiceRootName = whatsMyServiceRootName(typeSchemaName);
1207
- if(myServiceRootName)
1208
- typeSchemaName = typeSchemaName.replace(myServiceRootName + '.', '');
1229
+ if (myServiceRootName)
1230
+ typeSchemaName = typeSchemaName.replace(`${myServiceRootName}.`, '');
1209
1231
  }
1210
1232
 
1211
- if(edmUtils.isStructuredArtifact(typeDef)) {
1233
+ if (edmUtils.isStructuredArtifact(typeDef)) {
1212
1234
  // pull forceNotNull to false for named types and non-key nodes
1213
1235
  // only toplevel nodes (elements) can be key
1214
1236
  forceToNotNull = !!(forceToNotNull && isKey && node.elements && !node.type);
1215
1237
 
1216
- typeClone = cloneStructTypeForProxy(typeSchemaName, `${typeSchemaName}.${typeId}`, typeDef);
1217
- if(typeClone) {
1238
+ typeClone = cloneStructTypeForProxy(`${typeSchemaName}.${typeId}`);
1239
+ if (typeClone) {
1218
1240
  // Recurse into elements of 'type' (if any)
1219
- typeClone.elements && Object.entries(typeClone.elements).forEach(([elemName, elem]) => {
1241
+ if (typeClone.elements) {
1242
+ Object.entries(typeClone.elements).forEach(([ elemName, elem ]) => {
1220
1243
  // if this is a foreign key element, we must check whether or not the association
1221
1244
  // has been exposed as proxy. If it has not been exposed, no further structured
1222
1245
  // types must be exposed as 'Proxy_' types.
1223
1246
 
1224
- // TODO: expose types of assoc.keys and don't rely on exposed foreign keys
1225
- if(!elem['@odata.foreignKey4'] ||
1226
- (elem['@odata.foreignKey4'] && !typeClone.elements[elem['@odata.foreignKey4']].$exposed))
1227
- exposeStructTypeForProxyOf(proxy, elem, `${typeId}_${elemName}`,
1228
- typeSchemaName, isKey, forceToNotNull);
1229
- });
1230
- if(!typeDef.$proxyTypes)
1247
+ // TODO: expose types of assoc.keys and don't rely on exposed foreign keys
1248
+ if (!elem['@odata.foreignKey4'] ||
1249
+ (elem['@odata.foreignKey4'] && !typeClone.elements[elem['@odata.foreignKey4']].$exposed)) {
1250
+ exposeStructTypeForProxyOf(elem, `${typeId}_${elemName}`,
1251
+ typeSchemaName, isKey, forceToNotNull);
1252
+ }
1253
+ });
1254
+ }
1255
+ if (!typeDef.$proxyTypes)
1231
1256
  typeDef.$proxyTypes = Object.create(null);
1232
1257
  typeDef.$proxyTypes[globalSchemaPrefix] = typeClone;
1233
1258
  }
@@ -1236,7 +1261,7 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1236
1261
  // FUTURE: expose scalar type definition as well
1237
1262
  }
1238
1263
  }
1239
- if(typeClone) {
1264
+ if (typeClone) {
1240
1265
  // register the type clone at the proxy
1241
1266
  // Reminder: Each proxy receives a full set of type clones, even if the types are shared
1242
1267
  // (no scattered type clone caching). registerProxy() checks if a clone needs to be added to
@@ -1253,12 +1278,12 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1253
1278
  // default, without we must do it to get the primary key tuple calculation correct.
1254
1279
  // Remember: node.type is the service local type name (not prepended by the service name),
1255
1280
  // so it can't be resolved in definitions later on
1256
- if(typeClone.elements)
1281
+ if (typeClone.elements)
1257
1282
  node.elements = typeClone.elements;
1258
1283
  }
1259
1284
  }
1260
1285
 
1261
- function cloneStructTypeForProxy(typeSchemaName, name, typeDef) {
1286
+ function cloneStructTypeForProxy( name ) {
1262
1287
  // Create type with empty elements
1263
1288
  const type = {
1264
1289
  kind: 'type',
@@ -1267,56 +1292,60 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1267
1292
  };
1268
1293
  setProp(type, '$mySchemaName', typeSchemaName);
1269
1294
  setProp(type, '$exposedBy', 'proxyExposure');
1270
- if(typeDef['@open'] !== undefined)
1295
+ if (typeDef['@open'] !== undefined)
1271
1296
  type['@open'] = typeDef['@open'];
1272
1297
 
1273
- typeDef.elements && Object.entries(typeDef.elements).forEach( ([elemName, elem]) => {
1274
- if(!elem.target) {
1275
- type.elements[elemName] = Object.create(null);
1276
- Object.keys(elem).forEach(prop => type.elements[elemName][prop] = elem[prop])
1277
- }
1278
- else if(elem.keys && !elem.on) {
1298
+ if (typeDef.elements) {
1299
+ Object.entries(typeDef.elements).forEach( ([ elemName, elem ]) => {
1300
+ if (!elem.target) {
1301
+ type.elements[elemName] = Object.create(null);
1302
+ Object.keys(elem).forEach((prop) => {
1303
+ type.elements[elemName][prop] = elem[prop];
1304
+ });
1305
+ }
1306
+ else if (elem.keys && !elem.on) {
1279
1307
  // a primary key can never be an unmanaged association
1280
- type.elements[elemName] = createProxyOrSchemaRefForManagedAssoc(elem);
1281
- }
1282
- if(forceToNotNull) {
1283
- const newElt = type.elements[elemName];
1284
- if(newElt.target) {
1285
- if (newElt.cardinality === undefined)
1286
- newElt.cardinality = {};
1287
- newElt.cardinality.min = 1;
1308
+ type.elements[elemName] = createProxyOrSchemaRefForManagedAssoc(elem);
1288
1309
  }
1289
- // if odata-spec-violation-key-null is checking on min>1, this can be an else
1290
- newElt.notNull = true;
1291
- }
1292
- setProp(type.elements[elemName], 'name', elem.name);
1293
- });
1310
+ if (forceToNotNull) {
1311
+ const newElt = type.elements[elemName];
1312
+ if (newElt.target) {
1313
+ if (newElt.cardinality === undefined)
1314
+ newElt.cardinality = {};
1315
+ newElt.cardinality.min = 1;
1316
+ }
1317
+ // if odata-spec-violation-key-null is checking on min>1, this can be an else
1318
+ newElt.notNull = true;
1319
+ }
1320
+ setProp(type.elements[elemName], 'name', elem.name);
1321
+ });
1322
+ }
1294
1323
  return type;
1295
1324
  }
1296
1325
  }
1297
1326
 
1298
1327
  // Convert a managed association into a structured type and
1299
1328
  // eliminate nested foreign key associations
1300
- function convertManagedAssocIntoStruct(e) {
1301
- let newElt = cloneCsnNonDict(e, options);
1329
+ function convertManagedAssocIntoStruct( e ) {
1330
+ const newElt = cloneCsnNonDict(e, options);
1302
1331
  newElt.elements = Object.create(null);
1303
- // remove all unwanted garbage
1332
+ // remove all unwanted garbage
1304
1333
  delete newElt.keys;
1305
1334
  delete newElt.target;
1306
1335
  delete newElt.type;
1307
1336
  // if this association has no keys or if it is a redirected parameterized entity,
1308
1337
  // use the primary keys of the target
1309
- let keys = (!e._target.$isParamEntity && e.keys) ||
1310
- Object.keys(e._target.$keys).map(k => { return { ref: [k] } });
1311
- keys.forEach(k => {
1338
+ const keys = (!e._target.$isParamEntity && e.keys) ||
1339
+ Object.keys(e._target.$keys).map(k => ({ ref: [ k ] }));
1340
+ keys.forEach((k) => {
1312
1341
  let art = e._target || csnUtils.getCsnDef(e.target);
1313
- for(let ps of k.ref) {
1342
+ for (const ps of k.ref)
1314
1343
  art = art.elements[ps];
1315
- }
1344
+
1316
1345
  // art is in the target side, clone it and remove key property
1317
- let cloneArt = cloneCsnNonDict(art, options);
1346
+ const cloneArt = cloneCsnNonDict(art, options);
1318
1347
  setProp(cloneArt, 'name', art.name);
1319
- if(e.key)
1348
+ if (e.key)
1320
1349
  cloneArt.notNull = true;
1321
1350
  delete cloneArt.key;
1322
1351
  newElt.elements[art.name] = cloneArt;
@@ -1330,28 +1359,27 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1330
1359
  // the proxy that is just being created targets back into
1331
1360
  // its own serice
1332
1361
  // 2) or if no proxy for this source schema has been created yet
1333
- function createProxyOrSchemaRefForManagedAssoc(e) {
1334
-
1335
- let proxy = e._target;
1336
- let newElt = cloneCsnNonDict(e, options);
1362
+ function createProxyOrSchemaRefForManagedAssoc( e ) {
1363
+ let newProxy = e._target;
1364
+ const newElt = cloneCsnNonDict(e, options);
1337
1365
 
1338
- if(isProxyRequired(e)) {
1339
- proxy = getProxyForTargetOf(e);
1340
- if(!proxy) {
1366
+ if (isProxyRequired(e)) {
1367
+ newProxy = getProxyForTargetOf(e);
1368
+ if (!newProxy) {
1341
1369
  // option odataXServiceRefs has precedence over odataProxies
1342
- if(e._target.$mySchemaName && options.odataXServiceRefs) {
1343
- proxy = createSchemaRefFor(e._target.$mySchemaName);
1370
+ if (e._target.$mySchemaName && options.odataXServiceRefs) {
1371
+ newProxy = createSchemaRefFor(e._target.$mySchemaName);
1344
1372
  }
1345
- else if(options.odataProxies) {
1346
- proxy = createProxyFor(e, e._target.$mySchemaName);
1347
- if(!e._target.$isParamEntity)
1348
- populateProxyElements(e, proxy, getForeignKeyDefinitions(e));
1373
+ else if (options.odataProxies) {
1374
+ newProxy = createProxyFor(e, e._target.$mySchemaName);
1375
+ if (!e._target.$isParamEntity)
1376
+ populateProxyElements(e, newProxy, getForeignKeyDefinitions(e));
1349
1377
  }
1350
- proxy = registerProxy(proxy, e);
1378
+ newProxy = registerProxy(newProxy, e);
1351
1379
  }
1352
1380
  }
1353
- if(proxy === undefined) {
1354
- proxy = e._target;
1381
+ if (!newProxy) {
1382
+ newProxy = e._target;
1355
1383
  // no proxy: no navigation
1356
1384
  edmUtils.assignAnnotation(newElt, '@odata.navigable', false);
1357
1385
  }
@@ -1367,9 +1395,9 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1367
1395
  finalizeConstraintsOnAssoc(e);
1368
1396
  setProp(newElt, '_constraints', e._constraints);
1369
1397
  setProp(newElt, '_selfReferences', []);
1370
- if(proxy.kind === 'entity') {
1371
- newElt.target = proxy.name;
1372
- setProp(newElt, '_target', proxy);
1398
+ if (newProxy.kind === 'entity') {
1399
+ newElt.target = newProxy.name;
1400
+ setProp(newElt, '_target', newProxy);
1373
1401
  }
1374
1402
  return newElt;
1375
1403
  }
@@ -1395,34 +1423,34 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1395
1423
  the same service name 'S', which implies that they are always exposed
1396
1424
  in the same Edm => no proxy required.
1397
1425
  */
1398
- function isProxyRequired(element) {
1426
+ function isProxyRequired( element ) {
1399
1427
  const targetSchemaName = element._target.$mySchemaName;
1400
1428
  // longest match for service name
1401
- return (!element._target.$proxy && globalSchemaPrefix !== targetSchemaName) ?
1402
- ((targetSchemaName &&
1403
- globalSchemaPrefix === whatsMyServiceRootName(targetSchemaName)) ? false : true) : false;
1429
+ return (!element._target.$proxy && globalSchemaPrefix !== targetSchemaName)
1430
+ ? (!((targetSchemaName &&
1431
+ globalSchemaPrefix === whatsMyServiceRootName(targetSchemaName)))) : false;
1404
1432
  }
1405
1433
 
1406
1434
  // read a proxy from the elements target
1407
- function getProxyForTargetOf(element) {
1435
+ function getProxyForTargetOf( element ) {
1408
1436
  return element._target.$cachedProxy && element._target.$cachedProxy[globalSchemaPrefix];
1409
1437
  }
1410
1438
 
1411
1439
  // register the proxy at the elements target
1412
- function registerProxy(proxy, element) {
1413
- if(proxy === undefined)
1440
+ function registerProxy( proxy, element ) {
1441
+ if (proxy === undefined)
1414
1442
  return undefined;
1415
1443
 
1416
1444
  setProp(proxy, '$globalSchemaPrefix', globalSchemaPrefix);
1417
1445
  setProp(proxy, '$origin', element);
1418
1446
 
1419
- const fqProxyName = proxy.$globalSchemaPrefix + '.' + proxy.name;
1447
+ const fqProxyName = `${proxy.$globalSchemaPrefix}.${proxy.name}`;
1420
1448
 
1421
- if(!element._target.$cachedProxy)
1449
+ if (!element._target.$cachedProxy)
1422
1450
  edmUtils.assignProp(element._target, '$cachedProxy', Object.create(null));
1423
- if(getProxyForTargetOf(element)) {
1424
- info(null, ['definitions', struct.name, 'elements', element.name],
1425
- { name: fqProxyName }, 'Proxy EDM entity type $(NAME) has already been registered');
1451
+ if (getProxyForTargetOf(element)) {
1452
+ info(null, [ 'definitions', struct.name, 'elements', element.name ],
1453
+ { name: fqProxyName }, 'Proxy EDM entity type $(NAME) has already been registered');
1426
1454
  }
1427
1455
  else {
1428
1456
  determineEntitySet(proxy);
@@ -1434,12 +1462,11 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1434
1462
  }
1435
1463
 
1436
1464
  function mergeProxiesIntoModel() {
1437
- proxyCache.forEach(proxy => {
1465
+ proxyCache.forEach((proxy) => {
1466
+ const fqProxyName = `${proxy.$globalSchemaPrefix}.${proxy.name}`;
1467
+ const fqSchemaName = `${proxy.$globalSchemaPrefix}.${proxy.$mySchemaName}`;
1438
1468
 
1439
- const fqProxyName = proxy.$globalSchemaPrefix + '.' + proxy.name;
1440
- const fqSchemaName = proxy.$globalSchemaPrefix + '.' + proxy.$mySchemaName;
1441
-
1442
- if(proxy.kind === 'entity') {
1469
+ if (proxy.kind === 'entity') {
1443
1470
  finalizeProxyContainments(proxy);
1444
1471
  // collect all schemas even for newly exposed types
1445
1472
  // (that may reside in another subcontext schema), but only once
@@ -1449,73 +1476,71 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1449
1476
  // followed by all namespaces that are potentially exposed by the exposed types
1450
1477
  // don't forget to prepend the global namespace prefix
1451
1478
  // schemas are ordered in csn2edm.js for each service
1452
- Object.keys(proxy.$exposedTypes).forEach(t =>
1453
- schemaSet.add(proxy.$globalSchemaPrefix + '.' + edmUtils.getSchemaPrefix(t)));
1454
- schemaSet.forEach(schemaName => {
1455
- if(!schemas[schemaName]) {
1479
+ Object.keys(proxy.$exposedTypes).forEach(t => schemaSet.add(`${proxy.$globalSchemaPrefix}.${edmUtils.getSchemaPrefix(t)}`));
1480
+ schemaSet.forEach((schemaName) => {
1481
+ if (!schemas[schemaName]) {
1456
1482
  schemas[schemaName] = { kind: 'schema', name: schemaName };
1457
1483
  schemaNames.push(schemaName);
1458
1484
  }
1459
1485
  });
1460
1486
  const alreadyRegistered = csn.definitions[fqProxyName];
1461
- if(!alreadyRegistered) {
1487
+ if (!alreadyRegistered) {
1462
1488
  csn.definitions[fqProxyName] = proxy;
1463
1489
  reqDefs.definitions[fqProxyName] = proxy;
1464
- setProp(proxy, '$path', ['definitions', fqProxyName]);
1465
- Object.entries(proxy.$exposedTypes).forEach(([tn, v]) => {
1466
- const fqtn = proxy.$globalSchemaPrefix + '.' + tn;
1467
- if(csn.definitions[fqtn] === undefined) {
1490
+ setProp(proxy, '$path', [ 'definitions', fqProxyName ]);
1491
+ Object.entries(proxy.$exposedTypes).forEach(([ tn, v ]) => {
1492
+ const fqtn = `${proxy.$globalSchemaPrefix}.${tn}`;
1493
+ if (csn.definitions[fqtn] === undefined) {
1468
1494
  csn.definitions[fqtn] = v;
1469
1495
  reqDefs.definitions[fqtn] = v;
1470
- setProp(v, '$path', ['definitions', fqtn]);
1496
+ setProp(v, '$path', [ 'definitions', fqtn ]);
1471
1497
  }
1472
1498
  });
1473
1499
 
1474
1500
  // default location is not always correct in case proxy has been created by a nested assoc
1475
1501
  // as foreign key targeting another proxy association
1476
- let loc = ['definitions', proxy.$origin._parent.name, 'elements', proxy.$origin.name];
1477
- if(proxy.$origin._parent.$path)
1478
- loc = [...proxy.$origin._parent.$path, 'elements', proxy.$origin.name]
1502
+ let loc = [ 'definitions', proxy.$origin._parent.name, 'elements', proxy.$origin.name ];
1503
+ if (proxy.$origin._parent.$path)
1504
+ loc = [ ...proxy.$origin._parent.$path, 'elements', proxy.$origin.name ];
1479
1505
  info(null, loc,
1480
- { name: proxy.name }, 'Created proxy EDM entity type $(NAME)');
1506
+ { name: proxy.name }, 'Created proxy EDM entity type $(NAME)');
1481
1507
  }
1482
- else if(alreadyRegistered && !alreadyRegistered.$proxy &&
1508
+ else if (alreadyRegistered && !alreadyRegistered.$proxy &&
1483
1509
  alreadyRegistered.kind !== 'entity') {
1484
- warning('odata-definition-exists', ['definitions', proxy.$origin._parent.name, 'elements', proxy.$origin.name],
1485
- { '#': 'proxy', name: fqProxyName, kind: alreadyRegistered.kind });
1510
+ warning('odata-definition-exists', [ 'definitions', proxy.$origin._parent.name, 'elements', proxy.$origin.name ],
1511
+ { '#': 'proxy', name: fqProxyName, kind: alreadyRegistered.kind });
1486
1512
  }
1487
1513
  }
1488
- else {
1514
+ else if (!schemas[fqSchemaName]) {
1489
1515
  // it's a service reference, just add that reference proxy
1490
- if(!schemas[fqSchemaName]) {
1491
- schemas[fqSchemaName] = proxy;
1492
- schemaNames.push(fqSchemaName);
1493
- info(null, ['definitions', proxy.$origin._parent.name, 'elements', proxy.$origin.name],
1494
- { name: proxy.name }, 'Created EDM namespace reference $(NAME)');
1495
- }
1496
- // don't error on duplicate schemas, if it's already present then all is good....
1516
+ schemas[fqSchemaName] = proxy;
1517
+ schemaNames.push(fqSchemaName);
1518
+ info(null, [ 'definitions', proxy.$origin._parent.name, 'elements', proxy.$origin.name ],
1519
+ { name: proxy.name }, 'Created EDM namespace reference $(NAME)');
1497
1520
  }
1521
+ // don't error on duplicate schemas, if it's already present then all is good....
1498
1522
  });
1499
- schemaNames.sort((a,b) => b.length-a.length);
1523
+ schemaNames.sort((a, b) => b.length - a.length);
1500
1524
 
1501
- function finalizeProxyContainments(proxy) {
1525
+ function finalizeProxyContainments( proxy ) {
1502
1526
  // initialise containments after all exposed types are collected
1503
1527
  // AND remove unfulfillable NavRestrictions
1504
1528
  initContainments(proxy);
1505
1529
  const assocPaths = proxy.$containeeAssociations.map(entry => entry.path.join('.'));
1506
1530
  const newNpr = [];
1507
1531
  const npr = proxy[NavResAnno];
1508
- npr && npr.forEach(np => {
1509
- const npath = np.NavigationProperty && np.NavigationProperty['='];
1510
- if(npath && assocPaths.includes(npath))
1511
- newNpr.push(np);
1512
- });
1513
- if(newNpr.length) {
1514
- proxy[NavResAnno] = newNpr;
1515
- }
1516
- else {
1517
- delete proxy[NavResAnno]
1532
+ if (npr) {
1533
+ npr.forEach((np) => {
1534
+ const npath = np.NavigationProperty && np.NavigationProperty['='];
1535
+ if (npath && assocPaths.includes(npath))
1536
+ newNpr.push(np);
1537
+ });
1518
1538
  }
1539
+ if (newNpr.length)
1540
+ proxy[NavResAnno] = newNpr;
1541
+
1542
+ else
1543
+ delete proxy[NavResAnno];
1519
1544
  }
1520
1545
  }
1521
1546
 
@@ -1532,25 +1557,25 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1532
1557
  and do not render associations (this will include the foreign keys of
1533
1558
  the _isToContainer association).
1534
1559
  */
1535
- function initEdmKeyRefPaths(def, defName) {
1536
- if(def.$keys) {
1560
+ function initEdmKeyRefPaths( def, defName ) {
1561
+ if (def.$keys) {
1537
1562
  setProp(def, '$edmKeyPaths', []);
1538
1563
  // for all key elements that shouldn't be ignored produce the paths
1539
1564
  edmUtils.foreach(def.$keys, k => !(k._isToContainer && k._selfReferences.length), (k, kn) => {
1540
- if(isEdmPropertyRendered(k, options) &&
1565
+ if (isEdmPropertyRendered(k, options) &&
1541
1566
  !(options.isV2() && k['@Core.MediaType'])) {
1542
- if(options.isV4() && options.isStructFormat) {
1567
+ if (options.isV4() && options.isStructFormat) {
1543
1568
  // This is structured OData ONLY
1544
1569
  // if the foreign keys are explicitly requested, ignore associations and use the flat foreign keys instead
1545
- if(!options.renderForeignKeys || (options.renderForeignKeys && !k.target))
1570
+ if (!options.renderForeignKeys || (options.renderForeignKeys && !k.target))
1546
1571
  def.$edmKeyPaths.push(...produceKeyRefPaths(k, kn, [ 'definitions', defName, 'elements', kn ]));
1547
1572
  }
1548
1573
  // In v2/v4 flat, associations are never rendered
1549
- else if(!k.target) {
1550
- def.$edmKeyPaths.push([kn]);
1574
+ else if (!k.target) {
1575
+ def.$edmKeyPaths.push([ kn ]);
1551
1576
  }
1552
1577
  // check toplevel key for spec violations
1553
- checkKeySpecViolations(k, ['definitions', defName, 'elements', k.name]);
1578
+ checkKeySpecViolations(k, [ 'definitions', defName, 'elements', k.name ]);
1554
1579
  }
1555
1580
  });
1556
1581
  }
@@ -1565,11 +1590,11 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1565
1590
  navprops to be key ref.
1566
1591
  If element is of scalar type, return it as an array.
1567
1592
  */
1568
- function produceKeyRefPaths(eltCsn, prefix, path) {
1593
+ function produceKeyRefPaths( eltCsn, prefix, path ) {
1569
1594
  const keyPaths = [];
1570
1595
  // we want to point to the element in the entity which is the first path step
1571
- const location = def.$path.concat(['elements']).concat(prefix.split('/')[0]);
1572
- if(!isEdmPropertyRendered(eltCsn, options)) {
1596
+ const location = def.$path.concat([ 'elements' ]).concat(prefix.split('/')[0]);
1597
+ if (!isEdmPropertyRendered(eltCsn, options)) {
1573
1598
  // let annos = Object.keys(eltCsn).filter(a=>a[0]==='@').join(', ');
1574
1599
  // warning(null, ['definitions', struct.name, 'elements', eltCsn.name ],
1575
1600
  // `${struct.name}: OData V4 primary key path: "${prefix}" is unexposed by one of these annotations "${annos}"` );
@@ -1583,25 +1608,25 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1583
1608
  elements = finalType?.elements || finalType?.items?.elements;
1584
1609
  }
1585
1610
  if (elements) {
1586
- Object.entries(elements).forEach(([eltName, elt]) => {
1587
- if(!elt.$visited) {
1611
+ Object.entries(elements).forEach(([ eltName, elt ]) => {
1612
+ if (!elt.$visited) {
1588
1613
  setProp(elt, '$visited', true);
1589
1614
  let newRefs = [];
1590
1615
  // if the foreign keys are explicitly requested, ignore associations and use the flat foreign key instead
1591
1616
  // ignore nested unmanaged associations
1592
- if((!options.renderForeignKeys || (options.renderForeignKeys && !elt.target)) && !(elt.target && elt.on))
1617
+ if ((!options.renderForeignKeys || (options.renderForeignKeys && !elt.target)) && !(elt.target && elt.on))
1593
1618
  newRefs = produceKeyRefPaths(elt, prefix + options.pathDelimiter + eltName, path);
1594
- if(newRefs.length) {
1619
+ if (newRefs.length) {
1595
1620
  keyPaths.push(...newRefs);
1596
- // check path step key for spec violations
1621
+ // check path step key for spec violations
1597
1622
  const pathSegment = `${prefix}/${eltName}`;
1598
1623
  checkKeySpecViolations(elt, location, pathSegment);
1599
1624
  }
1600
1625
  delete elt.$visited;
1601
- } else {
1626
+ }
1627
+ else {
1602
1628
  error('odata-key-recursive', path, { name: prefix });
1603
1629
  }
1604
-
1605
1630
  });
1606
1631
  }
1607
1632
  /* If element is a managed association (can't be anything else),
@@ -1609,38 +1634,37 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1609
1634
  This also implies that the association itself is never added into the
1610
1635
  list of primary key refs
1611
1636
  */
1612
- else if(eltCsn.target && !eltCsn.on) {
1637
+ else if (eltCsn.target && !eltCsn.on) {
1613
1638
  // if this association has no keys or if it is a redirected parameterized entity,
1614
1639
  // use the primary keys of the target
1615
- let keys = (!eltCsn._target.$isParamEntity && eltCsn.keys) ||
1616
- Object.keys(eltCsn._target.$keys).map(k => { return { ref: [k] } });
1617
- let pathSegment = prefix
1618
- keys.forEach(k => {
1640
+ const keys = (!eltCsn._target.$isParamEntity && eltCsn.keys) ||
1641
+ Object.keys(eltCsn._target.$keys).map(k => ({ ref: [ k ] }));
1642
+ let pathSegment = prefix;
1643
+ keys.forEach((k) => {
1619
1644
  let art = eltCsn._target || csnUtils.getCsnDef(eltCsn.target);
1620
- for(let ps of k.ref) {
1645
+ for (const ps of k.ref) {
1621
1646
  art = art.elements[ps];
1622
- pathSegment += '/' + art.name
1647
+ pathSegment += `/${art.name}`;
1623
1648
  checkKeySpecViolations(art, location, pathSegment);
1624
- if(art.type && !isBuiltinType(art.type)) {
1649
+ if (art.type && !isBuiltinType(art.type))
1625
1650
  art = art._type || csnUtils.getCsnDef(art.type);
1626
- }
1627
1651
  }
1628
1652
  keyPaths.push(...produceKeyRefPaths(art, prefix + options.pathDelimiter + k.ref.join(options.pathDelimiter), path));
1629
1653
  });
1630
1654
  }
1631
1655
  else {
1632
- keyPaths.push([prefix]);
1656
+ keyPaths.push([ prefix ]);
1633
1657
  }
1634
1658
  return keyPaths;
1635
1659
  }
1636
1660
 
1637
- function checkKeySpecViolations(elt, location, pathSegment) {
1661
+ function checkKeySpecViolations( elt, location, pathSegment ) {
1638
1662
  // Nullability
1639
1663
  const eltDef = elt.items || elt;
1640
- if((!elt.key && (eltDef.notNull === undefined || eltDef.notNull === false)) ||
1664
+ if ((!elt.key && (eltDef.notNull === undefined || eltDef.notNull === false)) ||
1641
1665
  elt.key && (eltDef.notNull !== undefined && eltDef.notNull === false)) {
1642
1666
  message('odata-spec-violation-key-null', location,
1643
- {name: pathSegment ? pathSegment : elt.name, '#': !pathSegment ? 'std' : 'scalar'});
1667
+ { name: pathSegment || elt.name, '#': !pathSegment ? 'std' : 'scalar' });
1644
1668
  }
1645
1669
  // many is either directly on elements or on the type
1646
1670
  // due to added proxy types it might be that the type can't be found in definitions
@@ -1649,32 +1673,46 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1649
1673
  !isBuiltinType(elt.type) &&
1650
1674
  csn.definitions[elt.type] &&
1651
1675
  csnUtils.getFinalTypeInfo(elt.type).items);
1652
- if(type ||
1676
+ if (type ||
1653
1677
  (options.odataFormat !== 'flat' && !options.odataForeignKeys) &&
1654
1678
  elt.cardinality?.max && elt.cardinality.max !== 1) {
1655
1679
  // many primary key can be induced by a many parameter of a view
1656
1680
  message('odata-spec-violation-key-array', location,
1657
- {
1658
- name: pathSegment ? pathSegment : elt.name,
1659
- value: cardinality2str(elt),
1660
- '#': elt.target ? 'assoc' : 'std'
1661
- });
1681
+ {
1682
+ name: pathSegment || elt.name,
1683
+ value: cardinality2str(elt),
1684
+ '#': elt.target ? 'assoc' : 'std',
1685
+ });
1662
1686
  }
1663
1687
  // type
1664
- if(!elt.elements) {
1665
- if(!type)
1688
+ if (!elt.elements) {
1689
+ if (!type)
1666
1690
  type = isBuiltinType(elt.type) ? elt : csn.definitions[elt.type];
1667
1691
 
1668
1692
  // check for legal scalar types, proxy exposed structured types are not resolvable in CSN
1669
1693
  // V2 allows any Edm.PrimitiveType (even Double and Binary), V4 is more specific:
1670
- if(options.isV4() && type && !type.target && isBuiltinType(type.type)) {
1694
+ if (options.isV4() && type && !type.target && isBuiltinType(type.type)) {
1671
1695
  const edmType = edmUtils.mapCdsToEdmType(type);
1672
1696
  const legalEdmTypes = {
1673
- 'Edm.Boolean':1, 'Edm.Byte':1, 'Edm.Date':1, 'Edm.DateTimeOffset':1, 'Edm.Decimal':1, 'Edm.Duration':1,
1674
- 'Edm.Guid':1, 'Edm.Int16':1, 'Edm.Int32':1, 'Edm.Int64':1, 'Edm.SByte':1, 'Edm.String':1, 'Edm.TimeOfDay':1 };
1675
- if(!(edmType in legalEdmTypes)) {
1697
+ 'Edm.Boolean': 1,
1698
+ 'Edm.Byte': 1,
1699
+ 'Edm.Date': 1,
1700
+ 'Edm.DateTimeOffset': 1,
1701
+ 'Edm.Decimal': 1,
1702
+ 'Edm.Duration': 1,
1703
+ 'Edm.Guid': 1,
1704
+ 'Edm.Int16': 1,
1705
+ 'Edm.Int32': 1,
1706
+ 'Edm.Int64': 1,
1707
+ 'Edm.SByte': 1,
1708
+ 'Edm.String': 1,
1709
+ 'Edm.TimeOfDay': 1,
1710
+ };
1711
+ if (!(edmType in legalEdmTypes)) {
1676
1712
  warning('odata-spec-violation-key-type', location,
1677
- {name: pathSegment, type: type.type, id: edmType, '#': pathSegment ? 'std' : 'scalar'});
1713
+ {
1714
+ name: pathSegment, type: type.type, id: edmType, '#': pathSegment ? 'std' : 'scalar',
1715
+ });
1678
1716
  }
1679
1717
  }
1680
1718
  }
@@ -1708,26 +1746,26 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1708
1746
  Path="items/subitems/subitems/up_" Target="Header/items/subitems"/>
1709
1747
  Path="items/subitems/subitems/toG" Target="G"/>
1710
1748
  */
1711
- function initEdmNavPropBindingTargets(def) {
1712
- if(def.$hasEntitySet) {
1749
+ function initEdmNavPropBindingTargets( def ) {
1750
+ if (def.$hasEntitySet) {
1713
1751
  forEachGeneric(def.items || def, 'elements', (element) => {
1714
- produceTargetPath([edmUtils.getBaseName(def.name)], element, def);
1752
+ produceTargetPath([ edmUtils.getBaseName(def.name) ], element, def);
1715
1753
  });
1716
1754
  }
1717
1755
 
1718
- function produceTargetPath(prefix, elt, curDef) {
1719
- const newPrefix = [...prefix, elt.name];
1720
- if(isEdmPropertyRendered(elt, options)) {
1756
+ function produceTargetPath( prefix, elt, curDef ) {
1757
+ const newPrefix = [ ...prefix, elt.name ];
1758
+ if (isEdmPropertyRendered(elt, options)) {
1721
1759
  // Assoc can never be a derived TypeDefinition, no need to
1722
1760
  // unroll derived type chains for assocs
1723
- if(elt.target && !elt.$visited) {
1724
- if(!elt._target.$edmTgtPaths)
1761
+ if (elt.target && !elt.$visited) {
1762
+ if (!elt._target.$edmTgtPaths)
1725
1763
  setProp(elt._target, '$edmTgtPaths', []);
1726
1764
  // drill into target only if
1727
1765
  // 1) target has no entity set and this assoc is not going to the container
1728
1766
  // 2) current definition and target are the same (cycle)
1729
1767
  // 3) it's no external reference
1730
- if(!elt.$externalRef &&
1768
+ if (!elt.$externalRef &&
1731
1769
  !elt._target.$hasEntitySet &&
1732
1770
  !elt._isToContainer &&
1733
1771
  curDef !== elt._target) {
@@ -1740,10 +1778,10 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1740
1778
  }
1741
1779
  else {
1742
1780
  // try to find elements to drill down further
1743
- while(elt && !(isBuiltinType(elt.type) || elt.elements)) {
1781
+ while (elt && !(isBuiltinType(elt.type) || elt.elements))
1744
1782
  elt = csn.definitions[elt.type];
1745
- }
1746
- if(elt && elt.elements && !elt.$visited) {
1783
+
1784
+ if (elt && elt.elements && !elt.$visited) {
1747
1785
  setProp(elt, '$visited', true);
1748
1786
  Object.values(elt.elements).forEach(e => produceTargetPath(newPrefix, e, curDef));
1749
1787
  delete elt.$visited;
@@ -1753,8 +1791,8 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1753
1791
  }
1754
1792
  }
1755
1793
 
1756
- function initEdmNavPropBindingPaths(def) {
1757
- if(options.isV4() &&def.$hasEntitySet) {
1794
+ function initEdmNavPropBindingPaths( def ) {
1795
+ if (options.isV4() && def.$hasEntitySet) {
1758
1796
  let npbs = [];
1759
1797
  forEachGeneric(def.items || def, 'elements', (element) => {
1760
1798
  npbs = npbs.concat(produceNavigationPath(element, def));
@@ -1763,50 +1801,52 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1763
1801
  }
1764
1802
 
1765
1803
  // collect all paths originating from this element that end up in an entity set
1766
- function produceNavigationPath(elt, curDef) {
1804
+ function produceNavigationPath( elt, curDef ) {
1767
1805
  let npbs = [];
1768
1806
  const prefix = elt.name;
1769
- if(isEdmPropertyRendered(elt, options)) {
1807
+ if (isEdmPropertyRendered(elt, options)) {
1770
1808
  // Assoc can never be a derived TypeDefinition, no need to
1771
1809
  // unroll derived type chains for assocs
1772
- if(elt.target && !elt.$visited) {
1810
+ if (elt.target && !elt.$visited) {
1773
1811
  // drill into target only if
1774
1812
  // 1) target has no entity set and this assoc is not going to the container
1775
1813
  // 2) current definition and target are the same (cycle)
1776
1814
  // 3) it's no external reference
1777
- if(!elt.$externalRef &&
1815
+ if (!elt.$externalRef &&
1778
1816
  !elt._target.$hasEntitySet &&
1779
1817
  !elt._isToContainer &&
1780
1818
  curDef !== elt._target) {
1781
1819
  // follow elements in the target but avoid cycles
1782
1820
  setProp(elt, '$visited', true);
1783
- Object.values(elt._target.elements).forEach(e => npbs = npbs.concat(produceNavigationPath(e, elt._target)));
1821
+ Object.values(elt._target.elements).forEach((e) => {
1822
+ npbs = npbs.concat(produceNavigationPath(e, elt._target));
1823
+ });
1784
1824
  delete elt.$visited;
1785
1825
  }
1786
- else if(!(options.odataContainment && options.isV4() && elt['@odata.contained'])) {
1826
+ else if (!(options.odataContainment && options.isV4() && elt['@odata.contained'])) {
1787
1827
  // end point reached but must not be an external reference nor a proxy nor a composition itself
1788
1828
  // last assoc step must not be to-n and target a singleton
1789
- let p = undefined;
1829
+ let path;
1790
1830
  if (!elt.$externalRef &&
1791
1831
  !(edmUtils.isToMany(elt) &&
1792
1832
  edmUtils.isSingleton(elt._target) &&
1793
1833
  options.isV4())) {
1794
- if(elt._target.$edmTgtPaths && elt._target.$edmTgtPaths.length) {
1795
- p = elt._target.$edmTgtPaths.find(p => p[0] === edmUtils.getBaseName(def.name)) || elt._target.$edmTgtPaths[0];
1834
+ if (elt._target.$edmTgtPaths && elt._target.$edmTgtPaths.length) {
1835
+ path = elt._target.$edmTgtPaths.find(p => p[0] === edmUtils.getBaseName(def.name)) || elt._target.$edmTgtPaths[0];
1796
1836
  }
1797
- else if(elt._target.$hasEntitySet) {
1837
+ else if (elt._target.$hasEntitySet) {
1798
1838
  const baseName = edmUtils.getBaseName(elt._target.$entitySetName || elt._target.name);
1799
1839
  // if own struct and target have a set they either are in the same $mySchemaName or not
1800
1840
  // if target is in another schema, target the full qualified entity set
1801
- p = (elt._target.$mySchemaName === def.$mySchemaName) ?
1802
- [ baseName ] : [elt._target.$mySchemaName + '.EntityContainer', baseName];
1841
+ path = (elt._target.$mySchemaName === def.$mySchemaName)
1842
+ ? [ baseName ] : [ `${elt._target.$mySchemaName}.EntityContainer`, baseName ];
1803
1843
  }
1804
- if(p) {
1844
+ if (path) {
1805
1845
  // if own struct and target have a set they either are in the same $mySchemaName or not
1806
1846
  // if target is in another schema, target the full qualified entity set
1807
1847
  const npb = {
1808
1848
  Path: elt.name,
1809
- Target: p.join('/')
1849
+ Target: path.join('/'),
1810
1850
  };
1811
1851
  npbs.push( npb );
1812
1852
  }
@@ -1817,61 +1857,65 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1817
1857
  }
1818
1858
  else {
1819
1859
  // try to find elements to drill down further
1820
- while(elt && !(isBuiltinType(elt.type) || elt.elements)) {
1860
+ while (elt && !(isBuiltinType(elt.type) || elt.elements))
1821
1861
  elt = csn.definitions[elt.type];
1822
- }
1823
- if(elt && elt.elements && !elt.$visited) {
1862
+
1863
+ if (elt && elt.elements && !elt.$visited) {
1824
1864
  setProp(elt, '$visited', true);
1825
- Object.values(elt.elements).forEach(e => npbs = npbs.concat(produceNavigationPath(e, curDef)));
1865
+ Object.values(elt.elements).forEach((e) => {
1866
+ npbs = npbs.concat(produceNavigationPath(e, curDef));
1867
+ });
1826
1868
  delete elt.$visited;
1827
1869
  }
1828
1870
  }
1829
1871
  }
1830
- npbs.forEach(p => p.Path = prefix + '/' + p.Path );
1872
+ npbs.forEach((p) => {
1873
+ p.Path = `${prefix}/${p.Path}`;
1874
+ });
1831
1875
  return npbs;
1832
1876
  }
1833
1877
  }
1834
1878
 
1835
- function determineEntitySet(def) {
1879
+ function determineEntitySet( def ) {
1836
1880
  // if this is an entity or a view, determine if an entity set is required or not
1837
1881
  // 1) must not be a proxy and not a containee in V4
1838
1882
  // No annos are rendered for non-existing EntitySet targets.
1839
- if(def.$hasEntitySet === undefined) {
1883
+ if (def.$hasEntitySet === undefined) {
1840
1884
  const hasEntitySet = def.kind === 'entity' && !(options.isV4() && edmUtils.isContainee(def)) && !def.$proxy;
1841
1885
  setProp(def, '$hasEntitySet', hasEntitySet);
1842
1886
  }
1843
1887
  }
1844
1888
 
1845
- function finalize(def, defName) {
1889
+ function finalize( def, defName ) {
1846
1890
  // 1. let all doc props become @Core.Descriptions
1847
1891
  // 2. mark a member that will become a collection
1848
1892
  // 3. assign the edm primitive type to elements, to be used in the rendering later
1849
1893
  // 4. assign @Validation.AllowedValues to enums
1850
- const path = ['definitions', defName];
1894
+ const defLocation = [ 'definitions', defName ];
1851
1895
  edmUtils.assignAnnotation(def, '@Core.Description', def.doc);
1852
1896
  markCollection(def);
1853
1897
  mapCdsToEdmProp(def);
1854
- annotateAllowedValues(def, path);
1855
- if (def.returns) {
1898
+ annotateAllowedValues(def, defLocation);
1899
+ if (def.returns) {
1856
1900
  markCollection(def.returns);
1857
1901
  mapCdsToEdmProp(def.returns);
1858
- annotateAllowedValues(def.returns, [...path, 'returns']);
1902
+ annotateAllowedValues(def.returns, [ ...defLocation, 'returns' ]);
1859
1903
  }
1860
- forEachMemberRecursively(def, (member, _memberName, _prop, path) => {
1904
+ forEachMemberRecursively(def, (member, _memberName, _prop, location) => {
1861
1905
  edmUtils.assignAnnotation(member, '@Core.Description', member.doc);
1862
1906
  markCollection(member);
1863
1907
  mapCdsToEdmProp(member);
1864
- annotateAllowedValues(member, path);
1908
+ annotateAllowedValues(member, location);
1865
1909
  ComputedDefaultValue(member);
1866
1910
  if (member.returns) {
1867
1911
  edmUtils.assignAnnotation(member.returns, '@Core.Description', member.returns.doc);
1868
1912
  markCollection(member.returns);
1869
1913
  mapCdsToEdmProp(member.returns);
1870
- annotateAllowedValues(member.returns, [...path, 'returns']);
1914
+ annotateAllowedValues(member.returns, [ ...location, 'returns' ]);
1871
1915
  }
1872
- }, path);
1916
+ }, defLocation);
1873
1917
  // mark members that need to be rendered as collections
1874
- function markCollection(obj) {
1918
+ function markCollection( obj ) {
1875
1919
  const items = obj.items || csn.definitions[obj.type] && csn.definitions[obj.type].items;
1876
1920
  if (items) {
1877
1921
  edmUtils.assignProp(obj, '_NotNullCollection', items.notNull !== undefined ? items.notNull : true);
@@ -1886,48 +1930,46 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1886
1930
  - has no value but the base type is cds.String, use the
1887
1931
  symbol as value
1888
1932
  */
1889
- function annotateAllowedValues(node, path) {
1933
+ function annotateAllowedValues( node, location ) {
1890
1934
  let typeDef = node;
1891
- if(!node.enum && node.type && !isBuiltinType(node.type))
1935
+ if (!node.enum && node.type && !isBuiltinType(node.type))
1892
1936
  typeDef = csn.definitions[node.type];
1893
- if(typeDef?.enum) {
1937
+ if (typeDef?.enum) {
1894
1938
  const enumValue = [];
1895
- for(const enumSymbol in typeDef.enum) {
1939
+ for (const enumSymbol in typeDef.enum) {
1896
1940
  const result = { '@Core.SymbolicName': enumSymbol };
1897
1941
  let enumSymbolDef = typeDef.enum[enumSymbol];
1898
- while(enumSymbolDef && !enumSymbolDef.$visited && enumSymbolDef['#']) {
1942
+ while (enumSymbolDef && !enumSymbolDef.$visited && enumSymbolDef['#']) {
1899
1943
  setProp(enumSymbolDef, '$visited', true);
1900
1944
  enumSymbolDef = typeDef.enum[enumSymbolDef['#']];
1901
1945
  }
1902
1946
  // reset visited
1903
- for(const es in typeDef.enum)
1947
+ for (const es in typeDef.enum)
1904
1948
  delete typeDef.enum[es].$visited;
1905
1949
 
1906
- if(enumSymbolDef) {
1907
- if(enumSymbolDef.val !== undefined) {
1950
+ if (enumSymbolDef) {
1951
+ if (enumSymbolDef.val !== undefined) {
1908
1952
  // 'null' value is represented spec conform as empty record in AllowedValues collection
1909
1953
  result.Value = enumSymbolDef.val;
1910
1954
  enumValue.push(result);
1911
1955
  }
1912
- else {
1913
- if(typeDef.type === 'cds.String') {
1956
+ else if (typeDef.type === 'cds.String') {
1914
1957
  // the symbol is used as value for type 'cds.String'
1915
- result.Value = enumSymbol;
1916
- enumValue.push(result);
1917
- }
1918
- else if(node.kind !== 'annotation') {
1919
- // omit the entry and warn
1920
- warning('odata-enum-missing-value', path,
1921
- { name: enumSymbol, anno: '@Validation.AllowedValues', type: typeDef.type },
1922
- 'Expected enum element $(NAME) of type $(TYPE) to have a value, not added to $(ANNO)');
1923
- }
1958
+ result.Value = enumSymbol;
1959
+ enumValue.push(result);
1960
+ }
1961
+ else if (node.kind !== 'annotation') {
1962
+ // omit the entry and warn
1963
+ warning('odata-enum-missing-value', location,
1964
+ { name: enumSymbol, anno: '@Validation.AllowedValues', type: typeDef.type },
1965
+ 'Expected enum element $(NAME) of type $(TYPE) to have a value, not added to $(ANNO)');
1924
1966
  }
1925
1967
  }
1926
1968
  else { // enumSymbolDef not found
1927
1969
  // omit the entry and warn
1928
- warning('odata-enum-missing-value', path,
1929
- { name: enumSymbol, anno: '@Validation.AllowedValues', type: typeDef.type },
1930
- 'Expected enum element $(NAME) of type $(TYPE) to have a value, not added to $(ANNO)');
1970
+ warning('odata-enum-missing-value', location,
1971
+ { name: enumSymbol, anno: '@Validation.AllowedValues', type: typeDef.type },
1972
+ 'Expected enum element $(NAME) of type $(TYPE) to have a value, not added to $(ANNO)');
1931
1973
  }
1932
1974
 
1933
1975
  // Can't rely that @description has already been renamed to @Core.Description
@@ -1937,11 +1979,10 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1937
1979
  if (desc)
1938
1980
  result['@Core.Description'] = desc;
1939
1981
  }
1940
- if(enumValue.length > 0)
1982
+ if (enumValue.length > 0)
1941
1983
  edmUtils.assignAnnotation(node, '@Validation.AllowedValues', enumValue);
1942
1984
  }
1943
1985
  }
1944
-
1945
1986
  }
1946
1987
 
1947
1988
  // If containment in V4 is active, annotations that would be assigned to the containees
@@ -1949,48 +1990,47 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1949
1990
  // the containment navigation property.
1950
1991
  // Today only Capabilities.*Restrictions are known to be remapped as there exists a CDS
1951
1992
  // short cut annotation @readonly that gets expanded and can be safely remapped.
1952
- function pullupCapabilitiesAnnotations(rootContainer) {
1953
-
1954
- if(!options.odataCapabilitiesPullup)
1993
+ function pullupCapabilitiesAnnotations( rootContainer ) {
1994
+ if (!options.odataCapabilitiesPullup)
1955
1995
  return;
1956
1996
  // @Capabilities is applicable to EntitySet/Collection only
1957
- if(!rootContainer.$hasEntitySet)
1997
+ if (!rootContainer.$hasEntitySet)
1958
1998
  return;
1959
1999
 
1960
- const isRecursiveContainment =
1961
- !!(rootContainer.$containerNames && rootContainer.$containeeAssociations &&
2000
+ const isRecursiveContainment
2001
+ = !!(rootContainer.$containerNames && rootContainer.$containeeAssociations &&
1962
2002
  rootContainer.$containerNames.length === 1 &&
1963
2003
  rootContainer.$containeeAssociations.some(entry => rootContainer.$containerNames.includes(entry.assoc.target)));
1964
2004
 
1965
2005
  // Root nodes are not contained
1966
- const isRootNode =
1967
- !!(!rootContainer.$containerNames ||
2006
+ const isRootNode
2007
+ = !!(!rootContainer.$containerNames ||
1968
2008
  rootContainer.$containerNames && rootContainer.$containerNames.length === 0);
1969
2009
 
1970
- if(!isRecursiveContainment && !isRootNode)
2010
+ if (!isRecursiveContainment && !isRootNode)
1971
2011
  return;
1972
2012
 
1973
2013
  const rootRestrictions = [];
1974
2014
  addContainmentAnnotationsRecursively([], rootContainer);
1975
- if(rootRestrictions.length)
2015
+ if (rootRestrictions.length)
1976
2016
  rootContainer[NavResAnno] = rootRestrictions;
1977
2017
 
1978
- function addContainmentAnnotationsRecursively(prefix, container) {
1979
- if(container.$containeeAssociations) {
2018
+ function addContainmentAnnotationsRecursively( prefix, container ) {
2019
+ if (container.$containeeAssociations) {
1980
2020
  // copy or create container restrictions, don't modify original
1981
- const localRestrictions = container[NavResAnno] ?
1982
- cloneAnnotationValue(container[NavResAnno]) : []
2021
+ const localRestrictions = container[NavResAnno]
2022
+ ? cloneAnnotationValue(container[NavResAnno]) : [];
1983
2023
 
1984
2024
  // prefix the existing navigation property restrictions on the container
1985
- if(prefix.length) {
1986
- localRestrictions.forEach(npe => {
1987
- if(npe.NavigationProperty &&
2025
+ if (prefix.length) {
2026
+ localRestrictions.forEach((npe) => {
2027
+ if (npe.NavigationProperty &&
1988
2028
  npe.NavigationProperty['='] &&
1989
2029
  typeof npe.NavigationProperty['='] === 'string') {
1990
- applyTransformations({ definitions: { npe }}, {
2030
+ applyTransformations({ definitions: { npe } }, {
1991
2031
  '=': (parent, prop, value) => {
1992
2032
  parent[prop] = prefix.concat(value).join('.');
1993
- }
2033
+ },
1994
2034
  });
1995
2035
  }
1996
2036
  });
@@ -1998,34 +2038,32 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
1998
2038
 
1999
2039
  setProp(container, '$visited', true);
2000
2040
  // collect capabilities from containees
2001
- container.$containeeAssociations.forEach(entry => {
2041
+ container.$containeeAssociations.forEach((entry) => {
2002
2042
  const { assoc, path } = entry;
2003
2043
  const containee = assoc._target;
2004
2044
 
2005
- if(edmUtils.isNavigable(assoc) && isMyServiceRequested(containee.name) || containee.$proxy) {
2045
+ if (edmUtils.isNavigable(assoc) && isMyServiceRequested(containee.name) || containee.$proxy) {
2006
2046
  const localAssocPath = path.join('.');
2007
- let navPropEntry= localRestrictions.find(p =>
2008
- p.NavigationProperty && p.NavigationProperty['='] === prefix.concat(localAssocPath).join('.'));
2047
+ let navPropEntry = localRestrictions.find(p => p.NavigationProperty && p.NavigationProperty['='] === prefix.concat(localAssocPath).join('.'));
2009
2048
  const hasEntry = !!navPropEntry;
2010
2049
 
2011
- if(!hasEntry) {
2012
- navPropEntry = { NavigationProperty: { '=': prefix.concat(localAssocPath).join('.') } };
2013
- }
2050
+ if (!hasEntry)
2051
+ navPropEntry = { NavigationProperty: { '=': prefix.concat(localAssocPath).join('.') } };
2052
+
2014
2053
 
2015
2054
  const props = Object.entries(containee);
2016
2055
  let newEntry = false;
2017
- capabilities.forEach(c => {
2018
- if(edmUtils.mergeIntoNavPropEntry(c, navPropEntry, prefix.concat(path), props))
2056
+ capabilities.forEach((c) => {
2057
+ if (edmUtils.mergeIntoNavPropEntry(c, navPropEntry, prefix.concat(path), props))
2019
2058
  newEntry = true;
2020
2059
  });
2021
2060
 
2022
- if(newEntry && !hasEntry) {
2061
+ if (newEntry && !hasEntry)
2023
2062
  localRestrictions.push(navPropEntry);
2024
- }
2025
2063
 
2026
- if(!containee.$visited) {
2064
+
2065
+ if (!containee.$visited)
2027
2066
  addContainmentAnnotationsRecursively(prefix.concat(path), containee);
2028
- }
2029
2067
  }
2030
2068
  });
2031
2069
 
@@ -2046,95 +2084,97 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
2046
2084
  parameter, a warning is raised, Core.OptionalParameter requires that all optional
2047
2085
  parameters appear rightmost.
2048
2086
  */
2049
- function annotateOptionalActFuncParams(def, defName) {
2050
- if(!isBetaEnabled(options, 'optionalActionFunctionParameters'))
2087
+ function annotateOptionalActFuncParams( def, defName ) {
2088
+ if (!isBetaEnabled(options, 'optionalActionFunctionParameters'))
2051
2089
  return;
2052
2090
  // return if there is nothing to do
2053
- const loc = [ 'definitions', defName ]
2054
- if(def.kind === 'function' || def.kind === 'action')
2091
+ const loc = [ 'definitions', defName ];
2092
+ if (def.kind === 'function' || def.kind === 'action')
2055
2093
  iterateParams(def, loc.concat('params'));
2056
- if(def.actions) {
2057
- for(const an in def.actions) {
2094
+ if (def.actions) {
2095
+ for (const an in def.actions) {
2058
2096
  const a = def.actions[an];
2059
- iterateParams(a, loc.concat(['actions', an, 'params' ]));
2097
+ iterateParams(a, loc.concat([ 'actions', an, 'params' ]));
2060
2098
  }
2061
2099
  }
2062
2100
 
2063
- function iterateParams(def, loc) {
2101
+ function iterateParams( action, location ) {
2064
2102
  let optPns = [];
2065
- def.params && Object.values(def.params).forEach(p => {
2103
+ if (action.params) {
2104
+ Object.values(action.params).forEach((p) => {
2066
2105
  // user assigned annotation, don't touch it
2067
- if(Object.keys(p).some(a => a.startsWith('@Core.OptionalParameter') && p[a] !== null)) {
2068
- optPns.push(p);
2069
- }
2070
- // default value automatically makes param optional
2071
- else if(p.default) {
2072
- if(p.default.val)
2073
- edmUtils.assignAnnotation(p, '@Core.OptionalParameter.DefaultValue', p.default.val);
2074
- else
2106
+ if (Object.keys(p).some(a => a.startsWith('@Core.OptionalParameter') && p[a] !== null)) {
2107
+ optPns.push(p);
2108
+ }
2109
+ // default value automatically makes param optional
2110
+ else if (p.default) {
2111
+ if (p.default.val)
2112
+ edmUtils.assignAnnotation(p, '@Core.OptionalParameter.DefaultValue', p.default.val);
2113
+ else
2114
+ edmUtils.assignAnnotation(p, '@Core.OptionalParameter.$Type', '');
2115
+ optPns.push(p);
2116
+ }
2117
+ // if no default is available, nullable makes param optional
2118
+ else if (!p.notNull) {
2075
2119
  edmUtils.assignAnnotation(p, '@Core.OptionalParameter.$Type', '');
2076
- optPns.push(p);
2077
- }
2078
- // if no default is available, nullable makes param optional
2079
- else if(!p.notNull) {
2080
- edmUtils.assignAnnotation(p, '@Core.OptionalParameter.$Type', '');
2081
- optPns.push(p);
2082
-
2083
- }
2084
- else {
2120
+ optPns.push(p);
2121
+ }
2122
+ else {
2085
2123
  // this is a mandatory parameter, warn about all previously collected optional parameters
2086
- optPns.forEach(p => {
2087
- const type = p.items?.type || p.type;
2088
- if(type !== special$self)
2089
- warning('odata-parameter-order', loc.concat(p.name));
2090
- });
2091
- optPns = [];
2092
- }
2093
- });
2124
+ optPns.forEach((op) => {
2125
+ const type = op.items?.type || op.type;
2126
+ if (type !== special$self)
2127
+ warning('odata-parameter-order', location.concat(op.name));
2128
+ });
2129
+ optPns = [];
2130
+ }
2131
+ });
2132
+ }
2094
2133
  }
2095
2134
  }
2096
2135
 
2097
- //////////////////////////////////////////////////////////////////////
2136
+ // ////////////////////////////////////////////////////////////////////
2098
2137
  //
2099
2138
  // Helper section starts here
2100
2139
  //
2101
2140
 
2102
2141
 
2103
- function mapCdsToEdmProp(obj) {
2142
+ function mapCdsToEdmProp( obj ) {
2104
2143
  if (obj.type && isBuiltinType(obj.type) && !obj.target && !obj.targetAspect) {
2105
- let edmType = edmUtils.mapCdsToEdmType(obj, messageFunctions, _options.odataVersion === 'v2', obj['@Core.MediaType']);
2144
+ const edmType = edmUtils.mapCdsToEdmType(obj, messageFunctions, _options.odataVersion === 'v2', obj['@Core.MediaType']);
2106
2145
  edmUtils.assignProp(obj, '_edmType', edmType);
2107
- } else if (obj._isCollection && (obj.items && isBuiltinType(csnUtils.getFinalTypeInfo(obj.items.type)?.type))) {
2108
- let edmType = edmUtils.mapCdsToEdmType(obj.items, messageFunctions, _options.odataVersion === 'v2', obj['@Core.MediaType'], obj.$path);
2146
+ }
2147
+ else if (obj._isCollection && (obj.items && isBuiltinType(csnUtils.getFinalTypeInfo(obj.items.type)?.type))) {
2148
+ const edmType = edmUtils.mapCdsToEdmType(obj.items, messageFunctions, _options.odataVersion === 'v2', obj['@Core.MediaType'], obj.$path);
2109
2149
  edmUtils.assignProp(obj, '_edmType', edmType);
2110
2150
  }
2111
2151
  // This is the special case when we have array of array, but will not be supported in the future
2112
2152
  else if (obj._isCollection && obj.items && obj.items.type && obj.items.items && isBuiltinType(csnUtils.getFinalTypeInfo(obj.items.items.type)?.type)) {
2113
- let edmType = edmUtils.mapCdsToEdmType(obj.items.items, messageFunctions, _options.odataVersion === 'v2', obj['@Core.MediaType']);
2153
+ const edmType = edmUtils.mapCdsToEdmType(obj.items.items, messageFunctions, _options.odataVersion === 'v2', obj['@Core.MediaType']);
2114
2154
  edmUtils.assignProp(obj, '_edmType', edmType);
2115
2155
  }
2116
2156
  }
2117
2157
 
2118
- function ComputedDefaultValue(member) {
2158
+ function ComputedDefaultValue( member ) {
2119
2159
  if (member.default && !csn['@Core.ComputedDefaultValue']) {
2120
2160
  let def = member.default;
2121
2161
  let noTailExpr = false;
2122
- if(def.xpr) {
2162
+ if (def.xpr) {
2123
2163
  let i = 0;
2124
2164
  // consume all unary signs
2125
- while(def.xpr[i] === '-' || def.xpr[i] === '+') i++;
2165
+ while (def.xpr[i] === '-' || def.xpr[i] === '+')
2166
+ i++;
2126
2167
  // noTailExpr is true if there is nothing behind the next token in the stream
2127
- noTailExpr = i < def.xpr.length-1;
2168
+ noTailExpr = i < def.xpr.length - 1;
2128
2169
  def = def.xpr[i];
2129
2170
  }
2130
2171
  // it is a computed value if it is not a simple value or an annotation
2131
- if(!((def.val !== undefined && !noTailExpr) || def['#'])) {
2172
+ if (!((def.val !== undefined && !noTailExpr) || def['#']))
2132
2173
  edmUtils.assignAnnotation(member, '@Core.ComputedDefaultValue', true);
2133
- }
2134
2174
  }
2135
2175
  }
2136
2176
  }
2137
2177
 
2138
2178
  module.exports = {
2139
2179
  initializeModel,
2140
- }
2180
+ };