@sap/cds-compiler 6.1.0 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/bin/cdsc.js +17 -6
  3. package/bin/cdsse.js +1 -1
  4. package/bin/cdsv2m.js +1 -1
  5. package/lib/api/main.js +29 -7
  6. package/lib/api/options.js +1 -1
  7. package/lib/base/builtins.js +9 -0
  8. package/lib/base/keywords.js +1 -1
  9. package/lib/base/message-registry.js +41 -10
  10. package/lib/base/messages.js +13 -6
  11. package/lib/base/model.js +1 -1
  12. package/lib/base/optionProcessorHelper.js +7 -2
  13. package/lib/checks/assocOutsideService.js +17 -30
  14. package/lib/checks/checkForTypes.js +0 -18
  15. package/lib/checks/checkPathsInStoredCalcElement.js +2 -1
  16. package/lib/checks/featureFlags.js +4 -1
  17. package/lib/checks/onConditions.js +2 -2
  18. package/lib/checks/queryNoDbArtifacts.js +16 -15
  19. package/lib/checks/types.js +1 -1
  20. package/lib/checks/utils.js +30 -6
  21. package/lib/checks/validator.js +4 -5
  22. package/lib/compiler/assert-consistency.js +3 -1
  23. package/lib/compiler/base.js +1 -1
  24. package/lib/compiler/builtins.js +1 -1
  25. package/lib/compiler/checks.js +85 -39
  26. package/lib/compiler/define.js +24 -5
  27. package/lib/compiler/extend.js +1 -1
  28. package/lib/compiler/finalize-parse-cdl.js +9 -1
  29. package/lib/compiler/generate.js +4 -4
  30. package/lib/compiler/index.js +88 -6
  31. package/lib/compiler/lsp-api.js +2 -0
  32. package/lib/compiler/populate.js +8 -8
  33. package/lib/compiler/propagator.js +1 -1
  34. package/lib/compiler/resolve.js +22 -21
  35. package/lib/compiler/shared.js +6 -6
  36. package/lib/compiler/tweak-assocs.js +53 -31
  37. package/lib/compiler/utils.js +9 -16
  38. package/lib/compiler/xpr-rewrite.js +2 -2
  39. package/lib/gen/BaseParser.js +35 -29
  40. package/lib/gen/CdlGrammar.checksum +1 -1
  41. package/lib/gen/CdlParser.js +1424 -1430
  42. package/lib/gen/Dictionary.json +1 -2
  43. package/lib/gen/cdlKeywords.json +26 -0
  44. package/lib/inspect/inspectPropagation.js +1 -1
  45. package/lib/json/from-csn.js +2 -2
  46. package/lib/json/to-csn.js +1 -1
  47. package/lib/language/multiLineStringParser.js +1 -1
  48. package/lib/model/cloneCsn.js +1 -0
  49. package/lib/model/csnRefs.js +9 -4
  50. package/lib/model/csnUtils.js +67 -2
  51. package/lib/optionProcessor.js +9 -9
  52. package/lib/parsers/AstBuildingParser.js +28 -26
  53. package/lib/parsers/identifiers.js +2 -30
  54. package/lib/render/toCdl.js +73 -13
  55. package/lib/render/toSql.js +127 -108
  56. package/lib/render/utils/common.js +4 -2
  57. package/lib/render/utils/sql.js +67 -0
  58. package/lib/transform/addTenantFields.js +4 -4
  59. package/lib/transform/db/assertUnique.js +2 -1
  60. package/lib/transform/db/associations.js +37 -1
  61. package/lib/transform/db/assocsToQueries/transformExists.js +21 -32
  62. package/lib/transform/db/assocsToQueries/utils.js +1 -1
  63. package/lib/transform/db/cdsPersistence.js +1 -1
  64. package/lib/transform/db/expansion.js +37 -36
  65. package/lib/transform/db/killAnnotations.js +1 -0
  66. package/lib/transform/db/processSqlServices.js +20 -2
  67. package/lib/transform/draft/db.js +20 -20
  68. package/lib/transform/draft/odata.js +38 -40
  69. package/lib/transform/effective/associations.js +1 -1
  70. package/lib/transform/effective/flattening.js +40 -47
  71. package/lib/transform/effective/main.js +6 -4
  72. package/lib/transform/forOdata.js +201 -92
  73. package/lib/transform/forRelationalDB.js +151 -142
  74. package/lib/transform/localized.js +116 -109
  75. package/lib/transform/odata/adaptAnnotationRefs.js +21 -16
  76. package/lib/transform/odata/createForeignKeys.js +73 -70
  77. package/lib/transform/odata/flattening.js +216 -200
  78. package/lib/transform/odata/foreignKeyRefsInXprAnnos.js +47 -45
  79. package/lib/transform/odata/toFinalBaseType.js +40 -39
  80. package/lib/transform/odata/typesExposure.js +151 -133
  81. package/lib/transform/odata/utils.js +7 -6
  82. package/lib/transform/parseExpr.js +165 -162
  83. package/lib/transform/transformUtils.js +184 -551
  84. package/lib/transform/translateAssocsToJoins.js +511 -596
  85. package/lib/transform/tupleExpansion.js +495 -0
  86. package/lib/transform/universalCsn/universalCsnEnricher.js +1 -0
  87. package/lib/utils/moduleResolve.js +1 -1
  88. package/package.json +2 -2
  89. package/lib/base/cleanSymbols.js +0 -17
  90. package/lib/checks/nonexpandableStructured.js +0 -39
