@sap/cds-compiler 6.9.0 → 6.9.1
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 +13 -0
- package/lib/base/message-registry.js +0 -1
- package/lib/compiler/extend.js +18 -8
- package/lib/compiler/shared.js +0 -2
- package/lib/edm/csn2edm.js +4 -2
- package/lib/edm/edm.js +6 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -13,6 +13,19 @@ we might not list every change in its behavior here.
|
|
|
13
13
|
Productive code should never require a `beta` flag to be set, and
|
|
14
14
|
might use a deprecated flag only for a limited period of time.
|
|
15
15
|
|
|
16
|
+
## Version 6.9.1 - 2026-05-05
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
- **compiler:**
|
|
21
|
+
+ make an element added via `extend` correctly shadow an element from an include
|
|
22
|
+
+ do not issue a warning for a correct use of `$projection`
|
|
23
|
+
- **odata:**
|
|
24
|
+
+ do not generate wrong ReferentialConstraints for unmanaged Composition without a partner
|
|
25
|
+
+ render Partner attribute on forward association correctly
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
16
29
|
## Version 6.9.0 - 2026-04-21
|
|
17
30
|
|
|
18
31
|
### Features
|
|
@@ -1138,7 +1138,6 @@ const centralMessageTexts = {
|
|
|
1138
1138
|
'old-not-target': 'Expected element $(NAME) not to be an association, because it overrides the included element from $(ART)',
|
|
1139
1139
|
},
|
|
1140
1140
|
|
|
1141
|
-
'ref-expecting-$self': 'Use $(NEWCODE) instead of $(CODE) here or remove $(CODE) altogether if possible; the compiler has rewritten it to $(NEWCODE) in CSN',
|
|
1142
1141
|
'ref-expecting-assoc': {
|
|
1143
1142
|
std: 'Expecting path $(ELEMREF) following “EXISTS” predicate to end with association/composition',
|
|
1144
1143
|
'with-type': 'Expecting path $(ELEMREF) following “EXISTS” predicate to end with association/composition, found $(TYPE)',
|
package/lib/compiler/extend.js
CHANGED
|
@@ -1173,7 +1173,8 @@ function extend( model ) {
|
|
|
1173
1173
|
}
|
|
1174
1174
|
if (art._extensions?.$add)
|
|
1175
1175
|
extendArtifact( art._extensions.$add, art );
|
|
1176
|
-
|
|
1176
|
+
checkRedefinitionThroughIncludes( art, 'elements' );
|
|
1177
|
+
checkRedefinitionThroughIncludes( art, 'actions' );
|
|
1177
1178
|
}
|
|
1178
1179
|
|
|
1179
1180
|
/**
|
|
@@ -1497,6 +1498,9 @@ function extend( model ) {
|
|
|
1497
1498
|
}
|
|
1498
1499
|
|
|
1499
1500
|
const existing = parent[prop]?.[name];
|
|
1501
|
+
const shadowsIncludeMember = construct !== parent &&
|
|
1502
|
+
elem.$inferred !== 'include' &&
|
|
1503
|
+
existing?.$inferred === 'include';
|
|
1500
1504
|
const add = construct !== parent && (!existing || elem.$inferred !== 'include');
|
|
1501
1505
|
if (!add && existing?.$inferred === 'include' && elem.$inferred === 'include') {
|
|
1502
1506
|
includeCollisions.push( {
|
|
@@ -1507,9 +1511,17 @@ function extend( model ) {
|
|
|
1507
1511
|
const { $duplicates } = elem;
|
|
1508
1512
|
if ($duplicates === true && add)
|
|
1509
1513
|
elem.$duplicates = null;
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1514
|
+
if (add && elem.$inferred === 'include' && Array.isArray( $duplicates ))
|
|
1515
|
+
elem.$duplicates = null;
|
|
1516
|
+
if (shadowsIncludeMember) {
|
|
1517
|
+
parent[prop][name] = elem;
|
|
1518
|
+
setMemberParent( elem, name, parent );
|
|
1519
|
+
}
|
|
1520
|
+
else {
|
|
1521
|
+
setMemberParent( elem, name, parent, add && prop );
|
|
1522
|
+
if (!$duplicates) // not already reported
|
|
1523
|
+
checkRedefinition( elem );
|
|
1524
|
+
}
|
|
1513
1525
|
initMembers( elem, elem, elem._block );
|
|
1514
1526
|
if (elem.kind === 'action' || elem.kind === 'function')
|
|
1515
1527
|
initBoundSelfParam( elem.params, elem._main );
|
|
@@ -1740,9 +1752,6 @@ function extend( model ) {
|
|
|
1740
1752
|
} );
|
|
1741
1753
|
}
|
|
1742
1754
|
}
|
|
1743
|
-
|
|
1744
|
-
checkRedefinitionThroughIncludes( parent, prop );
|
|
1745
|
-
|
|
1746
1755
|
if (!hasNewElement && members) {
|
|
1747
1756
|
ext[prop] = members;
|
|
1748
1757
|
}
|
|
@@ -1788,7 +1797,8 @@ function extend( model ) {
|
|
|
1788
1797
|
|
|
1789
1798
|
/**
|
|
1790
1799
|
* Report duplicates in parent[prop] that happen due to multiple includes having the
|
|
1791
|
-
* same member.
|
|
1800
|
+
* same member. Run after includes and extends so shadowing members have already
|
|
1801
|
+
* replaced any include-derived survivors in-place.
|
|
1792
1802
|
*/
|
|
1793
1803
|
function checkRedefinitionThroughIncludes( parent, prop ) {
|
|
1794
1804
|
if (!parent[prop])
|
package/lib/compiler/shared.js
CHANGED
|
@@ -984,8 +984,6 @@ function fns( model ) {
|
|
|
984
984
|
art.kind === '$self' && path[0].id === '$projection') {
|
|
985
985
|
// Rewrite $projection to $self
|
|
986
986
|
path[0].id = '$self';
|
|
987
|
-
warning( 'ref-expecting-$self', [ path[0].location, user ],
|
|
988
|
-
{ code: '$projection', newcode: '$self' });
|
|
989
987
|
}
|
|
990
988
|
return art.name?.$inferred !== '$internal'; // not a compiler-generated internal alias
|
|
991
989
|
}
|
package/lib/edm/csn2edm.js
CHANGED
|
@@ -472,8 +472,10 @@ function csn2edmAll( _csn, _options, serviceNames, messageFunctions ) {
|
|
|
472
472
|
|
|
473
473
|
navigationProperties.forEach((np) => {
|
|
474
474
|
if (options.isV4()) {
|
|
475
|
-
// V4: No referential constraints for Containment Relationships
|
|
476
|
-
|
|
475
|
+
// V4: No referential constraints for Containment Relationships or
|
|
476
|
+
// unmanaged Compositions without a partner
|
|
477
|
+
const isUnmanagedCompositionWithoutPartner = np._csn.type === 'cds.Composition' && np._csn.on && !np._csn._constraints._partnerCsn;
|
|
478
|
+
if ((!np.isContainment() || (options.renderForeignKeys)) && !np.isToMany() && !isUnmanagedCompositionWithoutPartner)
|
|
477
479
|
np.addReferentialConstraintNodes();
|
|
478
480
|
}
|
|
479
481
|
else {
|
package/lib/edm/edm.js
CHANGED
|
@@ -1053,11 +1053,14 @@ function getEdm( options ) {
|
|
|
1053
1053
|
delete this._edmAttributes.Nullable;
|
|
1054
1054
|
}
|
|
1055
1055
|
// we have exactly one selfReference or the default partner
|
|
1056
|
-
|
|
1057
|
-
|
|
1056
|
+
// $noPartner can be set when a second projection creates an ambiguous backlink, but if exactly
|
|
1057
|
+
// one self-reference targets the same entity as this association, that unambiguous partner still applies.
|
|
1058
|
+
const selfRefsToTarget = csn._selfReferences.filter(ref => ref.$abspath[0] === csn._target?.name);
|
|
1059
|
+
const isPartner = selfRefsToTarget.length === 1 && selfRefsToTarget[0]._constraints?._partnerCsn === csn;
|
|
1060
|
+
if (!csn.$noPartner || isPartner) {
|
|
1058
1061
|
const partner = csn._selfReferences.length === 1
|
|
1059
1062
|
? csn._selfReferences[0]
|
|
1060
|
-
: csn._constraints._partnerCsn;
|
|
1063
|
+
: selfRefsToTarget[0] || csn._constraints._partnerCsn;
|
|
1061
1064
|
if (partner && partner['@odata.navigable'] !== false && this._csn._edmParentCsn.kind !== 'type') {
|
|
1062
1065
|
// $abspath[0] is main entity
|
|
1063
1066
|
this._edmAttributes.Partner = partner.$abspath.slice(1).join('/');
|