@sap/cds-dk 8.9.15 → 8.9.16

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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,13 @@ This project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  The format is based on [Keep a Changelog](https://keepachangelog.com/).
9
9
 
10
+ ## Version 8.9.16 - 2026-03-12
11
+
12
+ ### Fixed
13
+
14
+ - `cds import` now correctly imports views with parameters
15
+ - `cds import` now correctly handles OData referential constraints
16
+
10
17
  ## Version 8.9.15 - 2026-02-27
11
18
 
12
19
  ### Fixed
@@ -407,7 +407,7 @@ function _validateAnnotationNamespace(annotationTerm, vocabNamespaceToAlias) {
407
407
  if (aliasOrNamespace === "cds") {
408
408
  return
409
409
  }
410
-
410
+
411
411
  for (let alias of Object.values(known_vocabularies)) {
412
412
  if (alias === aliasOrNamespace) {
413
413
  return;
@@ -673,6 +673,19 @@ function _parseAssociationProperty(foreignReference, associationNode, parserCont
673
673
  '=',
674
674
  {ref: ['$self']}
675
675
  ]
676
+ } else if (associationNode.$ReferentialConstraint) {
677
+ associationProperty.on = []
678
+ for (const constraint in associationNode.$ReferentialConstraint) {
679
+ if (associationProperty.on.length) {
680
+ associationProperty.on.push('and')
681
+ }
682
+ associationProperty.on.push(
683
+ { ref: [foreignReference, associationNode.$ReferentialConstraint[constraint]] },
684
+ '=',
685
+ { ref: [constraint] }
686
+ )
687
+ }
688
+
676
689
  } else if (common.checkForEmptyKeys(associationProperty, "V4")) {
677
690
  associationProperty.keys = [];
678
691
  }
@@ -719,52 +732,63 @@ function _parsePropertyContent(csnObj, elementObj, parserContext) {
719
732
  const isPrimaryKey = true;
720
733
  let dataType, isPrimitiveType, keySet = [];
721
734
 
722
- Object.keys(elementObj).forEach(objKey => {
723
- const contentKind = elementObj[objKey].$Kind;
724
- contentObj = elementObj[objKey];
725
-
726
- if ((objKey.indexOf('@') === -1) && (objKey.indexOf('.') === -1)) {
727
- if (contentObj instanceof Object) {
728
- if (contentObj.$Type) {
729
- dataType = contentObj.$Type;
730
- isPrimitiveType = dataType.startsWith('Edm') ? true : false;
731
- }
732
- if (objKey === '$Key') {
733
- keySet.push(...elementObj.$Key);
734
- }
735
- // primitive datatypes
736
- else if (isPrimitiveType) {
737
- if (edmPrimitiveTypes.includes(dataType)) {
738
- csnObj.elements[objKey] = _generatePrimitiveDataTypeCsn(contentObj,
739
- (keySet.includes(objKey) ? isPrimaryKey : !isPrimaryKey),
740
- parserContext
741
- );
742
- } else {
743
- throw new Error(messages.INVALID_DATATYPE + `'${dataType}' in element: '${objKey}'`)
735
+ const sortedElements = Object.keys(elementObj)
736
+ .sort((ele1, ele2) => {
737
+ if (elementObj[ele1]?.$Kind === elementObj[ele2]?.$Kind) {
738
+ return 0
739
+ } else if (elementObj[ele1]?.$Kind === 'NavigationProperty') {
740
+ return 1
741
+ } else if (elementObj[ele2]?.$Kind === 'NavigationProperty') {
742
+ return -1
743
+ }
744
+ return 0
745
+ })
746
+ sortedElements.forEach(objKey => {
747
+ const contentKind = elementObj[objKey].$Kind;
748
+ contentObj = elementObj[objKey];
749
+
750
+ if ((objKey.indexOf('@') === -1) && (objKey.indexOf('.') === -1)) {
751
+ if (contentObj instanceof Object) {
752
+ if (contentObj.$Type) {
753
+ dataType = contentObj.$Type;
754
+ isPrimitiveType = dataType.startsWith('Edm') ? true : false;
744
755
  }
745
- }
746
- // structured datatypes
747
- else if (!isPrimitiveType && !(contentKind === 'NavigationProperty')) {
748
- const dataKind = _checkIsStructureTypeAndReturnDataKind(dataType, contentObj, 'property', parserContext);
749
-
750
- if (['EnumType', 'TypeDefinition'].includes(dataKind)) {
751
- csnObj.elements[objKey] = _generateStructuredDataTypeCsn(dataType, contentObj,
752
- (keySet.includes(dataType) ? isPrimaryKey : !isPrimaryKey),
753
- dataKind, 'property', parserContext
754
- );
756
+ if (objKey === '$Key') {
757
+ keySet.push(...elementObj.$Key);
755
758
  }
756
- else {
757
- csnObj.elements[objKey] = _generateStructuredDataTypeCsn(dataType, contentObj,
758
- !isPrimaryKey, dataKind, 'property', parserContext
759
- );
759
+ // primitive datatypes
760
+ else if (isPrimitiveType) {
761
+ if (edmPrimitiveTypes.includes(dataType)) {
762
+ csnObj.elements[objKey] = _generatePrimitiveDataTypeCsn(contentObj,
763
+ (keySet.includes(objKey) ? isPrimaryKey : !isPrimaryKey),
764
+ parserContext
765
+ );
766
+ } else {
767
+ throw new Error(messages.INVALID_DATATYPE + `'${dataType}' in element: '${objKey}'`)
768
+ }
769
+ }
770
+ // structured datatypes
771
+ else if (!isPrimitiveType && !(contentKind === 'NavigationProperty')) {
772
+ const dataKind = _checkIsStructureTypeAndReturnDataKind(dataType, contentObj, 'property', parserContext);
773
+
774
+ if (['EnumType', 'TypeDefinition'].includes(dataKind)) {
775
+ csnObj.elements[objKey] = _generateStructuredDataTypeCsn(dataType, contentObj,
776
+ (keySet.includes(objKey) ? isPrimaryKey : !isPrimaryKey),
777
+ dataKind, 'property', parserContext
778
+ );
779
+ }
780
+ else {
781
+ csnObj.elements[objKey] = _generateStructuredDataTypeCsn(dataType, contentObj,
782
+ !isPrimaryKey, dataKind, 'property', parserContext
783
+ );
784
+ }
785
+ }
786
+ else if (contentKind === 'NavigationProperty') {
787
+ csnObj.elements[objKey] = _parseAssociationProperty(objKey, elementObj[objKey], parserContext);
760
788
  }
761
- }
762
- else if (contentKind === 'NavigationProperty') {
763
- csnObj.elements[objKey] = _parseAssociationProperty(objKey, elementObj[objKey], parserContext);
764
789
  }
765
790
  }
766
- }
767
- });
791
+ });
768
792
  }
769
793
 
770
794
  function _addBlobElement() {
@@ -1433,7 +1457,7 @@ function _collectBoundActionFunction(isAction, currNamespace, elementName, eleme
1433
1457
 
1434
1458
  // binding parameter type should be within the available namespaces in the scope of a document.
1435
1459
  if (entityTypeNamespace !== schemaName && entityTypeNamespace !== parserContext.schemaAliasToNamespace[schemaName]) {
1436
-
1460
+
1437
1461
  // checking if the namespace is available in other schema of the document
1438
1462
  if (parserContext.schemaToSchemaDataIndex.hasOwnProperty(schemaName)) {
1439
1463
  entityTypeNamespace = schemaName;
@@ -1603,8 +1627,7 @@ function _preProcess(edmxAsJson, parserContext, importerContext) {
1603
1627
  parserContext.entityToEntitySetMap._.size === 0 &&
1604
1628
  parserContext.entityToSingletonMap._.size === 0 &&
1605
1629
  parserContext.actionToActionImportMap._.size === 0 &&
1606
- parserContext.functionToFunctionImportMap._.size === 0)
1607
- {
1630
+ parserContext.functionToFunctionImportMap._.size === 0) {
1608
1631
  parserContext.mockServerUc = false;
1609
1632
  }
1610
1633
 
@@ -1666,22 +1689,57 @@ function _generateCSN(edmxAsJson, ignorePersistenceSkip, parserContext, importer
1666
1689
  //
1667
1690
  // This happens after Step 8 because that adjusts the names of entity container entities where
1668
1691
  // entity type and entity set differ in naming
1669
- for (const entity in csn.definitions) {
1670
- if (entity.type !== 'entity') continue;
1671
-
1672
- const containingCompositions = Object.keys(csn.definitions[entity].elements).filter(e =>
1673
- csn.definitions[entity].elements[e].type === 'cds.Composition' &&
1674
- csn.definitions[entity].elements[e].on
1692
+ for (const [eName, entity] of Object.entries(csn.definitions)) {
1693
+ if (entity.kind !== 'entity') continue;
1694
+ const containingCompositions = Object.keys(entity.elements).filter(e =>
1695
+ entity.elements[e].type === 'cds.Composition' &&
1696
+ entity.elements[e].on
1675
1697
  );
1676
1698
  for (const comp of containingCompositions) {
1677
- const compTarget = csn.definitions[csn.definitions[entity].elements[comp].target];
1678
- const backLink = Object.keys(compTarget.elements).find(e =>
1679
- compTarget.elements[e].type === 'cds.Association' &&
1680
- compTarget.elements[e].target === entity
1699
+ const compTarget = csn.definitions[entity.elements[comp].target];
1700
+ const backLink = Object.keys(compTarget.elements).find(e =>
1701
+ compTarget.elements[e].type === 'cds.Association' &&
1702
+ compTarget.elements[e].target === eName
1681
1703
  )
1682
- if (compTarget.elements[backLink].keys) {
1704
+ const entityKeys = Object.keys(entity.elements).filter(ele => entity.elements[ele].key)
1705
+ if (compTarget.elements[backLink]?.keys && !entityKeys.some(key => compTarget.elements[backLink + '_' + key])) {
1683
1706
  delete compTarget.elements[backLink].keys
1684
1707
  }
1708
+
1709
+ // 3. View with parameters handling. In OData if the entity has a Composition Set with a backlink Parameters and every
1710
+ // other element is a key, its a View with Parameters. Import it as such to ensure proper outbound handling
1711
+ if (
1712
+ comp === 'Set' && backLink === 'Parameters' &&
1713
+ Object.keys(entity.elements).filter(e => entity.elements[e].key).length + 1 === Object.keys(entity.elements).length
1714
+ ) {
1715
+ const actualEntity = csn.definitions[entity.elements[comp].target];
1716
+ const actualEntityName = entity.elements[comp].target
1717
+ // Adjust entity so that the current elements are parameters, remove Set, remove key flags
1718
+ delete entity.elements[comp];
1719
+ entity.params = {}
1720
+ for (const ele in entity.elements) {
1721
+ delete entity.elements[ele].key;
1722
+ entity.params[ele] = entity.elements[ele];
1723
+ }
1724
+ delete entity.elements
1725
+ // Move compTarget out of service
1726
+ // Get rid of service prefix
1727
+ let nameWithoutService = eName.split(parserContext.primarySchema).pop();
1728
+ // Get rid of leading dot
1729
+ nameWithoutService = nameWithoutService.substring(1, nameWithoutService.length)
1730
+ csn.definitions[nameWithoutService] = actualEntity;
1731
+ delete csn.definitions[actualEntityName];
1732
+ delete csn.definitions[nameWithoutService].elements['Parameters'];
1733
+ // Adjust entity to * query from compTarget
1734
+ entity.query = {
1735
+ SELECT: {
1736
+ from: {
1737
+ ref: [nameWithoutService]
1738
+ },
1739
+ columns: ["*"]
1740
+ }
1741
+ }
1742
+ }
1685
1743
  }
1686
1744
  }
1687
1745
 
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@sap/cds-dk",
3
- "version": "8.9.15",
3
+ "version": "8.9.16",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@sap/cds-dk",
9
- "version": "8.9.15",
9
+ "version": "8.9.16",
10
10
  "license": "SEE LICENSE IN LICENSE",
11
11
  "dependencies": {
12
12
  "@cap-js/asyncapi": "^1.0.0",
@@ -109,12 +109,12 @@
109
109
  }
110
110
  },
111
111
  "node_modules/@eslint/config-array": {
112
- "version": "0.21.1",
112
+ "version": "0.21.2",
113
113
  "license": "Apache-2.0",
114
114
  "dependencies": {
115
115
  "@eslint/object-schema": "^2.1.7",
116
116
  "debug": "^4.3.1",
117
- "minimatch": "^3.1.2"
117
+ "minimatch": "^3.1.5"
118
118
  },
119
119
  "engines": {
120
120
  "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -141,7 +141,7 @@
141
141
  }
142
142
  },
143
143
  "node_modules/@eslint/eslintrc": {
144
- "version": "3.3.4",
144
+ "version": "3.3.5",
145
145
  "license": "MIT",
146
146
  "dependencies": {
147
147
  "ajv": "^6.14.0",
@@ -151,7 +151,7 @@
151
151
  "ignore": "^5.2.0",
152
152
  "import-fresh": "^3.2.1",
153
153
  "js-yaml": "^4.1.1",
154
- "minimatch": "^3.1.3",
154
+ "minimatch": "^3.1.5",
155
155
  "strip-json-comments": "^3.1.1"
156
156
  },
157
157
  "engines": {
@@ -162,7 +162,7 @@
162
162
  }
163
163
  },
164
164
  "node_modules/@eslint/js": {
165
- "version": "9.39.3",
165
+ "version": "9.39.4",
166
166
  "license": "MIT",
167
167
  "engines": {
168
168
  "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -230,7 +230,7 @@
230
230
  }
231
231
  },
232
232
  "node_modules/@sap/cds": {
233
- "version": "8.9.8",
233
+ "version": "8.9.9",
234
234
  "license": "SEE LICENSE IN LICENSE",
235
235
  "dependencies": {
236
236
  "@sap/cds-compiler": "^5",
@@ -476,7 +476,7 @@
476
476
  "license": "MIT"
477
477
  },
478
478
  "node_modules/axios": {
479
- "version": "1.13.5",
479
+ "version": "1.13.6",
480
480
  "license": "MIT",
481
481
  "dependencies": {
482
482
  "follow-redirects": "^1.15.11",
@@ -921,22 +921,22 @@
921
921
  }
922
922
  },
923
923
  "node_modules/eslint": {
924
- "version": "9.39.3",
924
+ "version": "9.39.4",
925
925
  "license": "MIT",
926
926
  "dependencies": {
927
927
  "@eslint-community/eslint-utils": "^4.8.0",
928
928
  "@eslint-community/regexpp": "^4.12.1",
929
- "@eslint/config-array": "^0.21.1",
929
+ "@eslint/config-array": "^0.21.2",
930
930
  "@eslint/config-helpers": "^0.4.2",
931
931
  "@eslint/core": "^0.17.0",
932
- "@eslint/eslintrc": "^3.3.1",
933
- "@eslint/js": "9.39.3",
932
+ "@eslint/eslintrc": "^3.3.5",
933
+ "@eslint/js": "9.39.4",
934
934
  "@eslint/plugin-kit": "^0.4.1",
935
935
  "@humanfs/node": "^0.16.6",
936
936
  "@humanwhocodes/module-importer": "^1.0.1",
937
937
  "@humanwhocodes/retry": "^0.4.2",
938
938
  "@types/estree": "^1.0.6",
939
- "ajv": "^6.12.4",
939
+ "ajv": "^6.14.0",
940
940
  "chalk": "^4.0.0",
941
941
  "cross-spawn": "^7.0.6",
942
942
  "debug": "^4.3.2",
@@ -955,7 +955,7 @@
955
955
  "is-glob": "^4.0.0",
956
956
  "json-stable-stringify-without-jsonify": "^1.0.1",
957
957
  "lodash.merge": "^4.6.2",
958
- "minimatch": "^3.1.2",
958
+ "minimatch": "^3.1.5",
959
959
  "natural-compare": "^1.4.0",
960
960
  "optionator": "^0.9.3"
961
961
  },
@@ -1217,7 +1217,7 @@
1217
1217
  }
1218
1218
  },
1219
1219
  "node_modules/flatted": {
1220
- "version": "3.3.3",
1220
+ "version": "3.4.1",
1221
1221
  "license": "ISC"
1222
1222
  },
1223
1223
  "node_modules/follow-redirects": {
@@ -1755,7 +1755,7 @@
1755
1755
  "license": "MIT"
1756
1756
  },
1757
1757
  "node_modules/node-abi": {
1758
- "version": "3.87.0",
1758
+ "version": "3.88.0",
1759
1759
  "license": "MIT",
1760
1760
  "optional": true,
1761
1761
  "dependencies": {
@@ -1951,7 +1951,7 @@
1951
1951
  "license": "MIT"
1952
1952
  },
1953
1953
  "node_modules/pump": {
1954
- "version": "3.0.3",
1954
+ "version": "3.0.4",
1955
1955
  "license": "MIT",
1956
1956
  "optional": true,
1957
1957
  "dependencies": {
@@ -2064,7 +2064,7 @@
2064
2064
  "license": "MIT"
2065
2065
  },
2066
2066
  "node_modules/sax": {
2067
- "version": "1.4.4",
2067
+ "version": "1.5.0",
2068
2068
  "license": "BlueOak-1.0.0",
2069
2069
  "engines": {
2070
2070
  "node": ">=11.0.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds-dk",
3
- "version": "8.9.15",
3
+ "version": "8.9.16",
4
4
  "description": "Command line client and development toolkit for the SAP Cloud Application Programming Model",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "keywords": [