@sap/cds-compiler 6.2.2 → 6.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/bin/cdsc.js +11 -4
  3. package/lib/api/options.js +1 -1
  4. package/lib/base/message-registry.js +36 -7
  5. package/lib/base/messages.js +11 -4
  6. package/lib/base/model.js +0 -1
  7. package/lib/checks/assocOutsideService.js +17 -30
  8. package/lib/checks/checkForTypes.js +0 -18
  9. package/lib/checks/checkPathsInStoredCalcElement.js +2 -1
  10. package/lib/checks/enricher.js +15 -3
  11. package/lib/checks/onConditions.js +2 -2
  12. package/lib/checks/queryNoDbArtifacts.js +16 -15
  13. package/lib/checks/types.js +1 -1
  14. package/lib/checks/utils.js +30 -6
  15. package/lib/checks/validator.js +36 -37
  16. package/lib/compiler/assert-consistency.js +1 -1
  17. package/lib/compiler/checks.js +47 -18
  18. package/lib/compiler/extend.js +1 -1
  19. package/lib/compiler/index.js +88 -6
  20. package/lib/compiler/populate.js +1 -1
  21. package/lib/compiler/resolve.js +7 -7
  22. package/lib/compiler/tweak-assocs.js +48 -25
  23. package/lib/edm/annotations/edmJson.js +19 -19
  24. package/lib/gen/BaseParser.js +1 -1
  25. package/lib/gen/CdlGrammar.checksum +1 -1
  26. package/lib/gen/CdlParser.js +384 -383
  27. package/lib/gen/Dictionary.json +0 -2
  28. package/lib/json/to-csn.js +3 -2
  29. package/lib/model/csnRefs.js +9 -4
  30. package/lib/model/csnUtils.js +67 -2
  31. package/lib/optionProcessor.js +2 -3
  32. package/lib/parsers/AstBuildingParser.js +12 -11
  33. package/lib/render/toCdl.js +10 -4
  34. package/lib/render/utils/common.js +4 -2
  35. package/lib/transform/db/assertUnique.js +2 -1
  36. package/lib/transform/db/associations.js +37 -1
  37. package/lib/transform/db/assocsToQueries/transformExists.js +21 -32
  38. package/lib/transform/db/assocsToQueries/utils.js +1 -1
  39. package/lib/transform/db/cdsPersistence.js +1 -1
  40. package/lib/transform/db/expansion.js +37 -36
  41. package/lib/transform/draft/db.js +20 -20
  42. package/lib/transform/draft/odata.js +38 -40
  43. package/lib/transform/effective/associations.js +1 -1
  44. package/lib/transform/effective/flattening.js +40 -47
  45. package/lib/transform/effective/main.js +6 -4
  46. package/lib/transform/forOdata.js +135 -115
  47. package/lib/transform/forRelationalDB.js +151 -142
  48. package/lib/transform/localized.js +116 -109
  49. package/lib/transform/odata/adaptAnnotationRefs.js +21 -16
  50. package/lib/transform/odata/createForeignKeys.js +73 -70
  51. package/lib/transform/odata/flattening.js +216 -200
  52. package/lib/transform/odata/foreignKeyRefsInXprAnnos.js +47 -45
  53. package/lib/transform/odata/toFinalBaseType.js +40 -39
  54. package/lib/transform/odata/typesExposure.js +151 -133
  55. package/lib/transform/odata/utils.js +7 -6
  56. package/lib/transform/parseExpr.js +165 -162
  57. package/lib/transform/transformUtils.js +184 -551
  58. package/lib/transform/translateAssocsToJoins.js +510 -571
  59. package/lib/transform/tupleExpansion.js +495 -0
  60. package/lib/transform/universalCsn/universalCsnEnricher.js +1 -0
  61. package/package.json +1 -1
  62. package/lib/base/cleanSymbols.js +0 -17
  63. package/lib/checks/nonexpandableStructured.js +0 -39
@@ -2,16 +2,17 @@
2
2
 
3
3
  const { isBetaEnabled } = require('../base/model');
4
4
  const transformUtils = require('./transformUtils');
