@sap/cds-compiler 4.9.6 → 4.9.10
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 +15 -0
- package/lib/base/message-registry.js +6 -0
- package/lib/compiler/define.js +3 -1
- package/lib/compiler/shared.js +41 -7
- package/lib/edm/edm.js +8 -0
- package/lib/edm/edmPreprocessor.js +7 -3
- package/lib/json/to-csn.js +3 -1
- package/lib/main.d.ts +9 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,21 @@
|
|
|
7
7
|
Note: `beta` fixes, changes and features are usually not listed in this ChangeLog but [here](doc/CHANGELOG_BETA.md).
|
|
8
8
|
The compiler behavior concerning `beta` features can change at any time without notice.
|
|
9
9
|
|
|
10
|
+
## Version 4.9.10 - 2025-04-29
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Added option `allowMixinInProjectionExtension` which allows referring to mixins in `extend projection`.
|
|
15
|
+
This was forbidden in cds-compiler v4, but re-introduced in v5.5. Users wanting to migrate from cds-compiler
|
|
16
|
+
v3 to v4 can use this option for easier migration.
|
|
17
|
+
|
|
18
|
+
## Version 4.9.8 - 2024-07-29
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- compiler: Fix extensions with bound actions using an explicit binding parameter in `parseCdl` CSN.
|
|
23
|
+
- to.edm(x): No `Nullable` attribute for `$ReturnType` of `Collection(<entity type>)` [OData V4 CSDL, section 12.8 Return Type](https://docs.oasis-open.org/odata/odata-csdl-xml/v4.01/odata-csdl-xml-v4.01.html#sec_ReturnType)
|
|
24
|
+
|
|
10
25
|
## Version 4.9.6 - 2024-07-15
|
|
11
26
|
|
|
12
27
|
### Fixed
|
|
@@ -975,6 +975,12 @@ const centralMessageTexts = {
|
|
|
975
975
|
none: 'Ambiguous $(ID) requires an explicit table alias, but there are none: add table aliases to all sub-queries to disambiguate $(ID)',
|
|
976
976
|
},
|
|
977
977
|
|
|
978
|
+
'ref-special-in-extend': {
|
|
979
|
+
std: 'In an added column, $(ID) refers to the element of the projection source $(ART), not the table alias or mixin',
|
|
980
|
+
alias: 'In an added column, $(ID) refers to the element of the projection source $(ART), not the table alias',
|
|
981
|
+
mixin: 'In an added column, $(ID) refers to the element of the projection source $(ART), not the mixin',
|
|
982
|
+
},
|
|
983
|
+
|
|
978
984
|
'type-managed-composition': {
|
|
979
985
|
std: 'Managed compositions can\'t be used in types', // yet
|
|
980
986
|
sub: 'Managed compositions can\'t be used in sub elements',
|
package/lib/compiler/define.js
CHANGED
|
@@ -1203,7 +1203,9 @@ function define( model ) {
|
|
|
1203
1203
|
const type = first?.type || first?.items?.type; // this sequence = no derived type
|
|
1204
1204
|
const path = type?.path;
|
|
1205
1205
|
if (path?.length === 1 && path[0]?.id === '$self') { // TODO: no where: ?
|
|
1206
|
-
const
|
|
1206
|
+
const $self = main.$tableAliases?.$self ||
|
|
1207
|
+
main.kind === 'extend' && { name: { id: '$self' } };
|
|
1208
|
+
// remark: an extend has no "table alias" `$self` (relevant for parse-cdl)
|
|
1207
1209
|
setLink( type, '_artifact', $self );
|
|
1208
1210
|
setLink( path[0], '_artifact', $self );
|
|
1209
1211
|
}
|
package/lib/compiler/shared.js
CHANGED
|
@@ -175,7 +175,9 @@ function fns( model ) {
|
|
|
175
175
|
having: 'where',
|
|
176
176
|
groupBy: 'where',
|
|
177
177
|
column: {
|
|
178
|
-
lexical:
|
|
178
|
+
lexical: (!options.allowMixinInProjectionExtension
|
|
179
|
+
? tableAliasesIfNotExtendAndSelf // default for v4
|
|
180
|
+
: tableAliasesAndSelf), // default for v5 or via option
|
|
179
181
|
dollar: true,
|
|
180
182
|
dynamic: combinedSourcesOrParentElements,
|
|
181
183
|
notFound: undefinedSourceElement,
|
|
@@ -629,7 +631,6 @@ function fns( model ) {
|
|
|
629
631
|
// simple 'ref-undefined-art'/'ref-undefined-def' - TODO: which we
|
|
630
632
|
// could "change" to this message at the end of compile():
|
|
631
633
|
error( 'ref-unexpected-autoexposed', [ item.location, user ], { art },
|
|
632
|
-
// eslint-disable-next-line max-len
|
|
633
634
|
'An auto-exposed entity can\'t be referred to - expose entity $(ART) explicitly' );
|
|
634
635
|
return null; // continuation semantics: like “not found”
|
|
635
636
|
}
|
|
@@ -693,16 +694,49 @@ function fns( model ) {
|
|
|
693
694
|
return setArtifactLink( head, def ); // we do not want to see the using
|
|
694
695
|
}
|
|
695
696
|
case 'mixin': {
|
|
697
|
+
if (options.allowMixinInProjectionExtension) { // for v5 compatibility
|
|
698
|
+
// use a source element having that name if in `extend … with columns`:
|
|
699
|
+
const elem = (user._user || user).$extended &&
|
|
700
|
+
art._parent._combined[head.id];
|
|
701
|
+
if (elem) {
|
|
702
|
+
path.$prefix = elem._parent.name.id; // prepend alias name
|
|
703
|
+
info( 'ref-special-in-extend', [ head.location, user ],
|
|
704
|
+
{ '#': 'mixin', id: head.id, art: elem._origin._main } );
|
|
705
|
+
setLink( head, '_navigation', elem );
|
|
706
|
+
return setArtifactLink( head, elem._origin );
|
|
707
|
+
}
|
|
708
|
+
}
|
|
696
709
|
return setLink( head, '_navigation', art );
|
|
697
710
|
}
|
|
698
711
|
case '$navElement': {
|
|
699
|
-
if (
|
|
700
|
-
|
|
712
|
+
if (!options.allowMixinInProjectionExtension) { // for v5 compatibility
|
|
713
|
+
if (head.id === (user._user || user).$extended)
|
|
714
|
+
path.$prefix = head.id;
|
|
715
|
+
}
|
|
701
716
|
setLink( head, '_navigation', art );
|
|
702
717
|
return setArtifactLink( head, art._origin );
|
|
703
718
|
}
|
|
704
|
-
case '$self': // TODO: remove $projection from CC
|
|
705
719
|
case '$tableAlias': {
|
|
720
|
+
if (options.allowMixinInProjectionExtension) { // for v5 compatibility
|
|
721
|
+
// use a source element having that name if in `extend … with columns`:
|
|
722
|
+
const { $extended } = user._user || user;
|
|
723
|
+
const elem = $extended && art.elements[head.id];
|
|
724
|
+
if (elem) {
|
|
725
|
+
path.$prefix = art.name.id; // prepend alias name
|
|
726
|
+
info('ref-special-in-extend', [ head.location, user ],
|
|
727
|
+
{ '#': 'alias', id: head.id, art: elem._origin._main });
|
|
728
|
+
setLink( head, '_navigation', elem );
|
|
729
|
+
return setArtifactLink( head, elem._origin );
|
|
730
|
+
}
|
|
731
|
+
else if ($extended) {
|
|
732
|
+
warning( 'ref-deprecated-in-extend', [ head.location, user ], { id: head.id },
|
|
733
|
+
// eslint-disable-next-line max-len
|
|
734
|
+
'In an added column, do not use the table alias $(ID) to refer to source elements' );
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
/* FALLTHROUGH */
|
|
739
|
+
case '$self': { // TODO: remove $projection from CC
|
|
706
740
|
setLink( head, '_navigation', art );
|
|
707
741
|
setArtifactLink( head, art._origin ); // query source or leading query in FROM
|
|
708
742
|
if (!art._origin)
|
|
@@ -1113,7 +1147,7 @@ function fns( model ) {
|
|
|
1113
1147
|
// TODO: if it becomes non-configurable, we can omit this warning
|
|
1114
1148
|
let id = pathName( path );
|
|
1115
1149
|
let head = path[0]._artifact || { _parent: art };
|
|
1116
|
-
|
|
1150
|
+
|
|
1117
1151
|
while ((head = head?._parent) && head.kind === 'builtin')
|
|
1118
1152
|
id = `${ head.name.id }.${ id }`;
|
|
1119
1153
|
const msgId = (art.$uncheckedElements) ? 'ref-unknown-var' : 'ref-undefined-var';
|
|
@@ -1635,7 +1669,7 @@ function fns( model ) {
|
|
|
1635
1669
|
const txt = index >= path.length
|
|
1636
1670
|
? 'complete'
|
|
1637
1671
|
: (isAssocToPrimaryKeys( assoc ) ? 'keys' : 'std');
|
|
1638
|
-
|
|
1672
|
+
|
|
1639
1673
|
error( 'ref-invalid-navigation', [ last.location, user ], {
|
|
1640
1674
|
'#': msgPrefix + txt, art: assoc, name: last.id, alias: '$self',
|
|
1641
1675
|
}, {
|
package/lib/edm/edm.js
CHANGED
|
@@ -882,12 +882,20 @@ function getEdm( options, messageFunctions ) {
|
|
|
882
882
|
class ReturnType extends PropertyBase {
|
|
883
883
|
constructor(version, csn) {
|
|
884
884
|
super(version, {}, csn);
|
|
885
|
+
// CSDL 12.8: If the return type is a collection of entity types,
|
|
886
|
+
// the Nullable attribute has no meaning and MUST NOT be specified.
|
|
887
|
+
if (csn.$NoNullableProperty)
|
|
888
|
+
delete this._edmAttributes.Nullable;
|
|
885
889
|
}
|
|
886
890
|
|
|
887
891
|
// we need Name but NO $kind, can't use standard to JSON()
|
|
888
892
|
toJSON() {
|
|
889
893
|
const json = Object.create(null);
|
|
890
894
|
this.toJSONattributes(json);
|
|
895
|
+
// CSDL 12.8: If the return type is a collection of entity types,
|
|
896
|
+
// the Nullable attribute has no meaning and MUST NOT be specified.
|
|
897
|
+
if (this._csn.$NoNullableProperty)
|
|
898
|
+
delete json.$Nullable;
|
|
891
899
|
return json;
|
|
892
900
|
}
|
|
893
901
|
}
|
|
@@ -1892,7 +1892,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
|
|
|
1892
1892
|
mapCdsToEdmProp(def);
|
|
1893
1893
|
annotateAllowedValues(def, defLocation);
|
|
1894
1894
|
if (def.returns) {
|
|
1895
|
-
markCollection(def.returns);
|
|
1895
|
+
markCollection(def.returns, true);
|
|
1896
1896
|
mapCdsToEdmProp(def.returns);
|
|
1897
1897
|
annotateAllowedValues(def.returns, [ ...defLocation, 'returns' ]);
|
|
1898
1898
|
}
|
|
@@ -1905,16 +1905,20 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
|
|
|
1905
1905
|
rewriteAnnotationExpressions(member);
|
|
1906
1906
|
if (member.returns) {
|
|
1907
1907
|
edmUtils.assignAnnotation(member.returns, '@Core.Description', member.returns.doc);
|
|
1908
|
-
markCollection(member.returns);
|
|
1908
|
+
markCollection(member.returns, true);
|
|
1909
1909
|
mapCdsToEdmProp(member.returns);
|
|
1910
1910
|
annotateAllowedValues(member.returns, [ ...location, 'returns' ]);
|
|
1911
1911
|
rewriteAnnotationExpressions(member.returns);
|
|
1912
1912
|
}
|
|
1913
1913
|
}, defLocation);
|
|
1914
1914
|
// mark members that need to be rendered as collections
|
|
1915
|
-
function markCollection( obj ) {
|
|
1915
|
+
function markCollection( obj, isReturns ) {
|
|
1916
1916
|
const items = obj.items || csn.definitions[obj.type] && csn.definitions[obj.type].items;
|
|
1917
1917
|
if (items) {
|
|
1918
|
+
edmUtils.assignProp(obj, '$NoNullableProperty',
|
|
1919
|
+
isReturns && items.type &&
|
|
1920
|
+
!isBuiltinType(items.type) &&
|
|
1921
|
+
csn.definitions[items.type]?.kind === 'entity');
|
|
1918
1922
|
edmUtils.assignProp(obj, '_NotNullCollection', items.notNull !== undefined ? items.notNull : true);
|
|
1919
1923
|
edmUtils.assignProp(obj, '$isCollection', true);
|
|
1920
1924
|
}
|
package/lib/json/to-csn.js
CHANGED
|
@@ -1192,7 +1192,9 @@ function exprInternal( node, xprParens ) {
|
|
|
1192
1192
|
}
|
|
1193
1193
|
if (node.path) {
|
|
1194
1194
|
const ref = node.path.map( pathItem );
|
|
1195
|
-
|
|
1195
|
+
// auto-corrected ORDER BY refs without table alias, or EXTEND … WITH COLUMN
|
|
1196
|
+
// refs to source element shadowed by alias name:
|
|
1197
|
+
if (node.path.$prefix)
|
|
1196
1198
|
ref.unshift( node.path.$prefix );
|
|
1197
1199
|
// we would need to consider node.global here if we introduce that
|
|
1198
1200
|
return extra( { ref }, node );
|
package/lib/main.d.ts
CHANGED
|
@@ -131,6 +131,15 @@ declare namespace compiler {
|
|
|
131
131
|
* @since v2.8.0
|
|
132
132
|
*/
|
|
133
133
|
addTextsLanguageAssoc?: boolean
|
|
134
|
+
/**
|
|
135
|
+
* Allow referring to mixins in `extend projection` clauses.
|
|
136
|
+
* This was allowed in cds-compiler v3, forbidden in v4, and allowed in v5.5 by default again.
|
|
137
|
+
*
|
|
138
|
+
* @default false
|
|
139
|
+
* @since v4.9.10
|
|
140
|
+
* @until v4.9.10
|
|
141
|
+
*/
|
|
142
|
+
allowMixinInProjectionExtension?: boolean
|
|
134
143
|
/**
|
|
135
144
|
* An array of directory names that are used for CDS module lookups.
|
|
136
145
|
* Lookup directory `node_modules/` is appended if not set explicitly.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sap/cds-compiler",
|
|
3
|
-
"version": "4.9.
|
|
3
|
+
"version": "4.9.10",
|
|
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)",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"gentest3": "cross-env MAKEREFS=${MAKEREFS:-'true'} mocha --reporter-option maxDiffSize=0 test3/testRefFiles.js",
|
|
29
29
|
"coverage": "cross-env nyc mocha --reporter-option maxDiffSize=0 test/ test3/testRefFiles.js && nyc report --reporter=lcov",
|
|
30
30
|
"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",
|
|
31
|
-
"lint": "eslint bin/ benchmark/ lib/ test/ test3/ scripts/
|
|
31
|
+
"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",
|
|
32
32
|
"tslint": "tsc --pretty -p .",
|
|
33
33
|
"updateVocs": "node scripts/odataAnnotations/generateDictMain.js && npm run generateAllRefs",
|
|
34
34
|
"updateTocs": "node scripts/update-toc.js",
|