@sap/cds-compiler 2.13.8 → 3.0.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 (127) hide show
  1. package/CHANGELOG.md +155 -1594
  2. package/bin/cdsc.js +144 -66
  3. package/doc/CHANGELOG_ARCHIVE.md +1592 -0
  4. package/doc/CHANGELOG_BETA.md +3 -4
  5. package/doc/CHANGELOG_DEPRECATED.md +35 -1
  6. package/doc/{DeprecatedOptions.md → DeprecatedOptions_v2.md} +3 -1
  7. package/doc/Versioning.md +20 -1
  8. package/lib/api/.eslintrc.json +2 -2
  9. package/lib/api/main.js +237 -122
  10. package/lib/api/options.js +17 -88
  11. package/lib/api/validate.js +12 -16
  12. package/lib/base/keywords.js +216 -109
  13. package/lib/base/message-registry.js +152 -37
  14. package/lib/base/messages.js +145 -83
  15. package/lib/base/model.js +44 -2
  16. package/lib/base/optionProcessorHelper.js +19 -0
  17. package/lib/checks/actionsFunctions.js +7 -5
  18. package/lib/checks/annotationsOData.js +11 -32
  19. package/lib/checks/arrayOfs.js +1 -34
  20. package/lib/checks/cdsPersistence.js +1 -0
  21. package/lib/checks/elements.js +6 -6
  22. package/lib/checks/invalidTarget.js +1 -1
  23. package/lib/checks/nonexpandableStructured.js +1 -1
  24. package/lib/checks/queryNoDbArtifacts.js +2 -1
  25. package/lib/checks/selectItems.js +5 -1
  26. package/lib/checks/types.js +4 -2
  27. package/lib/checks/utils.js +2 -2
  28. package/lib/checks/validator.js +4 -5
  29. package/lib/compiler/assert-consistency.js +16 -10
  30. package/lib/compiler/base.js +1 -0
  31. package/lib/compiler/builtins.js +98 -9
  32. package/lib/compiler/checks.js +22 -70
  33. package/lib/compiler/define.js +61 -13
  34. package/lib/compiler/extend.js +79 -14
  35. package/lib/compiler/finalize-parse-cdl.js +46 -29
  36. package/lib/compiler/index.js +100 -37
  37. package/lib/compiler/moduleLayers.js +7 -0
  38. package/lib/compiler/populate.js +19 -18
  39. package/lib/compiler/propagator.js +7 -4
  40. package/lib/compiler/resolve.js +297 -234
  41. package/lib/compiler/shared.js +107 -102
  42. package/lib/compiler/tweak-assocs.js +16 -11
  43. package/lib/compiler/utils.js +5 -0
  44. package/lib/edm/annotations/genericTranslation.js +93 -21
  45. package/lib/edm/csn2edm.js +230 -115
  46. package/lib/edm/edm.js +305 -226
  47. package/lib/edm/edmPreprocessor.js +509 -438
  48. package/lib/edm/edmUtils.js +31 -45
  49. package/lib/gen/Dictionary.json +98 -22
  50. package/lib/gen/language.checksum +1 -1
  51. package/lib/gen/language.interp +10 -30
  52. package/lib/gen/language.tokens +105 -114
  53. package/lib/gen/languageLexer.interp +1 -34
  54. package/lib/gen/languageLexer.js +889 -1007
  55. package/lib/gen/languageLexer.tokens +95 -106
  56. package/lib/gen/languageParser.js +20786 -22199
  57. package/lib/json/csnVersion.js +10 -11
  58. package/lib/json/from-csn.js +59 -51
  59. package/lib/json/to-csn.js +10 -10
  60. package/lib/language/antlrParser.js +2 -2
  61. package/lib/language/docCommentParser.js +62 -39
  62. package/lib/language/errorStrategy.js +52 -40
  63. package/lib/language/genericAntlrParser.js +348 -229
  64. package/lib/language/language.g4 +629 -653
  65. package/lib/language/multiLineStringParser.js +14 -42
  66. package/lib/language/textUtils.js +44 -0
  67. package/lib/main.d.ts +46 -43
  68. package/lib/main.js +108 -79
  69. package/lib/model/csnRefs.js +34 -7
  70. package/lib/model/csnUtils.js +337 -332
  71. package/lib/model/enrichCsn.js +1 -0
  72. package/lib/model/revealInternalProperties.js +30 -10
  73. package/lib/model/sortViews.js +32 -31
  74. package/lib/modelCompare/compare.js +6 -6
  75. package/lib/optionProcessor.js +73 -46
  76. package/lib/render/.eslintrc.json +1 -1
  77. package/lib/render/DuplicateChecker.js +4 -7
  78. package/lib/render/manageConstraints.js +70 -2
  79. package/lib/render/toCdl.js +1042 -882
  80. package/lib/render/toHdbcds.js +195 -245
  81. package/lib/render/toRename.js +44 -22
  82. package/lib/render/toSql.js +225 -241
  83. package/lib/render/utils/common.js +145 -15
  84. package/lib/render/utils/sql.js +20 -19
  85. package/lib/sql-identifier.js +6 -0
  86. package/lib/transform/db/.eslintrc.json +4 -3
  87. package/lib/transform/db/associations.js +2 -2
  88. package/lib/transform/db/cdsPersistence.js +5 -15
  89. package/lib/transform/db/constraints.js +4 -2
  90. package/lib/transform/db/expansion.js +22 -16
  91. package/lib/transform/db/flattening.js +109 -80
  92. package/lib/transform/db/transformExists.js +7 -7
  93. package/lib/transform/db/views.js +9 -6
  94. package/lib/transform/draft/.eslintrc.json +2 -2
  95. package/lib/transform/draft/db.js +6 -6
  96. package/lib/transform/draft/odata.js +6 -7
  97. package/lib/transform/forHanaNew.js +62 -48
  98. package/lib/transform/forOdataNew.js +49 -50
  99. package/lib/transform/localized.js +31 -20
  100. package/lib/transform/odata/toFinalBaseType.js +16 -14
  101. package/lib/transform/odata/typesExposure.js +146 -198
  102. package/lib/transform/odata/utils.js +1 -38
  103. package/lib/transform/transformUtilsNew.js +67 -84
  104. package/lib/transform/translateAssocsToJoins.js +7 -3
  105. package/lib/transform/universalCsn/.eslintrc.json +2 -2
  106. package/lib/transform/universalCsn/coreComputed.js +16 -9
  107. package/lib/transform/universalCsn/universalCsnEnricher.js +60 -10
  108. package/lib/utils/file.js +3 -3
  109. package/lib/utils/moduleResolve.js +13 -6
  110. package/lib/utils/timetrace.js +20 -21
  111. package/package.json +35 -4
  112. package/share/messages/message-explanations.json +2 -1
  113. package/share/messages/syntax-expected-integer.md +37 -0
  114. package/doc/ApiMigration.md +0 -237
  115. package/doc/CommandLineMigration.md +0 -58
  116. package/doc/ErrorMessages.md +0 -175
  117. package/doc/FioriAnnotations.md +0 -94
  118. package/doc/ODataTransformation.md +0 -273
  119. package/lib/backends.js +0 -529
  120. package/lib/fix_antlr4-8_warning.js +0 -56
  121. package/lib/transform/odata/attachPath.js +0 -96
  122. package/lib/transform/odata/expandStructKeysInAssociations.js +0 -59
  123. package/lib/transform/odata/generateForeignKeyElements.js +0 -261
  124. package/lib/transform/odata/referenceFlattener.js +0 -296
  125. package/lib/transform/odata/sortByAssociationDependency.js +0 -105
  126. package/lib/transform/odata/structuralPath.js +0 -72
  127. package/lib/transform/odata/structureFlattener.js +0 -171
