@sap/cds-compiler 5.9.4 → 6.0.12

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 (114) hide show
  1. package/CHANGELOG.md +117 -319
  2. package/README.md +1 -1
  3. package/bin/cds_update_identifiers.js +3 -5
  4. package/bin/cdsc.js +24 -9
  5. package/bin/cdshi.js +1 -1
  6. package/bin/cdsse.js +4 -4
  7. package/doc/CHANGELOG_BETA.md +11 -0
  8. package/doc/CHANGELOG_DEPRECATED.md +29 -0
  9. package/lib/api/main.js +8 -5
  10. package/lib/api/options.js +12 -10
  11. package/lib/base/builtins.js +1 -0
  12. package/lib/base/message-registry.js +191 -99
  13. package/lib/base/messages.js +35 -21
  14. package/lib/base/model.js +14 -24
  15. package/lib/checks/actionsFunctions.js +10 -20
  16. package/lib/checks/annotationsOData.js +1 -1
  17. package/lib/checks/elements.js +35 -10
  18. package/lib/checks/enums.js +31 -0
  19. package/lib/checks/foreignKeys.js +2 -2
  20. package/lib/checks/hasPersistedElements.js +5 -0
  21. package/lib/checks/invalidTarget.js +1 -1
  22. package/lib/checks/managedWithoutKeys.js +5 -4
  23. package/lib/checks/queryNoDbArtifacts.js +10 -8
  24. package/lib/checks/types.js +5 -5
  25. package/lib/checks/validator.js +6 -4
  26. package/lib/compiler/assert-consistency.js +13 -9
  27. package/lib/compiler/checks.js +20 -52
  28. package/lib/compiler/define.js +31 -6
  29. package/lib/compiler/extend.js +5 -1
  30. package/lib/compiler/generate.js +14 -17
  31. package/lib/compiler/populate.js +8 -31
  32. package/lib/compiler/propagator.js +21 -35
  33. package/lib/compiler/resolve.js +64 -29
  34. package/lib/compiler/shared.js +16 -4
  35. package/lib/compiler/tweak-assocs.js +1 -1
  36. package/lib/compiler/utils.js +1 -1
  37. package/lib/edm/annotations/edmJson.js +23 -20
  38. package/lib/edm/annotations/genericTranslation.js +12 -10
  39. package/lib/edm/csn2edm.js +50 -56
  40. package/lib/edm/edm.js +33 -28
  41. package/lib/edm/edmInboundChecks.js +2 -2
  42. package/lib/edm/edmPreprocessor.js +54 -88
  43. package/lib/edm/edmUtils.js +9 -12
  44. package/lib/gen/BaseParser.js +63 -52
  45. package/lib/gen/CdlGrammar.checksum +1 -1
  46. package/lib/gen/CdlParser.js +1153 -1165
  47. package/lib/gen/Dictionary.json +21 -1
  48. package/lib/json/from-csn.js +70 -43
  49. package/lib/json/to-csn.js +6 -8
  50. package/lib/language/multiLineStringParser.js +3 -2
  51. package/lib/main.d.ts +58 -24
  52. package/lib/model/cloneCsn.js +3 -0
  53. package/lib/model/csnUtils.js +28 -39
  54. package/lib/model/xprAsTree.js +23 -9
  55. package/lib/modelCompare/compare.js +5 -4
  56. package/lib/optionProcessor.js +24 -17
  57. package/lib/parsers/AstBuildingParser.js +81 -25
  58. package/lib/parsers/XprTree.js +57 -3
  59. package/lib/parsers/identifiers.js +1 -1
  60. package/lib/parsers/index.js +0 -3
  61. package/lib/render/manageConstraints.js +25 -25
  62. package/lib/render/toCdl.js +173 -170
  63. package/lib/render/toHdbcds.js +126 -128
  64. package/lib/render/toRename.js +7 -7
  65. package/lib/render/toSql.js +128 -125
  66. package/lib/render/utils/common.js +47 -22
  67. package/lib/render/utils/delta.js +25 -25
  68. package/lib/render/utils/operators.js +2 -2
  69. package/lib/render/utils/pretty.js +5 -5
  70. package/lib/render/utils/sql.js +13 -13
  71. package/lib/render/utils/standardDatabaseFunctions.js +115 -103
  72. package/lib/render/utils/unique.js +4 -4
  73. package/lib/transform/db/applyTransformations.js +1 -1
  74. package/lib/transform/db/assertUnique.js +2 -2
  75. package/lib/transform/db/associations.js +6 -7
  76. package/lib/transform/db/assocsToQueries/utils.js +4 -5
  77. package/lib/transform/db/backlinks.js +12 -9
  78. package/lib/transform/db/cdsPersistence.js +8 -7
  79. package/lib/transform/db/constraints.js +13 -10
  80. package/lib/transform/db/expansion.js +7 -3
  81. package/lib/transform/db/flattening.js +4 -14
  82. package/lib/transform/db/processSqlServices.js +2 -1
  83. package/lib/transform/db/temporal.js +5 -7
  84. package/lib/transform/db/views.js +2 -4
  85. package/lib/transform/draft/db.js +8 -8
  86. package/lib/transform/draft/odata.js +10 -7
  87. package/lib/transform/forOdata.js +10 -5
  88. package/lib/transform/forRelationalDB.js +5 -75
  89. package/lib/transform/localized.js +1 -1
  90. package/lib/transform/odata/createForeignKeys.js +11 -10
  91. package/lib/transform/odata/flattening.js +8 -4
  92. package/lib/transform/odata/foreignKeyRefsInXprAnnos.js +96 -0
  93. package/lib/transform/odata/typesExposure.js +3 -3
  94. package/lib/transform/transformUtils.js +4 -8
  95. package/lib/transform/translateAssocsToJoins.js +14 -7
  96. package/lib/transform/universalCsn/universalCsnEnricher.js +10 -4
  97. package/lib/utils/objectUtils.js +0 -17
  98. package/package.json +10 -13
  99. package/share/messages/def-upcoming-virtual-change.md +1 -1
  100. package/LICENSE +0 -37
  101. package/bin/cds_remove_invalid_whitespace.js +0 -138
  102. package/doc/CHANGELOG_ARCHIVE.md +0 -3604
  103. package/lib/gen/genericAntlrParser.js +0 -3
  104. package/lib/gen/language.checksum +0 -1
  105. package/lib/gen/language.interp +0 -456
  106. package/lib/gen/language.tokens +0 -180
  107. package/lib/gen/languageLexer.interp +0 -439
  108. package/lib/gen/languageLexer.js +0 -1483
  109. package/lib/gen/languageLexer.tokens +0 -167
  110. package/lib/gen/languageParser.js +0 -24941
  111. package/lib/language/antlrParser.js +0 -205
  112. package/lib/language/errorStrategy.js +0 -646
  113. package/lib/language/genericAntlrParser.js +0 -1572
  114. package/lib/parsers/CdlGrammar.g4 +0 -2070