5
- const { forEachDefinition,
6
- forEachMemberRecursively,
7
- applyTransformationsOnNonDictionary,
8
- getArtifactDatabaseNameOf,
9
- getElementDatabaseNameOf,
10
- getServiceNames,
11
- forEachGeneric,
12
- cardinality2str,
13
- getUtils
14
- } = require('../model/csnUtils');
5
+ const {
6
+ forEachDefinition,
7
+ forEachMemberRecursively,
8
+ applyTransformationsOnNonDictionary,
9
+ getArtifactDatabaseNameOf,
10
+ getElementDatabaseNameOf,
11
+ getServiceNames,
12
+ forEachGeneric,
13
+ cardinality2str,
14
+ getUtils,
15
+ } = require('../model/csnUtils');
15
16
  const { checkCSNVersion } = require('../json/csnVersion');
16
17
  const validate = require('../checks/validator');
17
18
  const { isArtifactInSomeService, isLocalizedArtifactInService } = require('./odata/utils');
@@ -20,7 +21,7 @@ const { timetrace } = require('../utils/timetrace');
20
21
  const enrichUniversalCsn = require('./universalCsn/universalCsnEnricher');
21
22
  const flattening = require('./odata/flattening');
22
23
  const createForeignKeyElements = require('./odata/createForeignKeys');
23
- const associations = require('./db/associations')
24
+ const associations = require('./db/associations');
24
25
  const expansion = require('./db/expansion');
25
26
  const generateDrafts = require('./draft/odata');
26
27
 
@@ -80,7 +81,9 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
80
81
  const csn = cloneFullCsn(inputModel, options);
81
82
  messageFunctions.setModel(csn);
82
83
 
83
- const { message, error, warning, info, throwWithAnyError } = messageFunctions;
84
+ const {
85
+ message, error, warning, info, throwWithAnyError,
86
+ } = messageFunctions;
84
87
  throwWithAnyError();
85
88
 
86
89
  // the new transformer works only with new CSN
@@ -116,9 +119,7 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
116
119
  // @ts-ignore
117
120
  const externalServices = services.filter(serviceName => csn.definitions[serviceName]['@cds.external']);
118
121
  // @ts-ignore
119
- const isExternalServiceMember = (art, name) => {
120
- return !!(externalServices.includes(getServiceName(name)) || (art && art['@cds.external']))
121
- }
122
+ const isExternalServiceMember = (art, name) => !!(externalServices.includes(getServiceName(name)) || (art && art['@cds.external']));
122
123
 
123
124
  if (options.csnFlavor === 'universal' && isBetaEnabled(options, 'enableUniversalCsn'))
124
125
  enrichUniversalCsn(csn, options);
@@ -141,13 +142,25 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
141
142
  // replace all type refs to builtin types with direct type
142
143
  transformUtils.rewriteBuiltinTypeRef(csn);
143
144
 
144
- // Rewrite paths in annotations only if beta modes are set
145
+ // Rewrite paths in annotations only if beta modes are set
145
146
 
146
147
  options.enrichAnnotations = true;
147
148
  const cleanup = validate.forOdata(csn, {
148
- message, error, warning, info, inspectRef, effectiveType, getFinalTypeInfo, artifactRef,
149
- options, csnUtils, services, isExternalServiceMember, recurseElements,
150
- checkMultipleAssignments, csn,
149
+ message,
150
+ error,
151
+ warning,
152
+ info,
153
+ inspectRef,
154
+ effectiveType,
155
+ getFinalTypeInfo,
156
+ artifactRef,
157
+ options,
158
+ csnUtils,
159
+ services,
160
+ isExternalServiceMember,
161
+ recurseElements,
162
+ checkMultipleAssignments,
163
+ csn,
151
164
  });
152
165
 
153
166
 
@@ -155,19 +168,22 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
155
168
  throwWithAnyError();
156
169
 
157
170
  // TODO: Refactor out the following logic