@@ -5,6 +5,8 @@ const { applyTransformations, applyTransformationsOnNonDictionary } = require('.
5
5
  const { isBuiltinType } = require('../compiler/builtins.js')
6
6
  const { sortCsn, cloneCsnDictionary: _cloneCsnDictionary } = require('../json/to-csn');
7
7
  const { ModelError } = require("../base/error");
8
+ const { typeParameters } = require("../compiler/builtins");
9
+ const { forEach } = require('../utils/objectUtils');
8
10
  const version = require('../../package.json').version;
9
11
 
10
12
  // Low-level utility functions to work with compact CSN.
@@ -34,11 +36,14 @@ const version = require('../../package.json').version;
34
36
  */
35
37
 
36
38
  /**
37
- * Get utility functions for a given CSN.
39
+ * Get utility functions for a given CSN. Re-exports functions of `csnRefs()`.
38
40
  * @param {CSN.Model} model (Compact) CSN model
39
41
  */
40
42
  function getUtils(model, universalReady) {
41
- const { artifactRef, inspectRef, effectiveType, getOrigin, targetAspect, getColumn, getElement, initDefinition } = csnRefs(model, universalReady);
43
+ const _csnRefs = csnRefs(model, universalReady);
44
+ const { artifactRef } = _csnRefs;
45
+ /** Cache for getFinalBaseTypeWithProps(). Specific to the current model. */
46
+ const finalBaseTypeCache = Object.create(null);
42
47
 
43
48
  return {
44
49
  getCsnDef,
@@ -56,17 +61,10 @@ function getUtils(model, universalReady) {
56
61
  getServiceName,
57
62
  hasAnnotationValue,
58
63
  cloneWithTransformations,
59
- getFinalBaseType,
60
- inspectRef,
61
- artifactRef,
62
- effectiveType,
64
+ getFinalBaseTypeWithProps,
63
65
  get$combined,
64
- getOrigin,
65
66
  getQueryPrimarySource,
66
- targetAspect,
67
- getColumn,
68
- getElement,
69
- initDefinition
67
+ ..._csnRefs,
70
68
  };
71
69
 
72
70
  /**
@@ -261,7 +259,7 @@ function getUtils(model, universalReady) {
261
259
  */
262
260
  function isStructured(obj) {
263
261
  return obj.elements ||
264
- (obj.type && ((getFinalTypeDef(obj.type).elements) || (obj.type.ref && getFinalBaseType(obj.type).elements)));
262
+ (obj.type && ((getFinalTypeDef(obj.type).elements) || (obj.type.ref && getFinalBaseTypeWithProps(obj.type)?.elements)));
265
263
  }
266
264
 
267
265
  /**
@@ -447,13 +445,13 @@ function getUtils(model, universalReady) {
447
445
  * The transformer functions are called with the following signature:
448
446
  * transformer(value, node, resultNode, key)
449
447
  *
450
- * @param {any} node Node to transform
448
+ * @param {any} rootNode Node to transform
451
449
  * @param {any} transformers Object defining transformer functions
452
450
  * @returns {object}
453
451
  */
454
- function cloneWithTransformations(node, transformers) {
452
+ function cloneWithTransformations(rootNode, transformers) {
455
453
 
456
- return transformNode(node);
454
+ return transformNode(rootNode);
457
455
 
458
456
  // This general transformation function will be applied to each node recursively
459
457
  function transformNode(node) {
@@ -486,97 +484,122 @@ function getUtils(model, universalReady) {
486
484
  }
487
485
  }
488
486
 
487
+ function _normalizeTypeRef(type) {
488
+ if (type && typeof type === 'object' && type.ref?.length === 1)
489
+ type = type.ref[0]; // simplify type: no element -> simple string can be used
490
+ return type;
491
+ }
489
492
 
490
493
  /**
491
- * Resolve to the final type of a type, that means follow type chains, references to other types or
492
- * elements a.s.o
493
- * Works for all kinds of types, strings as well as type objects. Strings need to be absolute type names.
494
- * Returns the final type as string (if it has a name, which is not always the case, think of embedded structures),
495
- * else the type object itself is returned. If a type is structured, you can navigate into it by providing a path,
496
- * e.g. given the following model
497
- * type bar: S.foo;
498
- * type s1 {
499
- * s: s2;
500
- * };
501
- * type s2 {
502
- * u: type of S.e:t;
503
- * }
504
- * service S {
505
- * type foo: type of S.e:i.j1;
506
- * entity e {
507
- * key i: { j1: Integer };
508
- * t: bar;
509
- * v: s1;
510
- * x: blutz.s.u;
511
- * };
512
- * type blutz: S.e.v;
513
- * view V as select from e {
514
- * 1+1 as i: bar,
515
- * };
516
- * type tt: type of V:i;
517
- * }
518
- * the following calls will all return 'cds.Integer'
519
- * getFinalBaseType('S.tt')
520
- * getFinalBaseType('S.e',['i','j1'])
521
- * getFinalBaseType('S.e',['t'])
522
- * getFinalBaseType('S.e',['x'])
523
- * getFinalBaseType('S.blutz',['s', 'u'])
524
- * Types are always resolved as far as possible. A type name which has no further definition is simply returned.
525
- * Composed types (structures, entities, views, ...) are returned as type objects, if not drilled down into
526
- * the elements. Path steps that have no corresponding element lead to 'undefined'. Refs to something that has
527
- * no type (e.g. expr in a view without explicit type) returns 'null'
494
+ * Resolve to the final type of a type, that means follow type chains, references, etc.
495
+ * Input is a type name, i.e. string, or type ref, i.e. `{ ref: [...] }`.
496
+ *
497
+ * Returns `null` if the type can't be resolved or if the referenced element has no type,
498
+ * e.g. `typeof V:calculated`.
499
+ * Otherwise, if scalar, returns an object that has a `type` property and all collected type
500
+ * properties, or the type object with `elements` or `items` property if structured/arrayed.
528
501
  *
529
- * @param {string|object} type Type - either string or ref
530
- * @param {CSN.Path} path
531
- * @param {WeakMap} [resolved=new WeakMap()] WeakMap containing already resolved refs - if a ref is not cached, it will be resolved JIT
532
- * @param {object} [cycleCheck] Dictionary to remember already resolved types - to be cycle-safe
533
- * @returns
502
+ * Caches type lookups. If the CSN changes drastically, you will need to re-call `csnUtils()`
503
+ * and use the newly returned `getFinalBaseTypeWithProps()`.
504
+ *
505
+ * @param {string|object} type Type as string or type ref, i.e. `{ ref: [...] }`
506
+ * @returns {object|null}
534
507
  */
535
- function getFinalBaseType(type, path = [], resolved = new WeakMap(), cycleCheck = undefined) {
508
+ function getFinalBaseTypeWithProps(type) {
509
+ type = _normalizeTypeRef(type);
536
510
  if (!type)
537
- return type;
538
- if (typeof(type) === 'string') {
539
- if (isBuiltinType(type)) // built-in type
540
- return type;
541
- if (cycleCheck) {
542
- let visited = path.length? type + ':' + path.join('.') : type;
543
- if (cycleCheck[visited])
544
- throw new ModelError('Circular type chain on type ' + type);
545
- else
546
- cycleCheck[visited] = true;
511
+ return null;
512
+
513
+ // Nothing to copy from builtin type name.
514
+ if (typeof type === 'string' && isBuiltinType( type )) {
515
+ return { type };
516
+ }
517
+
518
+ // We differentiate between ref and type to avoid collisions due to dict key.
519
+ // Delimiter chosen arbitrarily; just one that is rarely used.
520
+ const resolvedKey = (typeof type === 'object') ? `ref:${type.ref.join('\\')}` : `type:${type}`;
521
+
522
+ if (finalBaseTypeCache[resolvedKey]) {
523
+ if (finalBaseTypeCache[resolvedKey] === true)
524
+ throw new ModelError(`Detected circular type reference; can't resolve: ${resolvedKey}`);
525
+ return finalBaseTypeCache[resolvedKey];
526
+ }
527
+
528
+ let typeRef = artifactRef(type); // throws if not found
529
+ const isNonScalar = _cacheNonScalar(typeRef);
530
+ if (isNonScalar)
531
+ return finalBaseTypeCache[resolvedKey];
532
+
533
+ const props = {};
534
+ _copyTypeProps(props, typeRef);
535
+
536
+ // If the resolved type is a builtin, stop and use its type arguments.
537
+ type = _normalizeTypeRef(typeRef.type);
538
+ if (typeof type === 'string' && isBuiltinType(type))
539
+ return _cacheResolved(props);
540
+
541
+ // Set to true (before the recursive call) to avoid cyclic issues.
542
+ finalBaseTypeCache[resolvedKey] = true;
543
+
544
+ // Continue the search
545
+ const finalBase = getFinalBaseTypeWithProps(type);
546
+ if (!finalBase) // Reference has no proper type, e.g. due to `type of View:calculated`.
547
+ return _cacheResolved(null);
548
+ const nonScalar = _cacheNonScalar(finalBase);
549
+ if (nonScalar)
550
+ return finalBaseTypeCache[resolvedKey];
551
+
552
+ // If not a non-scalar, must be resolved type.
553
+ _copyTypeProps(props, finalBase);
554
+ _cacheResolved(props);
555
+ return props;
556
+
557
+ /**
558
+ * Cache/Store the type props under the current `resolvedKey` in the `resolved` cache.
559
+ *
560
+ * @param {object} typeProps
561
+ */
562
+ function _cacheResolved(typeProps) {
563
+ finalBaseTypeCache[resolvedKey] = typeProps;
564
+ return typeProps;
565
+ }
566
+
567
+ /**
568
+ * Structured or arrayed types are not followed further, so cache them.
569
+ *
570
+ * @param obj
571
+ * @returns {boolean} True, if structured/arrayed/invalid, false if scalar.
572
+ */
573
+ function _cacheNonScalar(obj) {
574
+ if (!obj) { // Reference has no proper type, e.g. due to `type of View:calculated`.
575
+ _cacheResolved(null);
576
+ return true;
547
577
  }
548
- else {
549
- cycleCheck = Object.create(null);
578
+ if (obj.elements || obj.items) {
579
+ _cacheResolved(obj);
580
+ return true;
550
581
  }
551
- let definedType = model.definitions[type];
552
- if (definedType && definedType.type)
553
- return getFinalBaseType(definedType.type, path, resolved, cycleCheck);
554
- else
555
- return getFinalBaseType(definedType, path, resolved, cycleCheck);
582
+ return false;
556
583
  }
557
- else if (typeof(type) === 'object') {
558
- if (type.ref) {
559
- // assert type.ref instanceof Array && type.ref.length >= 1
560
- const ref = resolved.has(type) ? resolved.get(type).art : artifactRef(type);
561
- return getFinalBaseType(ref, path, resolved, cycleCheck);
562
- }
563
- else if (type.elements) {
564
- if (path.length) {
565
- let [e, ...p] = path;
566
- return getFinalBaseType(type.elements[e], p, resolved, cycleCheck);
584
+
585
+ /**
586
+ * Copy type properties from source to target. Also copies `type`, `enum`,
587
+ * and `localized` (if keepLocalized is true). Only copies from source,
588
+ * if target does not have them.
589
+ *
590
+ * @param {object} target
591
+ * @param {object} source
592
+ */
593
+ function _copyTypeProps(target, source) {
594
+ target.type = source.type;
595
+ const typeProps = [ ...typeParameters.list, 'enum', 'default', 'localized' ];
596
+ for (const param of typeProps) {
597
+ if (target[param] === undefined && source[param] !== undefined) {
598
+ target[param] = source[param];
567
599
  }
568
600
  }
569
- else if (type.type)
570
- return (getFinalBaseType(type.type, path, resolved, cycleCheck));
571
- else if (type.items)
572
- return type;
573
- else
574
- // TODO: this happens if we don't have a type, e.g. an expression in a select list
575
- // in a view without explicit type. Instead of returning null we might want to return
576
- // the object instead?
577
- return null;
601
+ return target;
578
602
  }
579
- return type;
580
603
  }
581
604
  }
582
605
 
@@ -588,7 +611,7 @@ function getUtils(model, universalReady) {
588
611
  * @param {object} csn Top-level CSN. You can pass non-dictionary values.
589
612
  * @param {CSN.Options} options CSN Options, only used for `dictionaryPrototype`, `testMode`, and `testSortCsn`
590
613
  */
591
- function cloneCsn(csn, options) {
614
+ function cloneCsnNonDict(csn, options) {
592
615
  return sortCsn(csn, options);
593
616
  }
594
617
 
@@ -596,7 +619,7 @@ function cloneCsn(csn, options) {
596
619
  * Deeply clone the given CSN dictionary and return it.
597
620
  * Note that annotations are only copied shallowly.
598
621
  * This function does _not_ sort the given dictionary.
599
- * See cloneCsn() if you want sorted definitions.
622
+ * See cloneCsnNonDict() if you want sorted definitions.
600
623
  *
601
624
  * @param {object} csn
602
625
  * @param {CSN.Options} options Only cloneOptions.dictionaryPrototype is
@@ -632,8 +655,10 @@ function forEachDefinition( csn, callback, iterateOptions = {} ) {
632
655
  * @param {CSN.Path} [path]
633
656
  * @param {boolean} [ignoreIgnore]
634
657
  * @param {object} iterateOptions can be used to skip certain kinds from being iterated
658
+ * @param constructCallback
635
659
  */
636
- function forEachMember( construct, callback, path=[], ignoreIgnore=true, iterateOptions = {}) {
660
+ function forEachMember( construct, callback, path=[], ignoreIgnore=true, iterateOptions = {},
661
+ constructCallback = (_construct, _prop, _path) => {}) {
637
662
  // Allow processing _ignored elements if requested
638
663
  if (ignoreIgnore && construct._ignore) {
639
664
  return;
@@ -641,8 +666,7 @@ function forEachMember( construct, callback, path=[], ignoreIgnore=true, iterate
641
666
 
642
667
  // `items` itself is a structure that can contain "elements", and more.
643
668
  if (construct.items) {
644
- // TODO: Should we go to the deepest items.items?
645
- forEachMember( construct.items, callback, [...path, 'items'], ignoreIgnore, iterateOptions );
669
+ forEachMember( construct.items, callback, [...path, 'items'], ignoreIgnore, iterateOptions, constructCallback );
646
670
  }
647
671
 
648
672
  // Unlike XSN, we don't make "returns" a "params" in the callback.
@@ -650,12 +674,43 @@ function forEachMember( construct, callback, path=[], ignoreIgnore=true, iterate
650
674
  // `elements` of the return type (if structured).
651
675
  // TODO: `returns` should be handled like a parameter just like XSN (maybe with different prop name)
652
676
  if (construct.returns && !iterateOptions.elementsOnly) {
653
- forEachMember( construct.returns, callback, [...path, 'returns'], ignoreIgnore, iterateOptions );
677
+ forEachMember( construct.returns, callback, [...path, 'returns'], ignoreIgnore, iterateOptions, constructCallback );
654
678
  }
655
679
 
656
680
  path = [...path]; // Copy
657
681
  const propsWithMembers = (iterateOptions.elementsOnly ? ['elements'] : ['elements', 'enum', 'actions', 'params']);
658
- propsWithMembers.forEach((prop) => forEachGeneric( construct, prop, callback, path, iterateOptions ));
682
+ propsWithMembers.forEach((prop) => {
683
+ forEachGeneric( construct, prop, callback, path, iterateOptions );
684
+ if (construct[prop]) {
685
+ if (Array.isArray(constructCallback))
686
+ constructCallback.forEach(cb => cb(construct, prop, path));
687
+ else
688
+ constructCallback(construct, prop, path);
689
+ }
690
+ });
691
+ }
692
+
693
+ /**
694
+ * Call `forEachMember` and then apply `forEachMember` on queries.
695
+ *
696
+ * @param {CSN.Artifact} construct
697
+ * @param {genericCallback|genericCallback[]} callback
698
+ * @param {CSN.Path} [path]
699
+ * @param {boolean} [ignoreIgnore]
700
+ * @param {object} iterateOptions can be used to skip certain kinds from being iterated
701
+ * @param {constructCallback|constructCallback[]} callback
702
+ */
703
+ function forEachMemberWithQuery( construct, callback, path=[], ignoreIgnore=true, iterateOptions = {},
704
+ constructCallback = (_construct, _prop, _path) => {}) {
705
+ forEachMember(construct, callback, path, ignoreIgnore, iterateOptions, constructCallback);
706
+ if (construct.query) {
707
+ forAllQueries(construct.query, (q, p) => {
708
+ const s = q.SELECT;
709
+ if(s) {
710
+ forEachMember(s, callback, p, ignoreIgnore, iterateOptions);
711
+ }
712
+ }, [ ...path, 'query' ]);
713
+ }
659
714
  }
660
715
 
661
716
  /**
@@ -667,16 +722,43 @@ function forEachMember( construct, callback, path=[], ignoreIgnore=true, iterate
667
722
  * @param {CSN.Path} [path]
668
723
  * @param {boolean} [ignoreIgnore]
669
724
  * @param {object} iterateOptions can be used to skip certain kinds from being iterated
725
+ * @param {constructCallback|constructCallback[]} callback
670
726
  */
671
- function forEachMemberRecursively( construct, callback, path=[], ignoreIgnore=true, iterateOptions = {}) {
672
- forEachMember( construct, ( member, memberName, prop, subpath ) => {
727
+ function forEachMemberRecursively( construct, callback, path=[], ignoreIgnore=true, iterateOptions = {},
728
+ constructCallback = (_construct, _prop, _path) => {}) {
729
+ forEachMember( construct, ( member, memberName, prop, subpath, parent ) => {
673
730
  if(Array.isArray(callback))
674
- callback.forEach(cb => cb( member, memberName, prop, subpath, construct ));
731
+ callback.forEach(cb => cb( member, memberName, prop, subpath, parent ));
675
732
  else
676
- callback( member, memberName, prop, subpath, construct );
733
+ callback( member, memberName, prop, subpath, parent );
677
734
  // Descend into nested members, too
678
- forEachMemberRecursively( member, callback, subpath, ignoreIgnore, iterateOptions);
679
- }, path, ignoreIgnore, iterateOptions);
735
+ forEachMemberRecursively( member, callback, subpath, ignoreIgnore, iterateOptions, constructCallback);
736
+ }, path, ignoreIgnore, iterateOptions, constructCallback);
737
+ }
738
+
739
+ /**
740
+ * Apply function `callback(member, memberName)` to each member in `construct`,
741
+ * recursively (i.e. also for sub-elements of elements).
742
+ * Recursively iterate over elements of `construct` query.
743
+ *
744
+ * @param {CSN.Artifact} construct
745
+ * @param {genericCallback|genericCallback[]} callback
746
+ * @param {CSN.Path} [path]
747
+ * @param {boolean} [ignoreIgnore]
748
+ * @param {object} iterateOptions can be used to skip certain kinds from being iterated
749
+ * @param {constructCallback|constructCallback[]} callback
750
+ */
751
+ function forEachMemberRecursivelyWithQuery( construct, callback, path=[], ignoreIgnore=true, iterateOptions = {},
752
+ constructCallback = (_construct, _prop, _path) => {}) {
753
+ forEachMemberRecursively(construct, callback, path, ignoreIgnore, iterateOptions, constructCallback);
754
+ if(construct.query) {
755
+ forAllQueries(construct.query, (q, p) => {
756
+ const s = q.SELECT;
757
+ if(s) {
758
+ forEachMemberRecursively(s, callback, p, ignoreIgnore, iterateOptions);
759
+ }
760
+ }, [ ...path, 'query' ]);
761
+ }
680
762
  }
681
763
 
682
764
  /**
@@ -685,14 +767,14 @@ function forEachMemberRecursively( construct, callback, path=[], ignoreIgnore=tr
685
767
  * the following arguments: the object, the name, and -if it is a duplicate-
686
768
  * the array index and the array containing all duplicates.
687
769
  *
688
- * @param {object} obj
770
+ * @param {object} construct
689
771
  * @param {string} prop
690
772
  * @param {genericCallback|genericCallback[]} callback
691
773
  * @param {CSN.Path} path
692
774
  * @param {object} iterateOptions can be used to skip certain kinds from being iterated
693
775
  */
694
- function forEachGeneric( obj, prop, callback, path = [], iterateOptions = {}) {
695
- const dict = obj[prop];
776
+ function forEachGeneric( construct, prop, callback, path = [], iterateOptions = {}) {
777
+ const dict = construct[prop];
696
778
  for (const name in dict) {
697
779
  if (!Object.prototype.hasOwnProperty.call(dict, name))
698
780
  continue;
@@ -701,98 +783,79 @@ function forEachGeneric( obj, prop, callback, path = [], iterateOptions = {}) {
701
783
  || (iterateOptions.skipArtifact && typeof iterateOptions.skipArtifact === 'function'
702
784
  && iterateOptions.skipArtifact(dictObj, name)))
703
785
  continue;
704
- cb( dictObj, name );
786
+ executeCallbacks( dictObj, name );
705
787
  }
706
- function cb(o, name ) {
788
+ function executeCallbacks(o, name ) {
707
789
  if (Array.isArray(callback))
708
- callback.forEach(cb => cb( o, name, prop, path.concat([prop, name])));
790
+ callback.forEach(cb => cb( o, name, prop, path.concat([prop, name]), construct ));
709
791
  else
710
- callback( o, name, prop, path.concat([prop, name]))
792
+ callback( o, name, prop, path.concat([prop, name]), construct )
711
793
  }
712
794
  }
713
795
 
714
- // Like Object.assign() but copies also non enumerable properties
715
- function assignAll(target, ...sources) {
716
- sources.forEach(source => {
717
- let descriptors = Object.getOwnPropertyNames(source).reduce((descriptors, key) => {
718
- descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
719
- return descriptors;
720
- }, {});
721
- // by default, Object.assign copies enumerable Symbols too
722
- Object.getOwnPropertySymbols(source).forEach(sym => {
723
- let descriptor = Object.getOwnPropertyDescriptor(source, sym);
724
- if (descriptor.enumerable) {
725
- descriptors[sym] = descriptor;
726
- }
727
- });
728
- Object.defineProperties(target, descriptors);
729
- });
730
- return target;
731
- }
732
-
733
796
  /**
734
- * @param {CSN.Query} query
735
- * @param {queryCallback|queryCallback[]} callback
797
+ * @param {CSN.Query} mainQuery
798
+ * @param {queryCallback|queryCallback[]} queryCallback
736
799
  * @param {CSN.Path} path
737
800
  */
738
- function forAllQueries(query, callback, path = []){
739
- return traverseQuery(query, callback, path);
740
- function traverseQuery( q, callback, p ) {
741
- if (q.SELECT) {
801
+ function forAllQueries(mainQuery, queryCallback, path = []){
802
+ return traverseQuery(mainQuery, queryCallback, path);
803
+ function traverseQuery( query, callback, queryPath ) {
804
+ if (query.SELECT) {
742
805
  // The projection is turned into a normalized query - there
743
806
  // is no real SELECT, it is fake
744
807
  if(!(path.length === 3 && path[2] === 'projection'))
745
- p.push('SELECT');
746
- cb( q, p );
747
- q = q.SELECT;
808
+ queryPath.push('SELECT');
809
+ executeCallbacks();
810
+ query = query.SELECT;
748
811
  }
749
- else if (q.SET) {
750
- p.push('SET');
751
- cb( q, p );
752
- q = q.SET;
812
+ else if (query.SET) {
813
+ queryPath.push('SET');
814
+ executeCallbacks();
815
+ query = query.SET;
753
816
  }
754
817
 
755
- if (q.from)
756
- traverseFrom( q.from, callback, p.concat(['from']) );
818
+ if (query.from)
819
+ traverseFrom( query.from, callback, queryPath.concat(['from']) );
757
820
 
758
821
  for (const prop of ['args', 'xpr', 'columns', 'where', 'having']) {
759
822
  // all properties which could have sub queries (directly or indirectly)
760
- const expr = q[prop];
823
+ const expr = query[prop];
761
824
  if (expr && typeof expr === 'object') {
762
825
  if(Array.isArray(expr)){
763
826
  for(let i = 0; i < expr.length; i++){
764
- traverseQuery(expr[i], callback, p.concat([prop, i]));
827
+ traverseQuery(expr[i], callback, queryPath.concat([prop, i]));
765
828
  }
766
829
  } else {
767
830
  for(const argName of Object.keys( expr )){
768
- traverseQuery(expr[argName], callback, p.concat([prop, argName]))
831
+ traverseQuery(expr[argName], callback, queryPath.concat([prop, argName]))
769
832
  }
770
833
  }
771
834
  }
772
835
  }
773
- function cb(q, p) {
836
+ function executeCallbacks() {
774
837
  if(Array.isArray(callback))
775
- callback.forEach(cb => cb( q, p ));
838
+ callback.forEach(cb => cb( query, queryPath ));
776
839
  else
777
- callback( q, p );
840
+ callback( query, queryPath );
778
841
  }
779
842
  }
780
843
 
781
844
  /**
782
845
  * @param {CSN.QueryFrom} from
783
846
  * @param {Function} callback
784
- * @param {CSN.Path} path
847
+ * @param {CSN.Path} csnPath
785
848
  */
786
- function traverseFrom( from, callback, path = [] ) {
849
+ function traverseFrom( from, callback, csnPath = [] ) {
787
850
  if (from.ref) // ignore
788
851
  return;
789
852
  else if (from.args){ // join
790
853
  for(let i = 0; i < from.args.length; i++){
791
- traverseFrom(from.args[i], callback, path.concat(['args', i]));
854
+ traverseFrom(from.args[i], callback, csnPath.concat(['args', i]));
792
855
  }
793
856
  }
794
857
  else
795
- traverseQuery( from, callback, path ); // sub query in FROM
858
+ traverseQuery( from, callback, csnPath ); // sub query in FROM
796
859
  }
797
860
  }
798
861
 
@@ -837,12 +900,10 @@ function hasAnnotationValue(artifact, annotationName, expected = true, caseInsen
837
900
  * @param {ODataOptions} options EDM specific options
838
901
  */
839
902
  function isEdmPropertyRendered(elementCsn, options) {
840
- if(options.toOdata)
841
- options = options.toOdata;
842
903
  // FKs are rendered in
843
904
  // V2/V4 flat: always on
844
905
  // V4 struct: on/off
845
- const renderForeignKey = (options.version === 'v4' && options.odataFormat === 'structured') ? !!options.odataForeignKeys : true;
906
+ const renderForeignKey = (options.odataVersion === 'v4' && options.odataFormat === 'structured') ? !!options.odataForeignKeys : true;
846
907
  const isNotIgnored = !elementCsn.target ? !elementCsn['@cds.api.ignore'] : true;
847
908
  const isNavigable = elementCsn.target ?
848
909
  (elementCsn['@odata.navigable'] === undefined ||
@@ -865,16 +926,19 @@ function isEdmPropertyRendered(elementCsn, options) {
865
926
  * - For the 'plain' naming mode, it means converting all '.' to '_' and upper-casing.
866
927
  * - For the 'quoted' naming mode, this means correctly replacing some '.' with '_'.
867
928
  *
868
- * If the old function signature is used - with a namespace as the third argument - the result might be wrong,
869
- * since the '.' -> '_' conversion for quoted/hdbcds is missing.
929
+ * The above rules might differ for different SQL dialects.
930
+ * Exceptions will be listed below.
870
931
  *
871
932
  * @param {string} artifactName The fully qualified name of the artifact
872
- * @param {('plain'|'quoted'|'hdbcds')} sqlMapping The naming mode to use
873
- * @param {CSN.Model|string|undefined} csn
933
+ * @param {'plain'|'quoted'|'hdbcds'|string} sqlMapping The naming mode to use
934
+ * @param {CSN.Model} csn
935
+ * @param {('sqlite'|'hana'|'plain'|string)} [sqlDialect='plain'] The SQL dialect to use
874
936
  * @returns {string} The resulting database name for (absolute) 'artifactName', depending on the current naming mode.
875
937
  */
876
- function getArtifactDatabaseNameOf(artifactName, sqlMapping, csn) {
877
- if(csn && typeof csn === 'object' && csn.definitions)
938
+ // eslint-disable-next-line no-unused-vars
939
+ function getArtifactDatabaseNameOf(artifactName, sqlMapping, csn, sqlDialect='plain') {
940
+ if(csn && typeof csn === 'object' && csn.definitions) {
941
+ isValidMappingDialectCombi(sqlDialect, sqlMapping)
878
942
  if (sqlMapping === 'quoted' || sqlMapping === 'hdbcds') {
879
943
  return getResultingName(csn, sqlMapping, artifactName);
880
944
  }
@@ -883,24 +947,8 @@ function getArtifactDatabaseNameOf(artifactName, sqlMapping, csn) {
883
947
  } else {
884
948
  throw new Error('Unknown naming mode: ' + sqlMapping);
885
949
  }
886
- else {
887
- console.error(`This invocation of "getArtifactCdsPersistenceName" is deprecated, as it doesn't produce correct output with definition names containing dots - please provide a CSN as the third parameter.`);
888
- if (sqlMapping === 'hdbcds') {
889
- if (csn) {
890
- const namespace = String(csn);
891
- return `${namespace}::${artifactName.substring(namespace.length + 1)}`;
892
- }
893
- return artifactName;
894
- }
895
- else if (sqlMapping === 'plain') {
896
- return artifactName.replace(/\./g, '_').toUpperCase();
897
- }
898
- else if (sqlMapping === 'quoted') {
899
- return artifactName;
900
- }
901
- else {
902
- throw new Error('Unknown naming mode: ' + sqlMapping);
903
- }
950
+ } else {
951
+ throw new Error('A valid CSN model is required to correctly calculate the database name of an artifact.');
904
952
  }
905
953
  }
906
954
 
@@ -967,7 +1015,7 @@ function getUnderscoredName(startIndex, parts, csn) {
967
1015
 
968
1016
  return result;
969
1017
  } else if(art && art.kind === 'service') {
970
- // inside services, we immediatly turn . into _
1018
+ // inside services, we immediately turn . into _
971
1019
  const prefix = parts.slice(0, i).join('.');
972
1020
  const suffix = parts.slice(i).join('_');
973
1021
  const result = [];
@@ -983,6 +1031,12 @@ function getUnderscoredName(startIndex, parts, csn) {
983
1031
  return null;
984
1032
  }
985
1033
 
1034
+ function isValidMappingDialectCombi(sqlDialect, sqlMapping) {
1035
+ if(sqlMapping === 'hdbcds' && sqlDialect !== 'hana')
1036
+ throw new Error(`sqlMapping "hdbcds" must only be used with sqlDialect "hana" - found: ${sqlDialect}`);
1037
+ return true;
1038
+ }
1039
+
986
1040
 
987
1041
  /**
988
1042
  * Return the resulting database element name for 'elemName', depending on the current
@@ -992,11 +1046,17 @@ function getUnderscoredName(startIndex, parts, csn) {
992
1046
  * - For the 'quoted' naming mode, it means converting all '.' to '_'.
993
1047
  * No other naming modes are accepted!
994
1048
  *
1049
+ * The above rules might differ for different SQL dialects.
1050
+ * Exceptions will be listed below.
1051
+ *
995
1052
  * @param {string} elemName The name of the element
996
- * @param {('plain'|'quoted'|'hdbcds')} sqlMapping The naming mode to use
1053
+ * @param {'plain'|'quoted'|'hdbcds'|string} sqlMapping The naming mode to use
1054
+ * @param {('sqlite'|'hana'|'plain'|string)} [sqlDialect='plain'] The SQL dialect to use
997
1055
  * @returns {string} The resulting database element name for 'elemName', depending on the current naming mode.
998
1056
  */
999
- function getElementDatabaseNameOf(elemName, sqlMapping) {
1057
+ // eslint-disable-next-line no-unused-vars
1058
+ function getElementDatabaseNameOf(elemName, sqlMapping, sqlDialect='plain') {
1059
+ isValidMappingDialectCombi(sqlMapping, sqlDialect)
1000
1060
  if (sqlMapping === 'hdbcds') {
1001
1061
  return elemName;
1002
1062
  }
@@ -1111,85 +1171,6 @@ function getNormalizedQuery(art) {
1111
1171
  return art;
1112
1172
  }
1113
1173
 
1114
- /**
1115
- * Merge multiple 'options' objects (from right to left, i.e. rightmost wins). Structured option values are
1116
- * merged deeply. Structured option value from the right may override corresponding bool options on the left,
1117
- * but no other combination of struct/scalar values is allowed. Array options are not merged, i.e. their
1118
- * content is treated like scalars.
1119
- * Returns a new options object.
1120
- *
1121
- * @param {...CSN.Options} optionsObjects
1122
- * @return {CSN.Options}
1123
- */
1124
- function mergeOptions(...optionsObjects) {
1125
- let result = {};
1126
- for (const options of optionsObjects) {
1127
- if (options)
1128
- result = mergeTwo(result, options, 'options');
1129
- }
1130
-
1131
- // Reverse the array to ensure that the rightmost option has priority
1132
- const reversedOptions = [...optionsObjects].reverse(); // de-structure and create a new array, so reverse doesn't impact optionsObject
1133
- const msgOptions = reversedOptions.find(opt => opt && Array.isArray(opt.messages));
1134
- if (msgOptions) {
1135
- result.messages = msgOptions.messages;
1136
- }
1137
-
1138
- return result;
1139
-
1140
- // Recursively used for scalars, too
1141
- function mergeTwo(left, right, name) {
1142
- let result;
1143
- // Copy left as far as required
1144
- if (Array.isArray(left)) {
1145
- // Shallow-copy left array
1146
- result = left.slice();
1147
- } else if (isObject(left)) {
1148
- // Deep-copy left object (unless empty)
1149
- result = Object.keys(left).length ? mergeTwo({}, left, name) : {};
1150
- } else {
1151
- // Just use left scalar
1152
- result = left;
1153
- }
1154
- // Check against improper overwriting
1155
- if (isObject(left) && !Array.isArray(left) && (Array.isArray(right) || isScalar(right))) {
1156
- throw new ModelError(`Cannot overwrite structured option "${name}" with array or scalar value`);
1157
- }
1158
- if ((isScalar(left) && typeof left !== 'boolean' || Array.isArray(left)) && isObject(right) && !Array.isArray(right)) {
1159
- throw new ModelError(`Cannot overwrite non-boolean scalar or array option "${name}" with structured value`);
1160
- }
1161
-
1162
- // Copy or overwrite properties from right to left
1163
- if (Array.isArray(right)) {
1164
- // Shallow-copy right array
1165
- result = right.slice();
1166
- } else if (isObject(right)) {
1167
- // Object overwrites undefined, scalars and arrays
1168
- if (result === undefined || isScalar(result) || Array.isArray(result)) {
1169
- result = {};
1170
- }
1171
- // Deep-copy right object into result
1172
- for (let key of Object.keys(right)) {
1173
- result[key] = mergeTwo(result[key], right[key], `${name}.${key}`);
1174
- }
1175
- } else {
1176
- // Right scalar wins (unless undefined)
1177
- result = (right !== undefined) ? right : result;
1178
- }
1179
- return result;
1180
- }
1181
-
1182
- // Return true if 'o' is a non-null object or array
1183
- function isObject(o) {
1184
- return typeof o === 'object' && o !== null
1185
- }
1186
-
1187
- // Return true if 'o' is a non-undefined scalar
1188
- function isScalar(o) {
1189
- return o !== undefined && !isObject(o);
1190
- }
1191
- }
1192
-
1193
1174
  /**
1194
1175
  * If the artifact with the name given is part of a context (or multiple), return the top-most context.
1195
1176
  * Else, return the artifact itself. Namespaces are not of concern here.
@@ -1241,68 +1222,103 @@ function getLastPartOfRef(ref) {
1241
1222
  return getLastPartOf(lastPathStep.id || lastPathStep);
1242
1223
  }
1243
1224
 
1244
- // Return the name of the parent artifact of the artifact 'name' or
1245
- // '' if there is no parent.
1246
- function getParentNameOf(name) {
1247
- return name.substring(0, name.lastIndexOf('.'));
1248
- }
1225
+ /**
1226
+ * Copy all annotations from 'fromNode' to 'toNode'.
1227
+ *
1228
+ * Overwrite existing ones only if 'overwrite' is true.
1229
+ *
1230
+ * @param {object} fromNode
1231
+ * @param {object} toNode
1232
+ * @param {boolean} [overwrite]
1233
+ */
1234
+ function copyAnnotations(fromNode, toNode, overwrite = false) {
1235
+ // Ignore if no toNode (in case of errors)
1236
+ if (!toNode)
1237
+ return;
1249
1238
 
1250
- // Return an array of parent names of 'name' (recursing into grand-parents)
1251
- // Examples:
1252
- // 'foo.bar.wiz' => [ 'foo.bar', 'foo' ]
1253
- // 'foo' => []
1254
- // 'foo::bar.wiz' => 'foo::bar'
1255
- // 'foo::bar' => []
1256
- function getParentNamesOf(name) {
1257
- let remainder = name.slice(0, -getLastPartOf(name).length);
1258
- if (remainder.endsWith('.')) {
1259
- let parentName = remainder.slice(0, -1);
1260
- return [parentName, ...getParentNamesOf(parentName)];
1261
- } else {
1262
- return [];
1239
+ const annotations = Object.keys(fromNode).filter(key => key.startsWith('@'));
1240
+
1241
+ for (const anno of annotations) {
1242
+ if (toNode[anno] === undefined || overwrite) {
1243
+ toNode[anno] = fromNode[anno];
1244
+ }
1263
1245
  }
1264
1246
  }
1265
1247
 
1266
1248
 
1267
- // Copy all annotations from 'fromNode' to 'toNode'. Overwrite existing ones only if 'overwrite' is true
1268
- function copyAnnotations(fromNode, toNode, overwrite=false) {
1249
+ /**
1250
+ * Same as `copyAnnotations()` but also copies the
1251
+ * annotation-like property `doc`.
1252
+ *
1253
+ * Overwrite existing ones only if 'overwrite' is true.
1254
+ *
1255
+ * @param {object} fromNode
1256
+ * @param {object} toNode
1257
+ * @param {boolean} [overwrite]
1258
+ */
1259
+ function copyAnnotationsAndDoc(fromNode, toNode, overwrite = false) {
1269
1260
  // Ignore if no toNode (in case of errors)
1270
- if (!toNode) {
1261
+ if (!toNode)
1271
1262
  return;
1272
- }
1273
- for (let prop in fromNode) {
1274
- if (!Object.hasOwnProperty.call( fromNode, prop ))
1275
- continue;
1276
- if (prop.startsWith('@')) {
1277
- if (toNode[prop] === undefined || overwrite) {
1278
- toNode[prop] = fromNode[prop];
1279
- }
1263
+
1264
+ const annotations = Object.keys(fromNode)
1265
+ .filter(key => key.startsWith('@') || key === 'doc');
1266
+
1267
+ for (const anno of annotations) {
1268
+ if (toNode[anno] === undefined || overwrite) {
1269
+ toNode[anno] = fromNode[anno];
1280
1270
  }
1281
1271
  }
1282
1272
  }
1283
1273
 
1284
- function isAspect(node) {
1285
- return node && node.kind === 'aspect';
1286
- }
1287
-
1288
- // For each property named 'path' in 'node' (recursively), call callback(path, node)
1289
- function forEachPath(node, callback) {
1290
- if (node === null || typeof node !== 'object') {
1291
- // Primitive node
1274
+ /**
1275
+ * Applies annotations from `csn.extensions` to definitions and their elements.
1276
+ *
1277
+ * `config.filter` can be used to only copy annotations for those definitions,
1278
+ * for which the filter returns true.
1279
+ *
1280
+ * @todo Does _not_ apply param/action/... annotations.
1281
+ *
1282
+ * @param {CSN.Model} csn
1283
+ * @param {{overwrite?: boolean, filter?: (name: string) => boolean}} config
1284
+ */
1285
+ function applyAnnotationsFromExtensions(csn, config) {
1286
+ if (!csn.extensions)
1292
1287
  return;
1293
- }
1294
- for (let name in node) {
1295
- if (!Object.hasOwnProperty.call( node, name ))
1296
- continue;
1297
- // If path found within a non-dictionary, call callback
1298
- if (name === 'path' && Object.getPrototypeOf(node)) {
1299
- callback(node.path, node);
1288
+
1289
+ const filter = config.filter || ((_name) => true);
1290
+ for (const ext of csn.extensions) {
1291
+ const name = ext.annotate || ext.extend;
1292
+ const def = csn.definitions[name];
1293
+ if (name && def && filter(name)) {
1294
+ copyAnnotationsAndDoc(ext, def, config.overwrite);
1295
+ applyAnnotationsToElements(ext, def);
1300
1296
  }
1301
- // Descend recursively
1302
- forEachPath(node[name], callback);
1297
+ }
1298
+
1299
+ function applyAnnotationsToElements(ext, def) {
1300
+ // Only the definition is arrayed but the extension is not since
1301
+ // `items` is not expected in `extensions` by the CSN frontend and not
1302
+ // generated by the CDL parser for `annotate E:arrayed.elem`.
1303
+ if (def.items)
1304
+ def = def.items;
1305
+
1306
+ if (!ext.elements || !def.elements)
1307
+ return;
1308
+
1309
+ forEach(ext.elements, (key, sourceElem) => {
1310
+ const targetElem = def.elements[key];
1311
+ if (targetElem) {
1312
+ copyAnnotationsAndDoc(sourceElem, targetElem, config.overwrite);
1313
+ applyAnnotationsToElements(sourceElem, targetElem);
1314
+ }
1315
+ });
1303
1316
  }
1304
1317
  }
1305
1318
 
1319
+ function isAspect(node) {
1320
+ return node && node.kind === 'aspect';
1321
+ }
1306
1322
 
1307
1323
  /**
1308
1324
  * Return true if the artifact has a valid, truthy persistence.exists/skip annotation
@@ -1379,16 +1395,6 @@ function getServiceNames(csn) {
1379
1395
  return result;
1380
1396
  }
1381
1397
 
1382
- /**
1383
- * Check whether the artifact is @cds.persistence.skip
1384
- *
1385
- * @param {CSN.Artifact} artifact
1386
- * @returns {Boolean}
1387
- */
1388
- function isSkipped(artifact) {
1389
- return hasAnnotationValue(artifact, '@cds.persistence.skip', true)
1390
- }
1391
-
1392
1398
  /**
1393
1399
  * Walk path in the CSN and return the result.
1394
1400
  *
@@ -1442,7 +1448,7 @@ function getVariableReplacement(ref, options) {
1442
1448
  * @returns {boolean} returns equality
1443
1449
  *
1444
1450
  * noExtendedProps remove '$', '_' and '@' properties from
1445
- * the comparision. This eliminates false negatives such as
1451
+ * the comparison. This eliminates false negatives such as
1446
1452
  * mismatching $locations or @odata.foreignKey4.
1447
1453
  */
1448
1454
  function isDeepEqual(obj, other, noExtendedProps) {
@@ -1472,14 +1478,17 @@ function isDeepEqual(obj, other, noExtendedProps) {
1472
1478
 
1473
1479
  module.exports = {
1474
1480
  getUtils,
1475
- cloneCsn,
1481
+ cloneCsn: cloneCsnNonDict, // Umbrella relies on this name
1482
+ cloneCsnNonDict,
1476
1483
  cloneCsnDictionary,
1477
1484
  isBuiltinType,
1478
- assignAll,
1485
+ applyAnnotationsFromExtensions,
1479
1486
  forEachGeneric,
1480
1487
  forEachDefinition,
1481
1488
  forEachMember,
1489
+ forEachMemberWithQuery,
1482
1490
  forEachMemberRecursively,
1491
+ forEachMemberRecursivelyWithQuery,
1483
1492
  forAllQueries,
1484
1493
  hasAnnotationValue,
1485
1494
  isEdmPropertyRendered,
@@ -1493,20 +1502,16 @@ module.exports = {
1493
1502
  isPersistedOnDatabase,
1494
1503
  generatedByCompilerVersion,
1495
1504
  getNormalizedQuery,
1496
- mergeOptions,
1497
1505
  getRootArtifactName,
1498
1506
  getLastPartOfRef,
1499
- getParentNamesOf,
1500
- getParentNameOf,
1501
1507
  getLastPartOf,
1502
1508
  copyAnnotations,
1509
+ copyAnnotationsAndDoc,
1503
1510
  isAspect,
1504
- forEachPath,
1505
1511
  hasValidSkipOrExists,
1506
1512
  getNamespace,
1507
1513
  sortCsnDefinitionsForTests,
1508
1514
  getServiceNames,
1509
- isSkipped,
1510
1515
  walkCsnPath,
1511
1516
  getVariableReplacement,
1512
1517
  implicitAs,