@@ -3,7 +3,6 @@
3
3
  const { makeMessageFunction } = require('../base/messages');
4
4
  const { setProp } = require('../base/model');
5
5
  const { forEachKey } = require('../utils/objectUtils');
6
- const { cleanSymbols } = require('../base/cleanSymbols.js');
7
6
  const {
8
7
  applyAnnotationsFromExtensions,
9
8
  forEachDefinition,
@@ -15,29 +14,9 @@ const {
15
14
  cloneCsnDict,
16
15
  cloneCsnNonDict,
17
16
  sortCsnDefinitionsForTests,
18
- sortCsn
17
+ sortCsn,
19
18
  } = require('../model/cloneCsn');
20
19
 
21
- /**
22
- * Indicator that a definition is localized and has a convenience view.
23
- * art[_hasLocalizedView]'s value should be the name of the convenience view.
24
- */
25
- const _hasLocalizedView = Symbol('_hasLocalizedView');
26
- /**
27
- * Whether a convenience view was generated for another view.
28
- * In that case we have a _vertical_ view.
29
- */
30
- const _isViewForView = Symbol('_isViewForView'); // $inferred = 'LOCALIZED-VERTICAL'
31
- /**
32
- * Whether a convenience view was generated for an entity that is localized.
33
- * In that case we have a _horizontal_ view.
34
- */
35
- const _isViewForEntity = Symbol('_isViewForEntity'); // $inferred = 'LOCALIZED-HORIZONTAL'
36
- /**
37
- * List of artifacts for which the view/entity is a target.
38
- * Used to transitively create convenience views.
39
- */
40
- const _targetFor = Symbol('_targetFor');
41
20
  const annoPersistenceSkip = '@cds.persistence.skip';
42
21
 
43
22
  /**
@@ -50,8 +29,10 @@ const annoPersistenceSkip = '@cds.persistence.skip';
50
29
  /**
51
30
  * Create transitive localized convenience views.
52
31
  *
53
- * A convenience view is created if the entity/view has a localized element[^1]
54
- * or if it exposes an association leading to a localized-tagged target.
32
+ * A convenience view is created if (a) the entity/view has a localized element[^1]
33
+ * or (b) if it exposes an association leading to a localized-tagged target.
34
+ * The second part (b) is only performed if option `fewerLocalizedViews` is
35
+ * disabled.
55
36
  *
56
37
  * INTERNALS:
57
38
  * We have three kinds of localized convenience views:
@@ -120,9 +101,33 @@ function _addLocalizationViews(csn, options, config) {
120
101
  // default is true, hence only check for explicitly disabled option
121
102
  const ignoreAssocToLocalized = options.fewerLocalizedViews !== false;
122
103
 
104
+ /**
105
+ * Indicator that a definition is localized and has a convenience view.
106
+ * localizedViewsFor[name]'s value should be the name of the convenience view.
107
+ * @type {Record<string, string>}
108
+ */
109
+ const localizedViewFor = Object.create(null);
110
+ /**
111
+ * Whether a convenience view was generated for another view.
112
+ * In that case we have a _vertical_ view.
113
+ * @type {Record<string, boolean>}
114
+ */
115
+ const createdForView = Object.create(null); // $inferred = 'LOCALIZED-VERTICAL'
116
+ /**
117
+ * Whether a convenience view was generated for an entity that is localized.
118
+ * In that case we have a _horizontal_ view.
119
+ * @type {Record<string, boolean>}
120
+ */
121
+ const createdForEntity = Object.create(null); // $inferred = 'LOCALIZED-HORIZONTAL'
122
+ /**
123
+ * List of artifacts for which the view/entity is a target.
124
+ * Used to transitively create convenience views.
125
+ * @type {Record<string, string[]>}
126
+ */
127
+ const targetFor = Object.create(null);
128
+
123
129
  createDirectConvenienceViews(); // 1
124
130
  createTransitiveConvenienceViews(); // 2 + 3
125
- cleanDefinitionSymbols();
126
131
  applyAnnotationsForLocalizedViews();
127
132
  sortLocalizedForTests(csn, options);
128
133
  messageFunctions.throwWithError();
@@ -169,16 +174,16 @@ function _addLocalizationViews(csn, options, config) {
169
174
  return;
170
175
  }
171
176
 
172
- art[_hasLocalizedView] = viewName;
177
+ localizedViewFor[artName] = viewName;
173
178
 
174
179
  if (acceptLocalizedView && !acceptLocalizedView(viewName, artName))
175
180
  return;
176
181
 
177
182
  let view;
178
183
  if (art.query || art.projection)
179
- view = createLocalizedViewForView(art);
184
+ view = createLocalizedViewForView(art, viewName);
180
185
  else
181
- view = createLocalizedViewForEntity(art, artName, textElements);
186
+ view = createLocalizedViewForEntity(art, artName, viewName, textElements);
182
187
 
183
188
  copyPersistenceAnnotations(view, art);
184
189
  csn.definitions[viewName] = view;
@@ -191,10 +196,11 @@ function _addLocalizationViews(csn, options, config) {
191
196
  *
192
197
  * @param {CSN.Definition} entity
193
198
  * @param {string} entityName
199
+ * @param {string} viewName Name of the localized view.
194
200
  * @param {string[]} [textElements]
195
201
  * @returns {CSN.View}
196
202
  */
197
- function createLocalizedViewForEntity( entity, entityName, textElements = [] ) {
203
+ function createLocalizedViewForEntity( entity, entityName, viewName, textElements = [] ) {
198
204
  // Only use joins if requested and text elements are provided.
199
205
  const shouldUseJoin = useJoins && !!textElements.length;
200
206
  const columns = [ ];
@@ -209,14 +215,14 @@ function _addLocalizationViews(csn, options, config) {
209
215
  },
210
216
  },
211
217
  elements: cloneCsnDict(entity.elements, options),
212
- [_isViewForEntity]: true,
213
218
  };
214
219
  copyLocation(convenienceView, entity);
215
220
  copyLocation(convenienceView.query, entity);
221
+ createdForEntity[viewName] = true;
216
222
 
217
223
  if (shouldUseJoin)
218
224
  // Expand elements; (variant 1)
219
- columns.push( ...columnsForEntityWithExcludeList( entity, 'L_0', textElements ) )
225
+ columns.push( ...columnsForEntityWithExcludeList( entity, 'L_0', textElements ) );
220
226
  else
221
227
  columns.push( '*' ); // (variant 2)
222
228
 
@@ -235,11 +241,9 @@ function _addLocalizationViews(csn, options, config) {
235
241
 
236
242
  return convenienceView;
237
243
 
238
-
239
244
  function createFromClauseForEntity() {
240
- if (!shouldUseJoin) {
245
+ if (!shouldUseJoin)
241
246
  return createColumnRef( [ entityName ], 'L');
242
- }
243
247
 
244
248
  const from = {
245
249
  join: 'left',
@@ -247,7 +251,7 @@ function _addLocalizationViews(csn, options, config) {
247
251
  createColumnRef( [ entityName ], 'L_0'),
248
252
  createColumnRef( [ textsEntityName(entityName) ], 'localized_1' ),
249
253
  ],
250
- on: []
254
+ on: [],
251
255
  };
252
256
 
253
257
  for (const originalElement of textElements) {
@@ -266,37 +270,37 @@ function _addLocalizationViews(csn, options, config) {
266
270
 
267
271
  return from;
268
272
  }
269
-
270
273
  }
271
274
 
272
275
  /**
273
- * Create a localized convenience view for the given definition `view`.
276
+ * Create a localized convenience view for the given definition `art`.
274
277
  * Does _not_ rewrite references.
275
278
  *
276
- * @param {CSN.Definition} view
279
+ * @param {CSN.Definition} art View for which a convenience view should be created.
280
+ * @param {string} viewName Name of the to-be created convenience view.
277
281
  * @returns {CSN.View}
278
282
  */
279
- function createLocalizedViewForView( view ) {
283
+ function createLocalizedViewForView( art, viewName ) {
280
284
  const convenienceView = {
281
285
  kind: 'entity',
282
- '@odata.draft.enabled': false
286
+ '@odata.draft.enabled': false,
283
287
  };
284
288
 
285
- if (view.query)
286
- convenienceView.query = cloneCsnNonDict(view.query, options);
287
- else if (view.projection)
288
- convenienceView.projection = cloneCsnNonDict(view.projection, options);
289
+ if (art.query)
290
+ convenienceView.query = cloneCsnNonDict(art.query, options);
291
+ else if (art.projection)
292
+ convenienceView.projection = cloneCsnNonDict(art.projection, options);
289
293
 
290
- convenienceView.elements = cloneCsnDict(view.elements, options);
291
- convenienceView[_isViewForView] = true;
292
- copyLocation(convenienceView, view);
294
+ convenienceView.elements = cloneCsnDict(art.elements, options);
295
+ createdForView[viewName] = true;
296
+ copyLocation(convenienceView, art);
293
297
 
294
298
  Object.keys(convenienceView.elements).forEach((elemName) => {
295
299
  addCoreComputedIfNecessary(convenienceView.elements, elemName);
296
300
  });
297
301
 
298
- if (view.params)
299
- convenienceView.params = cloneCsnDict(view.params, options);
302
+ if (art.params)
303
+ convenienceView.params = cloneCsnDict(art.params, options);
300
304
 
301
305
  return convenienceView;
302
306
  }
@@ -309,14 +313,14 @@ function _addLocalizationViews(csn, options, config) {
309
313
  const mainName = shouldUseJoins ? 'L_0' : 'L';
310
314
  const localizedNames = shouldUseJoins ? [ 'localized_1' ] : [ 'L', 'localized' ];
311
315
 
312
- if (noCoalesce) {
313
- return createColumnRef( [...localizedNames, elementName], elementName );
314
- }
316
+ if (noCoalesce)
317
+ return createColumnRef( [ ...localizedNames, elementName ], elementName );
318
+
315
319
 
316
320
  return {
317
321
  func: 'coalesce',
318
322
  args: [
319
- createColumnRef( [ ...localizedNames, elementName] ),
323
+ createColumnRef( [ ...localizedNames, elementName ] ),
320
324
  createColumnRef( [ mainName, elementName ] ),
321
325
  ],
322
326
  as: elementName,
@@ -366,7 +370,7 @@ function _addLocalizationViews(csn, options, config) {
366
370
  let keyCount = 0;
367
371
  let textElements = [];
368
372
 
369
- forEachGeneric(art, 'elements', (elem, elemName , _prop) => {
373
+ forEachGeneric(art, 'elements', (elem, elemName, _prop) => {
370
374
  if (elem.$ignore) // from SAP HANA backend
371
375
  return;
372
376
 
@@ -382,8 +386,10 @@ function _addLocalizationViews(csn, options, config) {
382
386
  return null;
383
387
 
384
388
  if (!isEntityPreprocessed( art )) {
385
- messageFunctions.info( null, artPath, { name: artName },
386
- 'Skipped creation of convenience view for $(NAME) because the artifact is missing localization elements' );
389
+ messageFunctions.info(
390
+ null, artPath, { name: artName },
391
+ 'Skipped creation of convenience view for $(NAME) because the artifact is missing localization elements'
392
+ );
387
393
  return null;
388
394
  }
389
395
 
@@ -391,18 +397,24 @@ function _addLocalizationViews(csn, options, config) {
391
397
  const textsEntity = csn.definitions[textsName];
392
398
 
393
399
  if (!textsEntity) {
394
- messageFunctions.info( null, artPath, { name: artName },
395
- 'Skipped creation of convenience view for $(NAME) because its texts entity could not be found' );
400
+ messageFunctions.info(
401
+ null, artPath, { name: artName },
402
+ 'Skipped creation of convenience view for $(NAME) because its texts entity could not be found'
403
+ );
396
404
  return null;
397
405
  }
398
406
  if (!isValidTextsEntity( textsEntity )) {
399
- messageFunctions.info( null, [ 'definitions', textsName ], { name: artName },
400
- 'Skipped creation of convenience view for $(NAME) because its texts entity does not appear to be valid' );
407
+ messageFunctions.info(
408
+ null, [ 'definitions', textsName ], { name: artName },
409
+ 'Skipped creation of convenience view for $(NAME) because its texts entity does not appear to be valid'
410
+ );
401
411
  return null;
402
412
  }
403
413
  if (!art[annoPersistenceSkip] && textsEntity[annoPersistenceSkip]) {
404
- messageFunctions.message( 'anno-unexpected-localized-skip', artPath,
405
- { name: textsName, art: artName, anno: annoPersistenceSkip } );
414
+ messageFunctions.message(
415
+ 'anno-unexpected-localized-skip', artPath,
416
+ { name: textsName, art: artName, anno: annoPersistenceSkip }
417
+ );
406
418
  return null;
407
419
  }
408
420
 
@@ -433,7 +445,7 @@ function _addLocalizationViews(csn, options, config) {
433
445
  *
434
446
  * 1. For each view with elements that have `localized: true` markers:
435
447
  * => add view to array `entities`
436
- * For each view/entity with associations:
448
+ * For each view/entity with associations (if fewerLocalizedViews is false):
437
449
  * - If target is NOT localized => add view/entity to target's `_targetFor` property
438
450
  * - If target is localized => add view/entity to array `entities`
439
451
  * 2. As long as `entities` has entries:
@@ -465,7 +477,7 @@ function _addLocalizationViews(csn, options, config) {
465
477
  if (isInLocalizedNamespace(artName))
466
478
  // Ignore existing `localized.` views.
467
479
  return;
468
- if (art[_hasLocalizedView])
480
+ if (localizedViewFor[artName])
469
481
  // Entity already has a convenience view.
470
482
  return;
471
483
 
@@ -486,11 +498,12 @@ function _addLocalizationViews(csn, options, config) {
486
498
  }
487
499
  else if (!ignoreAssocToLocalized && elem.target) {
488
500
  // If the target has a localized view then we are localized as well.
501
+ // Only necessary if "fewerLocalizedView" is disabled.
489
502
  const def = csn.definitions[elem.target];
490
503
  if (!def)
491
504
  continue;
492
505
 
493
- if (def[_hasLocalizedView]) {
506
+ if (localizedViewFor[elem.target]) {
494
507
  // The target may already be localized and if so, then add the artifact
495
508
  // to the to-be-processed entities.
496
509
  entities.push(artName);
@@ -498,12 +511,11 @@ function _addLocalizationViews(csn, options, config) {
498
511
  else {
499
512
  // Otherwise the target view may become localized at a later point so
500
513
  // we should add it to a reverse-dependency list.
501
- if (!def[_targetFor])
502
- def[_targetFor] = [];
503
- def[_targetFor].push(artName);
514
+ targetFor[elem.target] ??= [];
515
+ targetFor[elem.target].push(artName);
504
516
  }
505
-
506
- } else {
517
+ }
518
+ else {
507
519
  // recursive check
508
520
  _collectFromElements(elem.elements);
509
521
  }
@@ -518,16 +530,16 @@ function _addLocalizationViews(csn, options, config) {
518
530
  * @param {string} artName
519
531
  */
520
532
  function createViewAndCollectSources( artName ) {
521
- const art = csn.definitions[artName];
522
- if (art[_hasLocalizedView])
533
+ if (localizedViewFor[artName]) {
523
534
  // view/entity was already processed
524
535
  return;
536
+ }
525
537
 
526
538
  addLocalizedView(artName);
527
539
 
528
- if (!ignoreAssocToLocalized && art[_targetFor])
529
- nextEntities.push(...art[_targetFor]);
530
- delete art[_targetFor];
540
+ if (!ignoreAssocToLocalized && targetFor[artName])
541
+ nextEntities.push(...targetFor[artName]);
542
+ delete targetFor[artName];
531
543
  }
532
544
  }
533
545
 
@@ -538,12 +550,12 @@ function _addLocalizationViews(csn, options, config) {
538
550
  * @param {string} artName
539
551
  */
540
552
  function rewriteToLocalized( art, artName ) {
541
- if (art[_isViewForEntity]) {
553
+ if (createdForEntity[artName]) {
542
554
  // For entity convenience views only references in elements need to be rewritten.
543
555
  // a.k.a 'LOCALIZED-HORIZONTAL'
544
556
  forEachGeneric(art, 'elements', elem => rewriteDirectRefPropsToLocalized(elem));
545
557
  }
546
- else if (art[_isViewForView]) {
558
+ else if (createdForView[artName]) {
547
559
  // For view convenience views (i.e. transitive views) we need to rewrite `from`
548
560
  // references as well as need to handle `mixin` elements.
549
561
  // a.k.a 'LOCALIZED-VERTICAL'
@@ -597,8 +609,8 @@ function _addLocalizationViews(csn, options, config) {
597
609
  }
598
610
  else if (typeof val === 'string') {
599
611
  const def = csn.definitions[val];
600
- if (def && def[_hasLocalizedView])
601
- obj[prop] = def[_hasLocalizedView];
612
+ if (def && localizedViewFor[val])
613
+ obj[prop] = localizedViewFor[val];
602
614
  }
603
615
  }
604
616
  }
@@ -614,20 +626,18 @@ function _addLocalizationViews(csn, options, config) {
614
626
  return;
615
627
  const ref = Array.isArray(obj.ref) ? obj.ref[0] : obj.ref;
616
628
  if (typeof ref === 'string') {
617
- const def = csn.definitions[ref];
618
- if (def && def[_hasLocalizedView]) {
629
+ if (localizedViewFor[ref]) {
619
630
  if (Array.isArray(obj.ref))
620
- obj.ref[0] = def[_hasLocalizedView];
631
+ obj.ref[0] = localizedViewFor[ref];
621
632
  else
622
- obj.ref = def[_hasLocalizedView];
633
+ obj.ref = localizedViewFor[ref];
623
634
  }
624
-
625
- } else if (ref.id) {
626
- const def = csn.definitions[ref.id];
627
- if (def && def[_hasLocalizedView])
628
- obj.ref[0].id = def[_hasLocalizedView];
629
-
630
- } else if (options.testMode) {
635
+ }
636
+ else if (ref.id) {
637
+ if (localizedViewFor[ref.id])
638
+ obj.ref[0].id = localizedViewFor[ref.id];
639
+ }
640
+ else if (options.testMode) {
631
641
  throw new CompilerAssertion('Debug me: Unhandled reference during localized-rewrite!');
632
642
  }
633
643
  }
@@ -640,19 +650,13 @@ function _addLocalizationViews(csn, options, config) {
640
650
  return csn.definitions[artName].elements.texts.target;
641
651
  }
642
652
 
643
- function cleanDefinitionSymbols() {
644
- forEachDefinition(csn, function cleanDefinition(definition) {
645
- cleanSymbols(definition, _hasLocalizedView, _isViewForEntity, _isViewForView, _targetFor);
646
- });
647
- }
648
-
649
653
  /**
650
654
  * In case that the user tried to annotate `localized.*` artifacts, apply them.
651
655
  */
652
656
  function applyAnnotationsForLocalizedViews() {
653
657
  applyAnnotationsFromExtensions(csn, {
654
658
  override: true,
655
- filter: (name) => name.startsWith('localized.'),
659
+ filter: name => name.startsWith('localized.'),
656
660
  notFound(name, index) {
657
661
  if (!ignoreUnknownExtensions) {
658
662
  messageFunctions.message('ext-undefined-def', [ 'extensions', index ],
@@ -673,11 +677,11 @@ function _addLocalizationViews(csn, options, config) {
673
677
  const artName = defName.substring(localizedPrefix.length);
674
678
  const art = csn.definitions[artName];
675
679
  if (def[annoPersistenceSkip] && !art?.[annoPersistenceSkip]) {
676
- messageFunctions.message( 'anno-unexpected-localized-skip', ['definitions', defName], {
680
+ messageFunctions.message( 'anno-unexpected-localized-skip', [ 'definitions', defName ], {
677
681
  '#': 'view',
678
682
  name: defName,
679
683
  art: artName,
680
- anno: annoPersistenceSkip
684
+ anno: annoPersistenceSkip,
681
685
  });
682
686
  }
683
687
  }
@@ -734,9 +738,7 @@ function columnsForEntityWithExcludeList(entity, entityName, excludeList) {
734
738
  // @ts-ignore
735
739
  return Object.keys(entity.elements)
736
740
  .filter(elementName => !excludeList.includes(elementName))
737
- .map(elementName => {
738
- return { ref: [ entityName, elementName ] };
739
- });
741
+ .map(elementName => ({ ref: [ entityName, elementName ] }));
740
742
  }
741
743
 
742
744
  /**
@@ -758,7 +760,7 @@ function copyLocation(target, source) {
758
760
  * @param {CSN.Artifact} source
759
761
  */
760
762
  function copyPersistenceAnnotations(target, source) {
761
- forEachKey(source, anno => {
763
+ forEachKey(source, (anno) => {
762
764
  // Note:
763
765
  // v3/v4: Because `.exists` is copied to the convenience view, it could
764
766
  // lead to some localization views referencing non-existing ones.
@@ -788,13 +790,18 @@ function checkExistingLocalizationViews(csn, options, messageFunctions) {
788
790
  if (!def.query && !def.projection) {
789
791
  if (!name.endsWith('.texts')) {
790
792
  hasNonViews = true;
791
- messageFunctions.error('reserved-namespace-localized', ['definitions', name], { name: 'localized' },
792
- 'The namespace $(NAME) is reserved for localization views');
793
+ messageFunctions.error(
794
+ 'reserved-namespace-localized', [ 'definitions', name ], { name: 'localized' },
795
+ 'The namespace $(NAME) is reserved for localization views'
796
+ );
793
797
  }
794
- } else if (!hasExistingViews) {
798
+ }
799
+ else if (!hasExistingViews) {
795
800
  hasExistingViews = true;
796
- messageFunctions.info( null, [ 'definitions', name ], {},
797
- 'Input CSN already contains localization views, no further ones will be created' );
801
+ messageFunctions.info(
802
+ null, [ 'definitions', name ], {},
803
+ 'Input CSN already contains localization views, no further ones will be created'
804
+ );
798
805
  }
799
806
  }
800
807
  });
@@ -810,7 +817,7 @@ function isValidTextsEntity(entity) {
810
817
  if (!entity)
811
818
  return false;
812
819
  const requiredTextsProps = [ 'locale' ];
813
- return requiredTextsProps.some( prop => !!entity.elements[prop])
820
+ return requiredTextsProps.some( prop => !!entity.elements[prop]);
814
821
  }
815
822
 
816
823
  /**
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { transformAnnotationExpression, implicitAs, } = require('../../model/csnUtils');
3
+ const { transformAnnotationExpression, implicitAs } = require('../../model/csnUtils');
4
4
 
5
5
  /**
6
6
  * Used during annotating of foreign keys.
@@ -14,23 +14,27 @@ const { transformAnnotationExpression, implicitAs, } = require('../../model/csnU
14
14
  * @param {CSN.Path} elementPath
15
15
  */
16
16
  function adaptAnnotationsRefs(generatedForeignKeys, csnUtils, { error }, elementPath) {
17
- if(Array.isArray(generatedForeignKeys?.[0])) {
17
+ if (Array.isArray(generatedForeignKeys?.[0])) {
18
18
  // ensure we are always called with an array of objects. TODO: Cleanup fk creation in for.effective to create array of objects
19
19
  adaptAnnotationsRefs(remapToArrayOfObjects(generatedForeignKeys), csnUtils, { error }, elementPath);
20
- } else {
20
+ }
21
+ else {
21
22
  const reportedErrorsForAnnoPath = {};
22
23
  generatedForeignKeys.forEach((gfk, index) => {
23
- Object.entries(gfk.foreignKey).forEach(([key, value]) => {
24
- if (key[0] !== '@') return;
24
+ Object.entries(gfk.foreignKey).forEach(([ key, value ]) => {
25
+ if (key[0] !== '@')
26
+ return;
25
27
 
26
28
  transformAnnotationExpression(gfk.foreignKey, key, {
27
29
  ref: (_parent, _prop, ref, path, _p, _ppn, ctx) => {
28
30
  // if the reference is a $self reference, we do nothing,
29
31
  // as this is the way to tell that we do not reference the foreign key
30
- if (ref[0] === '$self') return;
32
+ if (ref[0] === '$self')
33
+ return;
31
34
  // if annotation was not propagated from the keys array during foreign keys creation,
32
35
  // means that it is not a candidate for foreign key substitution
33
- if (gfk.keyAnnotations !== null && !gfk.keyAnnotations.includes(key)) return;
36
+ if (gfk.keyAnnotations !== null && !gfk.keyAnnotations.includes(key))
37
+ return;
34
38
 
35
39
  const art = gfk.originalKey._art ||
36
40
  csnUtils.inspectRef(elementPath ? path : getOriginatingKeyPath(gfk, path)).art; // OData uses getOriginatingKeyPath - as it relies on $path
@@ -39,15 +43,16 @@ function adaptAnnotationsRefs(generatedForeignKeys, csnUtils, { error }, element
39
43
  error('odata-anno-xpr-ref', path, { elemref: { ref }, anno: key, '#': 'fk_substitution' });
40
44
  reportedErrorsForAnnoPath[path] = true;
41
45
  }
42
- } else {
46
+ }
47
+ else {
43
48
  const gfkForRef = findGeneratedForeignKeyForKeyRef(generatedForeignKeys, ref);
44
49
  if (gfkForRef.length === 1) {
45
50
  ref[0] = gfkForRef[0].prefix;
46
51
 
47
- if (ctx?.annoExpr?.['=']) {
52
+ if (ctx?.annoExpr?.['='])
48
53
  ctx.annoExpr['='] = true;
49
- }
50
- } else {
54
+ }
55
+ else {
51
56
  // check if the annotation reference points to a structure that has been expanded,
52
57
  // if so -> report an error
53
58
  const foundInOriginalRef = findOriginalRef(generatedForeignKeys.filter(gfk => gfk.originalKey.$originalKeyRef), ref);
@@ -59,8 +64,8 @@ function adaptAnnotationsRefs(generatedForeignKeys, csnUtils, { error }, element
59
64
  }
60
65
  }
61
66
  }
62
- }
63
- }, elementPath ? elementPath.concat(['keys', index]) : value?.$path?.slice(0, value.$path.length - 1)); // OData uses $path
67
+ },
68
+ }, elementPath ? elementPath.concat([ 'keys', index ]) : value?.$path?.slice(0, value.$path.length - 1)); // OData uses $path
64
69
  });
65
70
  });
66
71
  }
@@ -88,9 +93,9 @@ function adaptAnnotationsRefs(generatedForeignKeys, csnUtils, { error }, element
88
93
  }
89
94
 
90
95
  function remapToArrayOfObjects(generatedForeignKeys) {
91
- return generatedForeignKeys.map(([ prefix, foreignKey, originalKey ]) => {
92
- return { prefix, foreignKey, originalKey, keyAnnotations: null };
93
- });
96
+ return generatedForeignKeys.map(([ prefix, foreignKey, originalKey ]) => ({
97
+ prefix, foreignKey, originalKey, keyAnnotations: null,
98
+ }));
94
99
  }
95
100
 
96
101
  module.exports = { adaptAnnotationsRefs };