@@ -5,7 +5,6 @@ const { forEachMemberRecursively, forAllQueries, applyTransformationsOnNonDictio
5
5
  getArtifactDatabaseNameOf, getElementDatabaseNameOf, applyTransformations,
6
6
  walkCsnPath, isPersistedOnDatabase
7
7
  } = require('../model/csnUtils');
8
- const { isBuiltinType } = require('../base/builtins');
9
8
  const transformUtils = require('./transformUtils');
10
9
  const { translateAssocsToJoinsCSN } = require('./translateAssocsToJoins');
11
10
  const { csnRefs, pathId, traverseQuery, columnAlias} = require('../model/csnRefs');
@@ -16,7 +15,7 @@ const { addTenantFields } = require('../transform/addTenantFields');
16
15
  const { addLocalizationViewsWithJoins, addLocalizationViews } = require('../transform/localized');
17
16
  const { timetrace } = require('../utils/timetrace');
18
17
  const { createReferentialConstraints, assertConstraintIdentifierUniqueness } = require('./db/constraints');
19
- const { createDict, forEach } = require('../utils/objectUtils');
18
+ const { forEach } = require('../utils/objectUtils');
20
19
  const handleExists = require('./db/assocsToQueries/transformExists');
21
20
  const { rewriteCalculatedElementsInViews, processCalculatedElementsInEntities } = require('./db/rewriteCalculatedElements');
22
21
  const replaceAssociationsInGroupByOrderBy = require('./db/groupByOrderBy');
@@ -403,10 +402,9 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
403
402
  assertConstraintIdentifierUniqueness(parent, path[1], path, error);
404
403
  },
405
404
  elements: (parent, prop, elements, path) => {
406
- // Attach @cds.persistence.name to elements, replace enums by their base value
405
+ // Attach @cds.persistence.name to elements
407
406
  const artifact = csn.definitions[path[1]];
408
407
  forEach(elements, (name, element) => {
409
- replaceEnums(element, name, path.concat(['elements', name]));
410
408
  if ((!element.virtual || artifact.query))
411
409
  csnUtils.addStringAnnotationTo('@cds.persistence.name', getElementDatabaseNameOf(name, options.sqlMapping, options.sqlDialect), element);
412
410
  });
@@ -467,7 +465,6 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
467
465
  includes: killProp,
468
466
  masked: killProp,
469
467
  localized: killProp,
470
- enum: killProp
471
468
  }
472
469
 
473
470
  if(options.sqlDialect === 'postgres') {
@@ -671,25 +668,6 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
671
668
  timetrace.stop('A2J');
672
669
  }
673
670
 
674
-
675
-
676
- /**
677
- * Replace Enum symbols by their values.
678
- *
679
- * Only applies to elements.
680
- *
681
- * @param {CSN.Element} obj
682
- * @param {String} objName
683
- * @param {CSN.Path} path
684
- */
685
- function replaceEnums(obj, objName, path) {
686
- // (190 a) Replace enum symbols by their value (if found)
687
- replaceEnumSymbolsByValues(obj, path);
688
-
689
- if (obj.enum)
690
- delete obj.enum;
691
- }
692
-
693
671
  // Change the names of those builtin types that have different names in HANA.
694
672
  // (do that directly in the csn where the builtin types are defined, so that
695
673
  // all users of the types benefit from it). Also add the type parameter 'length'
@@ -697,9 +675,10 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
697
675
  // TODO: there is no benefit at all - it is fundamentally wrong