171
+ const hasProjection = new Set();
158
172
  forEachDefinition(csn, [
159
173
  (def) => {
160
174
  // Convert a projection into a query for internal processing will be re-converted
161
175
  // at the end of the OData processing
162
176
  // TODO: handle artifact.projection instead of artifact.query correctly in future V2
163
177
  if (def.kind === 'entity' && def.projection) {
178
+ hasProjection.add(def);
164
179
  def.query = { SELECT: def.projection };
180
+ delete def.projection;
165
181
  dropDefinitionCache(def);
166
182
  initDefinition(def);
167
183
  }
168
- }],
169
- { skipArtifact: isExternalServiceMember }
170
- );
184
+ },
185
+ ],
186
+ { skipArtifact: isExternalServiceMember });
171
187
 
172
188
  // All type refs must be resolved, including external APIs.
173
189
  // OData has no 'type of' so 'real' imported OData APIs marked @cds.external are safe.
@@ -181,13 +197,13 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
181
197
  // and expand these structured elements. This tuple expansion allows all other
182
198
  // subsequent procession steps (especially a2j) to see plain paths in expressions.
183
199
  // If errors are detected, throwWithAnyError() will return from further processing
184
- expandStructsInExpression(csn, { skipArtifact: isExternalServiceMember, drillRef: true });
200
+ expandStructsInExpression({ skipArtifact: isExternalServiceMember, drillRef: true });
185
201
 
186
202
  // do expansion before Fk creation because of messages reporting
187
203
  if (!structuredOData) {
188
204
  expansion.expandStructureReferences(csn, options, '_',
189
- { error, info, throwWithAnyError }, csnUtils,
190
- { skipArtifact: isExternalServiceMember, keepKeysOrigin: true });
205
+ { error, info, throwWithAnyError }, csnUtils,
206
+ { skipArtifact: isExternalServiceMember, keepKeysOrigin: true });
191
207
  }
192
208
 
193
209
  createForeignKeyElements(csn, options, messageFunctions, csnUtils, { skipArtifact: isExternalServiceMember });
@@ -202,34 +218,34 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
202
218
  const resolved = new WeakMap();
203
219
  const { inspectRef, effectiveType } = csnRefs(csn);
204
220
  const { getFinalTypeInfo } = getUtils(csn);
205
- const { adaptRefs, transformer: refFlattener } =
206
- flattening.getStructRefFlatteningTransformer(csn, inspectRef, effectiveType, options, resolved, '_');
221
+ const { adaptRefs, transformer: refFlattener }
222
+ = flattening.getStructRefFlatteningTransformer(csn, inspectRef, effectiveType, options, resolved, '_');
207
223
 
208
224
  const allMgdAssocDefs = flattening.allInOneFlattening(csn, refFlattener, adaptRefs,
209
- inspectRef, getFinalTypeInfo, isExternalServiceMember, error, csnUtils, options);
225
+ inspectRef, getFinalTypeInfo, isExternalServiceMember, error, csnUtils, options);
210
226
  flattening.flattenAllStructStepsInRefs(csn, refFlattener, adaptRefs,
211
- inspectRef, effectiveType, csnUtils, error, options,
212
- { //skip: ['action', 'aspect', 'event', 'function', 'type'],
213
- skipArtifact: isExternalServiceMember,
214
- });
227
+ inspectRef, effectiveType, csnUtils, error, options,
228
+ { // skip: ['action', 'aspect', 'event', 'function', 'type'],
229
+ skipArtifact: isExternalServiceMember,
230
+ });
215
231
  flattening.replaceManagedAssocsAsKeys(allMgdAssocDefs, csnUtils);
216
232
 
217
233
  // replace structured with flat dictionaries that contain
218
234
  // rewritten path expressions