698
676
  function renamePrimitiveTypesAndUuid(val, node, key) {
699
677
  // assert key === 'type'
700
- const hanaNamesMap = createDict({
678
+ const hanaNamesMap = {
679
+ __proto__: null,
701
680
  'cds.UUID': 'cds.String'
702
- });
681
+ };
703
682
  node[key] = hanaNamesMap[val] || val;
704
683
  if (val === 'cds.UUID' && !node.length) {
705
684
  node.length = 36;
@@ -722,55 +701,6 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
722
701
  // }
723
702
  // }
724
703
 
725
-
726
- // If 'elem' has a default that is an enum constant, replace that by its value. Complain
727
- // if not found or not an enum type,
728
- // usually done by the Core Compiler, but backend might be called directly
729
- function replaceEnumSymbolsByValues(elem, path) {
730
- // (190 a) Replace enum symbols by their value (if found)
731
- if (!elem.default?.['#'])
732
- return;
733
- if (elem.default.val !== undefined) {
734
- delete elem.default['#'];
735
- }
736
- else {
737
- let Enum = elem.enum;
738
- if (!Enum && !isBuiltinType(elem.type)) {
739
- const typeDef = csnUtils.getCsnDef(elem.type);
740
- Enum = typeDef && typeDef.enum;
741
- }
742
- if (!Enum) {
743
- // Not an enum at all
744
- // Looks like it is always run?! But message says HANA CDS?!
745
- error(null, path, {
746
- $reviewed: true,
747
- name: `#${ elem.default['#'] }`
748
- },
749
- 'Expecting enum literal $(NAME) to be used with an enum type');
750
- }
751
- else {
752
- // Try to get the corresponding enum symbol from the element's type
753
- const enumSymbol = Enum[elem.default['#']];
754
- if (!enumSymbol) {
755
- error(null, path, {
756
- $reviewed: true,
757
- name: `#${ elem.default['#'] }`
758
- }, 'Enum literal $(NAME) is undefined in enumeration type');
759
- }
760
- else if (enumSymbol.val !== undefined) { // `val` may be `null`
761
- // Replace default with enum value
762
- elem.default.val = enumSymbol.val;
763
- delete elem.default['#'];
764
- }
765
- else {
766
- // Enum symbol without explicit value - replace default by the symbol in string form
767
- elem.default.val = elem.default['#'];
768
- delete elem.default['#'];
769
- }
770
- }
771
- }
772
- }
773
-
774
704
  /**
775
705
  * Check that required actual parameters on 'node.type' are set, that their values are in the correct range etc.
776
706
 
@@ -659,7 +659,7 @@ function _addLocalizationViews(csn, options, config) {
659
659
  { art: name });
660
660
  }
661
661
  },
662
- });
662
+ }, messageFunctions.error);
663
663
  forEachDefinition(csn, checkAnnotationsOnLocalized);
664
664
  }
665
665
 
@@ -63,16 +63,16 @@ function createForeignKeyElements(csn, options, messageFunctions, csnUtils, iter
63
63
  }
64
64
 
65
65
  adaptAnnotationsRefs(generatedForeignKeys, csnUtils, messageFunctions);
66
- setProp(element, '$generatedForeignKeys', generatedForeignKeys.map(gfk => gfk.prefix));
66
+ setProp(element, '$generatedForeignKeys', generatedForeignKeys.map(gfk => {
67
+ return { name: gfk.prefix, origin: gfk.originalKey, source: gfk.sourceElement } } ));
67
68
  orderedElements.push(...generatedForeignKeys.map(gfk => [ gfk.prefix, gfk.foreignKey ]));
68
-
69
- });
69
+ });
70
70
 
71
- parent[prop] = orderedElements.reduce((elementsAccumulator, [ name, element ]) => {
72
- elementsAccumulator[name] = element;
73
- return elementsAccumulator;
74
- }, Object.create(null));
75
- }
71
+ parent[prop] = orderedElements.reduce((elementsAccumulator, [ name, element ]) => {
72
+ elementsAccumulator[name] = element;
73
+ return elementsAccumulator;
74
+ }, Object.create(null));
75
+ }
76
76
 
77
77
  function createForeignKeysForElement(path, element, prefix, csn, options, pathDelimiter, lvl = 0, originalKey = {} ) {
78
78
  const special$self = !csn?.definitions?.$self && '$self';
@@ -108,7 +108,7 @@ function createForeignKeyElements(csn, options, messageFunctions, csnUtils, iter
108
108
  // main if for this function
109
109
  // the element is a managed association
110
110
  if (csnUtils.isManagedAssociation(finalElement)) {
111
- finalElement.keys.forEach((key, keyIndex) => {
111
+ finalElement.keys?.forEach((key, keyIndex) => {
112
112
  const continuePath = getContinuePath([ 'keys', keyIndex ]);
113
113
  const alias = key.as || implicitAs(key.ref);
114
114
  const result = csnUtils.inspectRef(continuePath);
@@ -143,7 +143,8 @@ function createForeignKeyElements(csn, options, messageFunctions, csnUtils, iter
143
143
  if (element[prop] !== undefined)
144
144
  newFk[prop] = element[prop];
145
145
  });
146
- return [ { prefix, foreignKey: newFk, originalKey, keyAnnotations: [] } ];
146
+ let result = { prefix, foreignKey: newFk, originalKey, keyAnnotations: [], sourceElement: finalElement }
147
+ return [ result ];
147
148
  }
148
149
 
149
150
  fks.forEach((fk) => {
@@ -151,7 +151,7 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
151
151
  }
152
152
  // loop through types as well in order to collect the managaed associations
153
153
  // that reside in types definitions
154
- if ((def.kind === 'action' || def.kind === 'function' || def.kind === 'type' || def.kind === 'aspect' || def.kind === 'event')
154
+ if ((def.kind === 'action' || def.kind === 'function' || def.kind === 'type' || def.kind === 'aspect' || def.kind === 'event')
155
155
  && !isExternalServiceMember(def, defName)) {
156
156
  if (def.kind === 'type' && csnUtils.isManagedAssociation(def))
157
157
  allMgdAssocDefs.push(def);
@@ -472,7 +472,8 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, getFinalTy
472
472
  generatedForeignKeysForAssoc.forEach(gfk => gfk[1]['@odata.foreignKey4'] = flatEltName);
473
473
  // reassign the generated foreign keys for current assoc in order to assign
474
474
  // correct values for $generatedFieldName later on during flattenManagedAssocsAsKeys();
475
- setProp(flatElt, '$generatedForeignKeys', generatedForeignKeysForAssoc.map(gfk => gfk[0]));
475
+ // eslint-disable-next-line @stylistic/js/max-statements-per-line
476
+ setProp(flatElt, '$generatedForeignKeys', generatedForeignKeysForAssoc.map(gfk => { return { name: gfk[0] }}));
476
477
  }
477
478
  }
478
479
 
@@ -644,6 +645,9 @@ function replaceManagedAssocsAsKeys(allFlatManagedAssocDefinitions, csnUtils) {
644
645
  allFlatManagedAssocDefinitions.forEach( assoc => {
645
646
  let finished = false;
646
647
 
648
+ if (!assoc.keys)
649
+ return; // managed to-many assoc
650
+
647
651
  while (!finished) {
648
652
  const newKeys = [];
649
653
  finished = processKeys(newKeys);
@@ -670,8 +674,8 @@ function replaceManagedAssocsAsKeys(allFlatManagedAssocDefinitions, csnUtils) {
670
674
  // we do not generate foreign keys in the definition, therefore no $generatedForeignKeys,
671
675
  // respectively we do not assign $generatedFieldName
672
676
  if (assoc.$generatedForeignKeys) {
673
- const generatedForeignKey = assoc.$generatedForeignKeys.find(gfk => gfk === `${flatAssocName}_${key.as || key.ref.join('_')}`);
674
- key.$generatedFieldName = generatedForeignKey;
677
+ const generatedForeignKey = assoc.$generatedForeignKeys.find(gfk => gfk.name === `${flatAssocName}_${key.as || key.ref.join('_')}`);
678
+ key.$generatedFieldName = generatedForeignKey.name;
675
679
  }
676
680
  }
677
681
  if (key.as && key.as === key.ref[0]) delete key.as;
@@ -0,0 +1,96 @@
1
+ 'use strict'
2
+
3
+ const { applyTransformations, transformAnnotationExpression } = require('../../model/csnUtils');
4
+ const { isBuiltinType } = require('../../base/builtins');
5
+
6
+
7
+ function replaceForeignKeyRefsInExpressionAnnotations(csn, options, messageFunctions, csnUtils, iterateOptions = {}) {
8
+ const transformers = {
9
+ elements: processRef,
10
+ params: processRef,
11
+ actions: processRef
12
+ // '@': processRef
13
+ };
14
+ applyTransformations(csn, transformers, [ processRef ], iterateOptions);
15
+
16
+ function processRef(parent, prop, _dict, path) {
17
+ transformAnnotationExpression(parent, prop,
18
+ {
19
+ ref: (parent, _prop, ref, path, _p, _ppn, ctx) => {
20
+ const { art, links } =
21
+ (parent._art && parent._links) ?
22
+ { art: parent._art, links: parent._links } :
23
+ csnUtils.inspectRef(path);
24
+ // if a reference points to a structure(managed assoc or structured element), then we do not process
25
+ // as we can't guess which specific foreign key is targeted
26
+ if (!art || csnUtils.isManagedAssociation(art) || csnUtils.isStructured(art)) return;
27
+
28
+ const allMngAssocsInRef = links.filter(link => csnUtils.isManagedAssociation(link.art));
29
+ if (!allMngAssocsInRef.length) return;
30
+ let firstAssocToProcess = allMngAssocsInRef[0];
31
+
32
+ const mngAssocsWithFilter = allMngAssocsInRef.filter(assoc => typeof ref[assoc.idx] !== 'string');
33
+ if (mngAssocsWithFilter.length) {
34
+ const refTail = links.slice(mngAssocsWithFilter.at(-1).idx + 1);
35
+ firstAssocToProcess = refTail.find(link => csnUtils.isManagedAssociation(link.art));
36
+ }
37
+
38
+ const match = findMatchingForeignKeyForAssoc(firstAssocToProcess, art, ref, links);
39
+ if (match) {
40
+ const refHead = ref.slice(0, match.idx);
41
+ parent.ref = [...refHead, match.fkName];
42
+ if (ctx?.annoExpr?.['=']) {
43
+ ctx.annoExpr['='] = true;
44
+ }
45
+ }
46
+ }
47
+ },
48
+ path);
49
+ }
50
+
51
+ function findMatchingForeignKeyForAssoc(assoc, refArt, ref, links) {
52
+ if (!assoc) return undefined;
53
+
54
+ const expectedFkName = findExpectedFkName(assoc, ref, links);
55
+ const gfks = assoc.art?.$generatedForeignKeys;
56
+ if (!gfks) return undefined;
57
+ const matchedFk = gfks.find(fk => fk.source === refArt && fk.name === expectedFkName);
58
+ if (matchedFk) {
59
+ return { fkName: matchedFk.name, idx: assoc.idx };
60
+ } else {
61
+ // try to find FK substitution in the next assoc in the ref (if there is such assoc)
62
+ const refTail = links.slice(assoc.idx + 1);
63
+ const nextAssoc = refTail.find(link => csnUtils.isManagedAssociation(link.art));
64
+ return findMatchingForeignKeyForAssoc(nextAssoc, refArt, ref, links);
65
+ }
66
+
67
+
68
+ function findExpectedFkName(assoc, ref, links) {
69
+ let expectedFkName = ref[assoc.idx];
70
+ const refAliasMapping = assoc.art.keys.reduce( (acc, key) => {
71
+ acc[key.ref.join('_')] = key.as;
72
+ return acc;
73
+ }, {});
74
+ let bufferRef = [];
75
+ for (let i = assoc.idx + 1; i < links.length; i++) {
76
+ const link = links[i];
77
+ bufferRef.push(ref[i]);
78
+ if (csnUtils.isManagedAssociation(link.art)) {
79
+ const subFkName = findExpectedFkName(link, ref, links);
80
+ if (!subFkName) return undefined;
81
+ expectedFkName += bufferRef.length > 1 ?
82
+ `_${bufferRef.slice(0, -1).join('_')}_${subFkName}` :
83
+ `_${subFkName}`;
84
+ break;
85
+ } else if (isBuiltinType(link.art.type)) {
86
+ expectedFkName += `_${refAliasMapping[bufferRef.join('_')] || ref[i]}`;
87
+ bufferRef = [];
88
+ }
89
+
90
+ }
91
+ return expectedFkName;
92
+ }
93
+ }
94
+ }
95
+
96
+ module.exports = replaceForeignKeyRefsInExpressionAnnotations;
@@ -101,8 +101,8 @@ function typesExposure(csn, whatsMyServiceName, requestedServiceNames, fallBackS
101
101
  forEachGeneric(csn, 'vocabularies', (def, defName, _propertyName, path) => {
102
102
  const serviceName = whatsMyServiceName(defName, false);
103
103
  if (serviceName && requestedServiceNames.includes(serviceName)) {
104
- if(csn.definitions[defName]) {
105
- error('odata-definition-exists', ['vocabularies', defName], { anno: defName, '#':'anno' });
104
+ if (csn.definitions[defName]) {
105
+ error('odata-duplicate-definition', [ 'vocabularies', defName ], { anno: defName, '#': 'anno' });
106
106
  }
107
107
  else {
108
108
  // link def into definitions for later use
@@ -403,7 +403,7 @@ function typesExposure(csn, whatsMyServiceName, requestedServiceNames, fallBackS
403
403
  cloned.cardinality = {};
404
404
  cloned.cardinality.min = 1;
405
405
  }
406
- // if odata-spec-violation-key-null is checking on min>1, this can
406
+ // if odata-unexpected-nullable-key is checking on min>1, this can
407
407
  // be an else if
408
408
  if(cloned.notNull === undefined)
409
409
  cloned.notNull = true;
@@ -28,7 +28,6 @@ function getTransformers(model, options, msgFunctions, pathDelimiter = '_') {
28
28
  const {
29
29
  getCsnDef,
30
30
  getFinalTypeInfo,
31
- hasAnnotationValue,
32
31
  inspectRef,
33
32
  isStructured,
34
33
  effectiveType,
@@ -731,16 +730,13 @@ function getTransformers(model, options, msgFunctions, pathDelimiter = '_') {
731
730
  */
732
731
  function extractValidFromToKeyElement(element, path) {
733
732
  const validFroms = [], validTos = [], validKeys = [];
734
- if (hasAnnotationValue(element, '@cds.valid.from')) {
733
+ if (element['@cds.valid.from'])
735
734
  validFroms.push({ element, path: [...path] });
736
- }
737
- if (hasAnnotationValue(element, '@cds.valid.to')) {
735
+ if (element['@cds.valid.to'])
738
736
  validTos.push({ element, path: [...path] });
739
- }
740
- if (hasAnnotationValue(element, '@cds.valid.key')) {
737
+ if (element['@cds.valid.key'])
741
738
  validKeys.push({ element, path: [...path] });
742
- }
743
- return [validFroms, validTos, validKeys];
739
+ return [ validFroms, validTos, validKeys ];
744
740
  }
745
741
 
746
742
  /**
@@ -609,7 +609,7 @@ function translateAssocsToJoins(model, inputOptions = {})
609
609
  // TODO: why inner "parenthesise" - comparison in `and`?
610
610
  return parenthesise((args.length > 1 ? { op: { val: 'and' }, args: [ ...args.map(parenthesise) ] } : args[0] ));
611
611
  }
612
- else {
612
+ else if (assoc.on) {
613
613
  if(env.assocStack === undefined) {
614
614
  env.assocStack = [];
615
615
  env.assocStack.head = function() {
@@ -655,13 +655,19 @@ function translateAssocsToJoins(model, inputOptions = {})
655
655
  }
656
656
  }
657
657
  return path;
658
- }
658
+ };
659
659
  }
660
-
661
660
  env.assocStack.push(assoc);
662
661
  const onCond = cloneOnCondition(assoc.on);
663
662
  env.assocStack.pop();
664
663
  return compareTenants ? addTenantComparison(assoc, onCond) : onCond;
664
+
665
+ } else if (!hasPersistenceSkipAnnotation(assoc._main)) {
666
+ // TODO: exclude non-persisted entities from SQL generation; they may have
667
+ // to-many associations without foreign keys nor ON-condition.
668
+ throw new CompilerAssertion(`Association must have either ON-condition or foreign keys: ${assoc.name.id} at ${JSON.stringify(assoc.location)}`);
669
+ } else {
670
+ return null;
665
671
  }
666
672
 
667
673
  // Add tenant comparison
@@ -716,10 +722,7 @@ function translateAssocsToJoins(model, inputOptions = {})
716
722
  {
717
723
  //env.assocStack.includes(fwdAssoc) => recursion
718
724
  if(env.assocStack.length === 2) {
719
- // reuse (ugly) error message from forHana
720
- error(null, [env.assocStack[0].location,env.assocStack[0]],
721
- { name: '$self', id: '$self' },
722
- 'An association that uses $(NAME) in its ON-condition can\'t be compared to $(ID)');
725
+ error('type-invalid-self', [env.assocStack[0].location, env.assocStack[0]], { name: '$self' });
723
726
  // don't check these paths again
724
727
  args[i].$check = args[i+2].$check = false;
725
728
  }
@@ -1950,4 +1953,8 @@ function annotationVal( anno ) {
1950
1953
  return anno && (anno.val === undefined || anno.val);
1951
1954
  }
1952
1955
 
1956
+ function hasPersistenceSkipAnnotation( art ) {
1957
+ return art?.['@cds.persistence.skip']?.val && art['@cds.persistence.skip'].val !== 'if-unused';
1958
+ }
1959
+
1953
1960
  module.exports = { translateAssocsToJoinsCSN };
@@ -34,7 +34,7 @@ module.exports = (csn, options) => {
34
34
  // Example: `type E : F;` does not have `elements`, but they are required for e.g. OData.
35
35
  elements: onlyTypeDef,
36
36
  type: always,
37
- doc: nullStopsPropagation,
37
+ doc: options.propagateDocComments ? nullStopsPropagation : null,
38
38
  length: always,
39
39
  precision: always,
40
40
  scale: always,
@@ -529,8 +529,14 @@ module.exports = (csn, options) => {
529
529
  * @param {CSN.Element} member
530
530
  */
531
531
  function calculateForeignKeys( member ) {
532
- // managed assocs in universal CSN have no longer keys
533
- // if they are not explicitly defined - PR#8064
532
+ // Managed assocs in universal CSN have don't have 'keys'
533
+ // if they are not explicitly defined - PR#8064.
534
+
535
+ // Beware that since cds-compiler v6, managed _to-many_ associations don't get 'keys'.
536
+ const max = member.cardinality?.max ?? 1;
537
+ if (typeof max !== 'number' || max > 1)
538
+ return; // to-many assoc
539
+
534
540
  const target = artifactRef(member.target);
535
541
  const targetKeys = Object.keys(target.elements).filter(key => target.elements[key].key);
536
542
  member.keys = targetKeys.map(
@@ -582,7 +588,7 @@ module.exports = (csn, options) => {
582
588
  * @param {CSN.Artifact} rootArtifact The artifact that had the localized
583
589
  */
584
590
  function attachAnnosForTextsTable( parent, rootArtifact ) {
585
- const isFioriDraftEnabled = rootArtifact && (rootArtifact['@fiori.draft.enabled'] === true || getOriginChain(rootArtifact).some(({ origin }) => origin['@fiori.draft.enabled'] === true));
591
+ const isFioriDraftEnabled = rootArtifact && (rootArtifact['@fiori.draft.enabled'] || getOriginChain(rootArtifact).some(({ origin }) => origin['@fiori.draft.enabled']));
586
592
  if (isFioriDraftEnabled) {
587
593
  setAnnotationIfNotDefined(parent, '@assert.unique.locale', [ { '=': 'locale' } ]);
588
594
  forEach(rootArtifact.elements, (name, element) => {
@@ -13,22 +13,6 @@ function copyPropIfExist( sourceObj, property, targetObj ) {
13
13
  targetObj[property] = sourceObj[property];
14
14
  }
15
15
 
16
- /**
17
- * Takes an object and creates a dictionary out of it.
18
- * This avoids cases where e.g. properties named "toString" are interpreted
19
- * as JS internal functions.
20
- *
21
- * @param {object} obj Object with prototype.
22
- * @return {object} Object without prototype, i.e. a dict.
23
- */
24
- function createDict( obj ) {
25
- const dict = Object.create(null);
26
- const keys = Object.keys(obj);
27
- for (const key of keys)
28
- dict[key] = obj[key];
29
- return dict;
30
- }
31
-
32
16
  /**
33
17
  * Loops over all elements in an object and calls the specified callback(key,obj)
34
18
  *
@@ -97,7 +81,6 @@ function hasNonEnumerable( object, propertyName ) {
97
81
 
98
82
  module.exports = {
99
83
  copyPropIfExist,
100
- createDict,
101
84
  forEach,
102
85
  forEachValue,
103
86
  forEachKey,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds-compiler",
3
- "version": "5.9.4",
3
+ "version": "6.0.12",
4
4
  "description": "CDS (Core Data Services) compiler and backends",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "author": "SAP SE (https://www.sap.com)",
@@ -14,11 +14,13 @@
14
14
  "main": "lib/main.js",
15
15
  "types": "lib/main.d.ts",
16
16
  "scripts": {
17
- "download": "node scripts/downloadANTLR.js",
18
- "gen": "node ./scripts/build.js && node scripts/genGrammarChecksum.js && node ./redepage/bin/redepage --compile lib/gen/CdlParser.js --copy-base-parser lib/parsers/CdlGrammar.g4",
17
+ "download": "exit 0",
18
+ "gen": "npm run rdpg",
19
+ "rdpg": "node ./redepage/bin/redepage --compile lib/gen/CdlParser.js --copy-base-parser lib/parsers/CdlGrammar.g4 && node scripts/genGrammarChecksum.js",
19
20
  "xmakeAfterInstall": "npm run gen",
20
21
  "xmakePrepareRelease": "echo \"$(node scripts/stripReadme.js README.md)\" > README.md && node scripts/assertSnapshotVersioning.js && node scripts/assertChangelog.js && node scripts/cleanup.js --remove-dev",
21
- "test": "npm run test:piper",
22
+ "test": "node scripts/xmakeTestDispatcher.js",
23
+ "test:xmake": "npm run test3 -- --topic=Drafts --test=CalculatedElements",
22
24
  "test:ci": "node scripts/verifyGrammarChecksum.js && mocha --timeout 10000 --reporter-option maxDiffSize=0 scripts/testLazyLoading.js && mocha --parallel --reporter-option maxDiffSize=0 test/ test3/",
23
25
  "test:piper": "node scripts/verifyGrammarChecksum.js && npm run coverage:piper",
24
26
  "test3": "node scripts/verifyGrammarChecksum.js && mocha --reporter-option maxDiffSize=0 test3/",
@@ -33,7 +35,8 @@
33
35
  "gentest3": "cross-env MAKEREFS=${MAKEREFS:-'true'} mocha --reporter-option maxDiffSize=0 test3/testRefFiles.js",
34
36
  "coverage": "cross-env nyc mocha --reporter-option maxDiffSize=0 test/ test3/testRefFiles.js && nyc report --reporter=lcov",
35
37
  "coverage:piper": "cross-env nyc mocha --reporter test/TestMochaReporter.js --reporter-options mochaFile=./coverage/TEST-results.xml --reporter-option maxDiffSize=0 --timeout 10000 test/ test3/ && nyc report --reporter=cobertura && nyc report --reporter=lcov",
36
- "lint": "eslint bin/ benchmark/ lib/ test/ test3/ scripts/ && node scripts/linter/lintGrammar.js && node scripts/linter/lintTests.js test3/ && node scripts/linter/lintMessages.js && node scripts/linter/lintMessageIdCoverage.js lib/ && markdownlint README.md CHANGELOG.md doc/ internalDoc/ && cd share/messages && markdownlint . && cd ../../ && node scripts/check-changelog.js",
38
+ "lint": "eslint bin/ benchmark/ lib/ test/ test3/ scripts/ && node scripts/linter/lintConstants.js && node scripts/linter/lintGrammar.js && node scripts/linter/lintTests.js test3/ && node scripts/linter/lintMessages.js && node scripts/linter/lintMessageIdCoverage.js lib/ && markdownlint README.md CHANGELOG.md doc/ internalDoc/ && cd share/messages && markdownlint . && cd ../../ && node scripts/check-changelog.js",
39
+ "lint:edmx": "node scripts/odata/lint-edmx-v4.js",
37
40
  "tslint": "tsc --pretty -p .",
38
41
  "updateVocs": "node scripts/odataAnnotations/generateDictMain.js && npm run generateAllRefs",
39
42
  "updateTocs": "node scripts/update-toc.js",
@@ -51,20 +54,14 @@
51
54
  "keywords": [
52
55
  "CDS"
53
56
  ],
54
- "dependencies": {
55
- "antlr4": "4.9.3"
56
- },
57
57
  "files": [
58
58
  "bin",
59
59
  "lib",
60
60
  "doc",
61
61
  "share",
62
- "package.json",
63
- "README.md",
64
- "CHANGELOG.md",
65
- "LICENSE"
62
+ "CHANGELOG.md"
66
63
  ],
67
64
  "engines": {
68
- "node": ">=18"
65
+ "node": ">=20"
69
66
  }
70
67
  }
@@ -21,7 +21,7 @@ entity Proj as projection on Source {
21
21
  In `@sap/cds-compiler` v5 and earlier, element `Proj:a` is a reference
22
22
  to element `Source:a`, which was marked virtual.
23
23
 
24
- In `@sap/cds-compiler` v6 and later, it will instead of a _new_ element,
24
+ In `@sap/cds-compiler` v6 and later, it will instead be a _new_ element,
25
25
  without any reference to `Source:a`.
26
26
 
27
27
  This may or may not affect your runtime coding, hence the warning.
package/LICENSE DELETED
@@ -1,37 +0,0 @@
1
- SAP DEVELOPER LICENSE AGREEMENT
2
-
3
- Version 3.1
4
-
5
- Please scroll down and read the following Developer License Agreement carefully ("Developer Agreement"). By clicking "I Accept" or by attempting to download, or install, or use the SAP software and other materials that accompany this Developer Agreement ("SAP Materials"), You agree that this Developer Agreement forms a legally binding agreement between You ("You" or "Your") and SAP SE, for and on behalf of itself and its subsidiaries and affiliates (as defined in Section 15 of the German Stock Corporation Act) and You agree to be bound by all of the terms and conditions stated in this Developer Agreement. If You are trying to access or download the SAP Materials on behalf of Your employer or as a consultant or agent of a third party (either "Your Company"), You represent and warrant that You have the authority to act on behalf of and bind Your Company to the terms of this Developer Agreement and everywhere in this Developer Agreement that refers to 'You' or 'Your' shall also include Your Company. If You do not agree to these terms, do not click "I Accept", and do not attempt to access or use the SAP Materials.
6
-
7
- 1. LICENSE: SAP grants You a non-exclusive, non-transferable, non-sublicensable, revocable, limited use license to copy, reproduce and distribute the application programming interfaces ("API"), documentation, plug-ins, templates, scripts and sample code ("Tools") on a desktop, laptop, tablet, smart phone, or other appropriate computer device that You own or control (any, a "Computer") to create new applications ("Customer Applications"). You agree that the Customer Applications will not: (a) unreasonably impair, degrade or reduce the performance or security of any SAP software applications, services or related technology ("Software"); (b) enable the bypassing or circumventing of SAP's license restrictions and/or provide users with access to the Software to which such users are not licensed; (c) render or provide, without prior written consent from SAP, any information concerning SAP software license terms, Software, or any other information related to SAP products; or (d) permit mass data extraction from an SAP product to a non-SAP product, including use, modification, saving or other processing of such data in the non-SAP product. In exchange for the right to develop Customer Applications under this Agreement, You covenant not to assert any Intellectual Property Rights in Customer Applications created by You against any SAP product, service, or future SAP development.
8
-
9
- 2. INTELLECTUAL PROPERTY: (a) SAP or its licensors retain all ownership and intellectual property rights in the APIs, Tools and Software. You may not: a) remove or modify any marks or proprietary notices of SAP, b) provide or make the APIs, Tools or Software available to any third party, c) assign this Developer Agreement or give or transfer the APIs, Tools or Software or an interest in them to another individual or entity, d) decompile, disassemble or reverse engineer (except to the extent permitted by applicable law) the APIs Tools or Software, (e) create derivative works of or based on the APIs, Tools or Software, (f) use any SAP name, trademark or logo, or (g) use the APIs or Tools to modify existing Software or other SAP product functionality or to access the Software or other SAP products' source code or metadata.
10
- (b) Subject to SAP's underlying rights in any part of the APIs, Tools or Software, You retain all ownership and intellectual property rights in Your Customer Applications.
11
-
12
- 3. FREE AND OPEN SOURCE COMPONENTS: The SAP Materials may include certain third party free or open source components ("FOSS Components"). You may have additional rights in such FOSS Components that are provided by the third party licensors of those components.
13
-
14
- 4. THIRD PARTY DEPENDENCIES: The SAP Materials may require certain third party software dependencies ("Dependencies") for the use or operation of such SAP Materials. These dependencies may be identified by SAP in Maven POM files, product documentation or by other means. SAP does not grant You any rights in or to such Dependencies under this Developer Agreement. You are solely responsible for the acquisition, installation and use of Dependencies. SAP DOES NOT MAKE ANY REPRESENTATIONS OR WARRANTIES IN RESPECT OF DEPENDENCIES, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY AND OF FITNESS FOR A PARTICULAR PURPOSE. IN PARTICULAR, SAP DOES NOT WARRANT THAT DEPENDENCIES WILL BE AVAILABLE, ERROR FREE, INTEROPERABLE WITH THE SAP MATERIALS, SUITABLE FOR ANY PARTICULAR PURPOSE OR NON-INFRINGING. YOU ASSUME ALL RISKS ASSOCIATED WITH THE USE OF DEPENDENCIES, INCLUDING WITHOUT LIMITATION RISKS RELATING TO QUALITY, AVAILABILITY, PERFORMANCE, DATA LOSS, UTILITY IN A PRODUCTION ENVIRONMENT, AND NON-INFRINGEMENT. IN NO EVENT WILL SAP BE LIABLE DIRECTLY OR INDIRECTLY IN RESPECT OF ANY USE OF DEPENDENCIES BY YOU.
15
-
16
-
17
- 5. WARRANTY:
18
- a) If You are located outside the US or Canada: AS THE API AND TOOLS ARE PROVIDED TO YOU FREE OF CHARGE, SAP DOES NOT GUARANTEE OR WARRANT ANY FEATURES OR QUALITIES OF THE TOOLS OR API OR GIVE ANY UNDERTAKING WITH REGARD TO ANY OTHER QUALITY. NO SUCH WARRANTY OR UNDERTAKING SHALL BE IMPLIED BY YOU FROM ANY DESCRIPTION IN THE API OR TOOLS OR ANY AVAILABLE DOCUMENTATION OR ANY OTHER COMMUNICATION OR ADVERTISEMENT. IN PARTICULAR, SAP DOES NOT WARRANT THAT THE SOFTWARE WILL BE AVAILABLE UNINTERRUPTED, ERROR FREE, OR PERMANENTLY AVAILABLE. FOR THE TOOLS AND API ALL WARRANTY CLAIMS ARE SUBJECT TO THE LIMITATION OF LIABILITY STIPULATED IN SECTION 4 BELOW.
19
- b) If You are located in the US or Canada: THE API AND TOOLS ARE LICENSED TO YOU "AS IS", WITHOUT ANY WARRANTY, ESCROW, TRAINING, MAINTENANCE, OR SERVICE OBLIGATIONS WHATSOEVER ON THE PART OF SAP. SAP MAKES NO EXPRESS OR IMPLIED WARRANTIES OR CONDITIONS OF SALE OF ANY TYPE WHATSOEVER, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY AND OF FITNESS FOR A PARTICULAR PURPOSE. IN PARTICULAR, SAP DOES NOT WARRANT THAT THE SOFTWARE WILL BE AVAILABLE UNINTERRUPTED, ERROR FREE, OR PERMANENTLY AVAILABLE. YOU ASSUME ALL RISKS ASSOCIATED WITH THE USE OF THE API AND TOOLS, INCLUDING WITHOUT LIMITATION RISKS RELATING TO QUALITY, AVAILABILITY, PERFORMANCE, DATA LOSS, AND UTILITY IN A PRODUCTION ENVIRONMENT.
20
-
21
- 6. LIMITATION OF LIABILITY:
22
- a) If You are located outside the US or Canada: IRRESPECTIVE OF THE LEGAL REASONS, SAP SHALL ONLY BE LIABLE FOR DAMAGES UNDER THIS AGREEMENT IF SUCH DAMAGE (I) CAN BE CLAIMED UNDER THE GERMAN PRODUCT LIABILITY ACT OR (II) IS CAUSED BY INTENTIONAL MISCONDUCT OF SAP OR (III) CONSISTS OF PERSONAL INJURY. IN ALL OTHER CASES, NEITHER SAP NOR ITS EMPLOYEES, AGENTS AND SUBCONTRACTORS SHALL BE LIABLE FOR ANY KIND OF DAMAGE OR CLAIMS HEREUNDER.
23
- b) If You are located in the US or Canada: IN NO EVENT SHALL SAP BE LIABLE TO YOU, YOUR COMPANY OR TO ANY THIRD PARTY FOR ANY DAMAGES IN AN AMOUNT IN EXCESS OF $100 ARISING IN CONNECTION WITH YOUR USE OF OR INABILITY TO USE THE TOOLS OR API OR IN CONNECTION WITH SAP'S PROVISION OF OR FAILURE TO PROVIDE SERVICES PERTAINING TO THE TOOLS OR API, OR AS A RESULT OF ANY DEFECT IN THE API OR TOOLS. THIS DISCLAIMER OF LIABILITY SHALL APPLY REGARDLESS OF THE FORM OF ACTION THAT MAY BE BROUGHT AGAINST SAP, WHETHER IN CONTRACT OR TORT, INCLUDING WITHOUT LIMITATION ANY ACTION FOR NEGLIGENCE. YOUR SOLE REMEDY IN THE EVENT OF BREACH OF THIS DEVELOPER AGREEMENT BY SAP OR FOR ANY OTHER CLAIM RELATED TO THE API OR TOOLS SHALL BE TERMINATION OF THIS AGREEMENT. NOTWITHSTANDING ANYTHING TO THE CONTRARY HEREIN, UNDER NO CIRCUMSTANCES SHALL SAP AND ITS LICENSORS BE LIABLE TO YOU OR ANY OTHER PERSON OR ENTITY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, OR INDIRECT DAMAGES, LOSS OF GOOD WILL OR BUSINESS PROFITS, WORK STOPPAGE, DATA LOSS, COMPUTER FAILURE OR MALFUNCTION, ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSS, OR EXEMPLARY OR PUNITIVE DAMAGES.
24
-
25
- 7. INDEMNITY: You will fully indemnify, hold harmless and defend SAP against law suits based on any claim: (a) that any Customer Application created by You infringes or misappropriates any patent, copyright, trademark, trade secrets, or other proprietary rights of a third party, or (b) related to Your alleged violation of the terms of this Developer Agreement.
26
-
27
- 8. EXPORT: The Tools and API are subject to German, EU and US export control regulations. You confirm that: a) You will not use the Tools or API for, and will not allow the Tools or API to be used for, any purposes prohibited by German, EU and US law, including, without limitation, for the development, design, manufacture or production of nuclear, chemical or biological weapons of mass destruction; b) You are not located in Cuba, Iran, Sudan, Iraq, North Korea, Syria, nor any other country to which the United States has prohibited export or that has been designated by the U.S. Government as a "terrorist supporting" country (any, an "US Embargoed Country"); c) You are not a citizen, national or resident of, and are not under the control of, a US Embargoed Country; d) You will not download or otherwise export or re-export the API or Tools, directly or indirectly, to a US Embargoed Country nor to citizens, nationals or residents of a US Embargoed Country; e) You are not listed on the United States Department of Treasury lists of Specially Designated Nationals, Specially Designated Terrorists, and Specially Designated Narcotic Traffickers, nor listed on the United States Department of Commerce Table of Denial Orders or any other U.S. government list of prohibited or restricted parties and f) You will not download or otherwise export or re-export the API or Tools , directly or indirectly, to persons on the above-mentioned lists.
28
-
29
- 9. SUPPORT: Other than what is made available on the SAP Community Website (SCN) by SAP at its sole discretion and by SCN members, SAP does not offer support for the API or Tools which are the subject of this Developer Agreement.
30
-
31
- 10. TERM AND TERMINATION: You may terminate this Developer Agreement by destroying all copies of the API and Tools on Your Computer(s). SAP may terminate Your license to use the API and Tools immediately if You fail to comply with any of the terms of this Developer Agreement, or, for SAP's convenience by providing you with ten (10) day's written notice of termination (including email). In case of termination or expiration of this Developer Agreement, You must destroy all copies of the API and Tools immediately. In the event Your Company or any of the intellectual property you create using the API, Tools or Software are acquired (by merger, purchase of stock, assets or intellectual property or exclusive license), or You become employed, by a direct competitor of SAP, then this Development Agreement and all licenses granted in this Developer Agreement shall immediately terminate upon the date of such acquisition.
32
-
33
- 11. LAW/VENUE:
34
- a) If You are located outside the US or Canada: This Developer Agreement is governed by and construed in accordance with the laws of the Germany. You and SAP agree to submit to the exclusive jurisdiction of, and venue in, the courts of Karlsruhe in Germany in any dispute arising out of or relating to this Developer Agreement.
35
- b) If You are located in the US or Canada: This Developer Agreement shall be governed by and construed under the Commonwealth of Pennsylvania law without reference to its conflicts of law principles. In the event of any conflicts between foreign law, rules, and regulations, and United States of America law, rules, and regulations, United States of America law, rules, and regulations shall prevail and govern. The United Nations Convention on Contracts for the International Sale of Goods shall not apply to this Developer Agreement. The Uniform Computer Information Transactions Act as enacted shall not apply.
36
-
37
- 12. MISCELLANEOUS: This Developer Agreement is the complete agreement for the API and Tools licensed (including reference to information/documentation contained in a URL). This Developer Agreement supersedes all prior or contemporaneous agreements or representations with regards to the subject matter of this Developer Agreement. If any term of this Developer Agreement is found to be invalid or unenforceable, the surviving provisions shall remain effective. SAP's failure to enforce any right or provisions stipulated in this Developer Agreement will not constitute a waiver of such provision, or any other provision of this Developer Agreement.