219
235
  forEachDefinition(csn, (def) => {
220
- ['elements', 'params'].forEach(dictName => {
221
- if(def[`$flat${dictName}`])
222
- def[dictName] = def[`$flat${dictName}`];
223
- })
224
- if(def.$flatAnnotations) {
225
- Object.entries(def.$flatAnnotations).forEach(([an, av]) => {
236
+ [ 'elements', 'params' ].forEach((dictName) => {
237
+ if (def[`$flat${ dictName }`])
238
+ def[dictName] = def[`$flat${ dictName }`];
239
+ });
240
+ if (def.$flatAnnotations) {
241
+ Object.entries(def.$flatAnnotations).forEach(([ an, av ]) => {
226
242
  def[an] = av;
227
- })
243
+ });
228
244
  }
229
- if(def.actions) {
245
+ if (def.actions) {
230
246
  Object.values(def.actions).forEach((action) => {
231
- if(action.$flatAnnotations) {
232
- Object.entries(action.$flatAnnotations).forEach(([an, av]) => {
247
+ if (action.$flatAnnotations) {
248
+ Object.entries(action.$flatAnnotations).forEach(([ an, av ]) => {
233
249
  action[an] = av;
234
250
  });
235
251
  }
@@ -243,9 +259,9 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
243
259
  // Allow using managed associations as steps in on-conditions to access their fks
244
260
  // To be done after handleManagedAssociationsAndCreateForeignKeys,
245
261
  // since then the foreign keys of the managed assocs are part of the elements
246
- if(!structuredOData) {
247
- forEachDefinition(csn, associations.getFKAccessFinalizer(csn, csnUtils, '_'));
248
- }
262
+ if (!structuredOData)
263
+ forEachDefinition(csn, associations.getFKAccessFinalizer(csn, options, csnUtils, '_'));
264
+
249
265
 
250
266
  // structure flattener reports errors, further processing is not safe -> throw exception in case of errors
251
267
  throwWithAnyError();
@@ -270,7 +286,9 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
270
286
  // - Perform checks for exposed non-abstract entities and views - check media type and key-ness
271
287
 
272
288
  // Deal with all kind of annotations manipulations here
273
- const skipPersNameKinds = {'service':1, 'context':1, 'namespace':1, 'annotation':1, 'action':1, 'function':1};
289
+ const skipPersNameKinds = {
290
+ service: 1, context: 1, namespace: 1, annotation: 1, action: 1, function: 1,
291
+ };
274
292
  forEachDefinition(csn, (def, defName) => {
275
293
  // Resolve annotation shorthands for entities, types, annotations, ...
276
294
  renameShorthandAnnotations(def);
@@ -278,7 +296,7 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
278
296
  // Annotate artifacts with their DB names if requested.
279
297
  // Skip artifacts that have no DB equivalent anyway
280
298
  if (options.sqlMapping && !(def.kind in skipPersNameKinds))
281
- // hana to allow naming mode "hdbcds"
299
+ // hana to allow naming mode "hdbcds"
282
300
  def['@cds.persistence.name'] = getArtifactDatabaseNameOf(defName, options.sqlMapping, csn, 'hana');
283
301
 
284
302
  forEachMemberRecursively(def, (member, memberName, propertyName) => {
@@ -290,8 +308,8 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
290
308
  !(propertyName === 'enum' || propertyName === 'returns') &&
291
309
  (!member.virtual || def.query)) {
292
310
  // If we have a 'preserved dotted name' (i.e. we are a result of flattening), use that for the @cds.persistence.name annotation
293
- member['@cds.persistence.name'] = getElementDatabaseNameOf((!member['@odata.foreignKey4'] && member.$defPath?.slice(1).join('.'))
294
- || memberName, options.sqlMapping, 'hana'); // hana to allow "hdbcds"
311
+ member['@cds.persistence.name'] = getElementDatabaseNameOf((!member['@odata.foreignKey4'] && member.$defPath?.slice(1).join('.')) ||
312
+ memberName, options.sqlMapping, 'hana'); // hana to allow "hdbcds"
295
313
  }
296
314
 
297
315
  processDynamicFieldControlAnnotations(member);
@@ -319,18 +337,19 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
319
337
  // to the foreign keys is done very late in edmPreprocessor.initializeAssociation()
320
338
  addCommonValueListviaAssociation(member, memberName);
321
339
  }
322
- }, ['definitions', defName]);
340
+ }, [ 'definitions', defName ]);
323
341
 
324
342
  // Convert a query back into a projection for CSN compliance as
325
343
  // the very last conversion step of the OData transformation
326
- if (def.kind === 'entity' && def.query && def.projection) {
344
+ if (def.kind === 'entity' && hasProjection.has(def)) {
345
+ def.projection = def.query.SELECT;
327
346
  delete def.query;
328
347
  }
329
- }, { skipArtifact: isExternalServiceMember })
348
+ }, { skipArtifact: isExternalServiceMember });
330
349
 
331
- if(isBetaEnabled(options, 'odataTerms')) {
350
+ if (isBetaEnabled(options, 'odataTerms'))
332
351
  forEachGeneric(csn, 'vocabularies', renameShorthandAnnotations);
333
- }
352
+
334
353
 
335
354
  cleanup();
336
355
  // Throw exception in case of errors
@@ -344,16 +363,18 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
344
363
  // Transform @readonly/@mandatory/@disabled into @Common.FieldControl annotation
345
364
  // with a when/then/else expression consisting of the input from the annotations.
346
365
  function processDynamicFieldControlAnnotations(node) {
347
- if (node['@Common.FieldControl']) return;
366
+ if (node['@Common.FieldControl'])
367
+ return;
348
368
  // TODO (SO): factor this out into a constant so we don't create a fresh array all the time?
349
- if (['@readonly', '@mandatory', '@disabled'].some(key => typeof node[key] === 'boolean')) {
350
- return;
351
- }
369
+ if ([ '@readonly', '@mandatory', '@disabled' ].some(key => typeof node[key] === 'boolean'))
370
+ return;
371
+
352
372
 
353
- const definedAnnotations = ['@disabled', '@readonly', '@mandatory']
373
+ const definedAnnotations = [ '@disabled', '@readonly', '@mandatory' ]
354
374
  .filter(key => node[key] && isAnnotationExpression(node[key]));
355
-
356
- if (definedAnnotations.length === 0) return;
375
+
376
+ if (definedAnnotations.length === 0)
377
+ return;
357
378
 
358
379
  const values = {
359
380
  '@disabled': { val: 0 },
@@ -365,7 +386,7 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
365
386
  '=': true,
366
387
  xpr: createFieldControlExpression(definedAnnotations),
367
388
  };
368
-
389
+
369
390
  setAnnotation(node, '@Common.FieldControl', fieldControl);
370
391
 
371
392
  function createFieldControlExpression(annotations) {
@@ -380,12 +401,12 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
380
401
  const currentExpression = [
381
402
  'case',
382
403
  'when',
383
- ...(Array.isArray(xprInAnnoValue) ? xprInAnnoValue : [xprInAnnoValue]),
404
+ ...(Array.isArray(xprInAnnoValue) ? xprInAnnoValue : [ xprInAnnoValue ]),
384
405
  'then',
385
406
  annotationVal,
386
407
  'else',
387
- // Use the previous nested expression or default value. Note that annotations
388
- // are looped backwards
408
+ // Use the previous nested expression or default value. Note that annotations
409
+ // are looped backwards
389
410
  nestedExpression ? { xpr: nestedExpression } : { val: 3 },
390
411
  'end',
391
412
  ];
@@ -399,28 +420,28 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
399
420
  function getXprFromAnno(anno) {
400
421
  const xprProp = xprInAnnoProperties.find(prop => anno[prop] !== undefined);
401
422
  const constructResult = {
402
- 'ref': () => {
423
+ ref: () => {
403
424
  const result = { ref: anno.ref };
404
425
  if (anno.cast)
405
426
  result.cast = anno.cast;
406
427
  return result;
407
428
  },
408
- 'xpr': () => anno.xpr,
409
- 'list': () => ({ list: anno.list }),
410
- 'literal': () => constructResult['val'](),
411
- 'val': () => {
429
+ xpr: () => anno.xpr,
430
+ list: () => ({ list: anno.list }),
431
+ literal: () => constructResult.val(),
432
+ val: () => {
412
433
  const result = { val: anno.val };
413
434
  if (anno.literal)
414
435
  result.literal = anno.literal;
415
436
  return result;
416
437
  },
417
438
  '#': () => ({ '#': anno['#'] }),
418
- 'func': () => ({ func: anno.func }),
419
- 'args': () => ({ args: anno.args }),
420
- 'SELECT': () => ({ SELECT: anno.SELECT }),
421
- 'SET': () => ({ SET: anno.SET }),
422
- 'cast': () => constructResult['ref']()
423
- }
439
+ func: () => ({ func: anno.func }),
440
+ args: () => ({ args: anno.args }),
441
+ SELECT: () => ({ SELECT: anno.SELECT }),
442
+ SET: () => ({ SET: anno.SET }),
443
+ cast: () => constructResult.ref(),
444
+ };
424
445
  return constructResult[xprProp]();
425
446
  }
426
447
  }
@@ -428,11 +449,12 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
428
449
  // Mark elements that are annotated with @odata.on.insert/update with the annotation @Core.Computed.
429
450
  function annotateCoreComputed(node) {
430
451
  // If @Core.Computed is explicitly set, don't overwrite it!
431
- if (node['@Core.Computed'] !== undefined) return;
452
+ if (node['@Core.Computed'] !== undefined)
453
+ return;
432
454
 
433
455
  // For @odata.on.insert/update, also add @Core.Computed
434
456
  // @odata.on is deprecated, use @cds.on {update|insert} instead
435
- if(['@odata.on.insert', '@odata.on.update', '@cds.on.insert', '@cds.on.update'].some(a => node[a]))
457
+ if ([ '@odata.on.insert', '@odata.on.update', '@cds.on.insert', '@cds.on.update' ].some(a => node[a]))
436
458
  node['@Core.Computed'] = true;
437
459
  }
438
460
 
@@ -445,37 +467,36 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
445
467
  };
446
468
  const renameMappings = {
447
469
  '@ValueList.entity': { val: '@Common.ValueList', op: 'entity' },
448
- '@ValueList.type': { val: '@Common.ValueList', op: 'type' },
470
+ '@ValueList.type': { val: '@Common.ValueList', op: 'type' },
449
471
  '@Capabilities.Deletable': { val: '@Capabilities.DeleteRestrictions', op: 'Deletable' },
450
472
  '@Capabilities.Insertable': { val: '@Capabilities.InsertRestrictions', op: 'Insertable' },
451
473
  '@Capabilities.Updatable': { val: '@Capabilities.UpdateRestrictions', op: 'Updatable' },
452
- '@Capabilities.Readable': { val: '@Capabilities.ReadRestrictions', op: 'Readable' }
474
+ '@Capabilities.Readable': { val: '@Capabilities.ReadRestrictions', op: 'Readable' },
453
475
  };
454
476
 
455
477
  const setShortCuts = Object.keys(setMappings);
456
478
  const renameShortCuts = Object.keys(renameMappings);
457
479
 
458
480
  // Capabilities shortcuts have precedence over @readonly/@insertonly
459
- Object.keys(node).forEach( name => {
481
+ Object.keys(node).forEach( (name) => {
460
482
  if (!name.startsWith('@'))
461
483
  return;
462
484
  // Rename according to map above
463
485
  const renamePrefix = (name in renameMappings)
464
486
  ? name
465
- : renameShortCuts.find(p => name.startsWith(p + '.'));
466
- if(renamePrefix) {
487
+ : renameShortCuts.find(p => name.startsWith(`${ p }.`));
488
+ if (renamePrefix) {
467
489
  const mapping = renameMappings[renamePrefix];
468
- renameAnnotation(node, name, name.replace(renamePrefix, `${mapping.val}.${mapping.op}`));
490
+ renameAnnotation(node, name, name.replace(renamePrefix, `${ mapping.val }.${ mapping.op }`));
469
491
  }
470
492
  else {
471
493
  // The two mappings have no overlap, so no need to check for second map if first matched.
472
494
  // Rename according to map above
473
495
  const setPrefix = (name in setMappings)
474
496
  ? name
475
- : setShortCuts.find(p => name.startsWith(p + '.') || name.startsWith(p + '#'));
476
- if(setPrefix) {
497
+ : setShortCuts.find(p => name.startsWith(`${ p }.`) || name.startsWith(`${ p }#`));
498
+ if (setPrefix)
477
499
  setAnnotation(node, name.replace(setPrefix, setMappings[setPrefix]), node[name]);
478
- }
479
500
  }
480
501
  });
481
502
 
@@ -483,14 +504,16 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
483
504
  // but '@Core.Computed' for everything else.
484
505
 
485
506
  // only if not both readonly/insertonly are true do the mapping
486
- if(!(node['@readonly'] && node['@insertonly'])) {
487
- if(node['@readonly']) {
507
+ if (!(node['@readonly'] && node['@insertonly'])) {
508
+ if (node['@readonly']) {
488
509
  const setRO = (qualifier) => {
489
510
  if (node.kind === 'entity' || node.kind === 'aspect') {
490
- setAnnotation(node, `@Capabilities.DeleteRestrictions${ qualifier ? '#' + qualifier : ''}.Deletable`, false);
491
- setAnnotation(node, `@Capabilities.InsertRestrictions${ qualifier ? '#' + qualifier : ''}.Insertable`, false);
492
- setAnnotation(node, `@Capabilities.UpdateRestrictions${ qualifier ? '#' + qualifier : ''}.Updatable`, false);
493
- } else if (!isAnnotationExpression(node['@readonly'])) {
511
+ const qualifierStr = qualifier ? `#${ qualifier }` : '';
512
+ setAnnotation(node, `@Capabilities.DeleteRestrictions${ qualifierStr }.Deletable`, false);
513
+ setAnnotation(node, `@Capabilities.InsertRestrictions${ qualifierStr }.Insertable`, false);
514
+ setAnnotation(node, `@Capabilities.UpdateRestrictions${ qualifierStr }.Updatable`, false);
515
+ }
516
+ else if (!isAnnotationExpression(node['@readonly'])) {
494
517
  // add @Core.Computed only for non-xpr values of @readonly
495
518
  setAnnotation(node, '@Core.Computed', true);
496
519
  }
@@ -500,10 +523,11 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
500
523
  // @insertonly is effective on entities/queries only
501
524
  if (node['@insertonly'] && (node.kind === 'entity' || node.kind === 'aspect')) {
502
525
  const setIO = (qualifier) => {
503
- setAnnotation(node, `@Capabilities.DeleteRestrictions${ qualifier ? '#' + qualifier : ''}.Deletable`, false);
504
- setAnnotation(node, `@Capabilities.ReadRestrictions${ qualifier ? '#' + qualifier : ''}.Readable`, false);
505
- setAnnotation(node, `@Capabilities.UpdateRestrictions${ qualifier ? '#' + qualifier : ''}.Updatable`, false);
506
- }
526
+ const qualifierStr = qualifier ? `#${ qualifier }` : '';
527
+ setAnnotation(node, `@Capabilities.DeleteRestrictions${ qualifierStr }.Deletable`, false);
528
+ setAnnotation(node, `@Capabilities.ReadRestrictions${ qualifierStr }.Readable`, false);
529
+ setAnnotation(node, `@Capabilities.UpdateRestrictions${ qualifierStr }.Updatable`, false);
530
+ };
507
531
  setIO(undefined);
508
532
  }
509
533
  }
@@ -513,11 +537,11 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
513
537
  setAnnotation(node, '@Validation.Pattern', node['@assert.format']);
514
538
 
515
539
  // Only on element level
516
- if(node.kind == null) {
517
- if (node['@mandatory'] && !isAnnotationExpression(node['@mandatory'])
518
- && !Object.entries(node).some(([k,v]) => k === '@Common.FieldControl' || k.startsWith('@Common.FieldControl.') && v != null)) {
540
+ if (node.kind == null) {
541
+ if (node['@mandatory'] && !isAnnotationExpression(node['@mandatory']) &&
542
+ !Object.entries(node).some(([ k, v ]) => k === '@Common.FieldControl' || k.startsWith('@Common.FieldControl.') && v != null))
519
543
  setAnnotation(node, '@Common.FieldControl', { '#': 'Mandatory' });
520
- }
544
+
521
545
  if (node['@assert.range'] != null)
522
546
  setAssertRangeAnnotation(node);
523
547
  }
@@ -527,7 +551,7 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
527
551
  function setAssertRangeAnnotation(node) {
528
552
  const range = node['@assert.range'];
529
553
  if (!Array.isArray(range) || range.length !== 2)
530
- return; // TODO: Warning for wrong format?
554
+ return; // TODO: Warning for wrong format?
531
555
 
532
556
  const min = range[0];
533
557
  const max = range[1];
@@ -539,7 +563,7 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
539
563
  // via `@assert.range: [ _, _ ]`.
540
564
  // For `_`, minVal is an object and this function returns false, which is ok,
541
565
  // since we don't render the annotation for "infinite" values.
542
- const shouldSet = (val) => (typeof val !== 'object' && val !== undefined && val !== null);
566
+ const shouldSet = val => (typeof val !== 'object' && val !== undefined && val !== null);
543
567
 
544
568
  if (shouldSet(minVal)) {
545
569
  setAnnotation(node, '@Validation.Minimum', minVal);
@@ -551,7 +575,6 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
551
575
  if (max['='] !== undefined)
552
576
  setAnnotation(node, '@Validation.Maximum.@Validation.Exclusive', true);
553
577
  }
554
-
555
578
  }
556
579
 
557
580
  // If an association was modelled as not null, like so:
@@ -578,30 +601,30 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
578
601
  // Apply default type facets to each type definition and every member
579
602
  // But do not apply default string length (as in DB)
580
603
  function setDefaultTypeFacets(def) {
581
- addDefaultTypeFacets(def.items || def, null)
582
- forEachMemberRecursively(def, m=>addDefaultTypeFacets(m.items || m, null));
583
- if(def.returns)
604
+ addDefaultTypeFacets(def.items || def, null);
605
+ forEachMemberRecursively(def, m => addDefaultTypeFacets(m.items || m, null));
606
+ if (def.returns)
584
607
  addDefaultTypeFacets(def.returns.items || def.returns, null);
585
608
  }
586
609
 
587
610
  // Handles on-conditions in unmanaged associations
588
611
  function processOnCond(def) {
589
612
  forEachMemberRecursively(def, (member) => {
590
- if (member.on && isAssocOrComposition(member)) {
613
+ if (member.on && isAssocOrComposition(member))
591
614
  removeLeadingDollarSelfInOnCondition(member);
592
- }
593
615
  });
594
616
 
595
617
  // removes leading $self in on-conditions's references
596
618
  function removeLeadingDollarSelfInOnCondition(assoc) {
597
- if (!assoc.on) return; // nothing to do
619
+ if (!assoc.on)
620
+ return; // nothing to do
598
621
  // TODO: Shouldn't this only run on the on-condition and not the whole assoc-node?
599
622
  applyTransformationsOnNonDictionary({ assoc }, 'assoc', {
600
623
  ref: (node, prop, ref) => {
601
624
  // remove leading $self when at the beginning of a ref
602
625
  if (ref.length > 1 && ref[0] === '$self')
603
626
  node.ref.splice(0, 1);
604
- }
627
+ },
605
628
  });
606
629
  }
607
630
  }
@@ -616,9 +639,8 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
616
639
  if (isAssociation(member)) {
617
640
  const navigable = member['@odata.navigable'] !== false; // navigable disabled only if explicitly set to false
618
641
  const targetDef = getCsnDef(member.target);
619
- if (navigable && targetDef['@cds.odata.valuelist'] && !member[vlAnno]) {
642
+ if (navigable && targetDef['@cds.odata.valuelist'] && !member[vlAnno])
620
643
  setAnnotation(member, vlAnno, { '=': memberName });
621
- }
622
644
  }
623
645
  }
624
646
 
@@ -627,6 +649,4 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
627
649
  const csnRefApi = csnRefs(csn);
628
650
  Object.assign(csnUtils, csnRefApi);
629
651
  }
630
-
631
-
632
652
  } // transform4odataWithCsn