@sap/cds-compiler 3.9.2 → 3.9.6
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 +19 -0
- package/lib/base/message-registry.js +1 -1
- package/lib/edm/annotations/genericTranslation.js +12 -2
- package/lib/edm/csn2edm.js +13 -13
- package/lib/edm/edm.js +4 -1
- package/lib/json/from-csn.js +2 -2
- package/lib/language/genericAntlrParser.js +6 -0
- package/lib/transform/forOdataNew.js +25 -28
- package/lib/transform/localized.js +1 -1
- package/lib/utils/file.js +3 -3
- package/lib/utils/moduleResolve.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,25 @@
|
|
|
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
|
+
|
|
11
|
+
## Version 3.9.6 - 2023-07-27
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- to.edm(x): Revert change introduced with [3.9.0](#version-390---2023-04-20)
|
|
16
|
+
"Correct referential constraint calculation for `[0..1]` backlink associations".
|
|
17
|
+
- for.odata: Process shortcut annotations sequence independent.
|
|
18
|
+
|
|
19
|
+
## Version 3.9.4 - 2023-06-07
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- compiler: `USING` empty files were incorrectly marked as "not found".
|
|
24
|
+
- Localized convenience views for projections (not views) did not have references rewritten.
|
|
25
|
+
This only affects CSN, the SQL result was correct.
|
|
26
|
+
- to.edm(x): Render correct EntitySetPath and annotation target path for actions/functions
|
|
27
|
+
with explicit binding parameter.
|
|
28
|
+
|
|
10
29
|
## Version 3.9.2 - 2023-04-27
|
|
11
30
|
|
|
12
31
|
### Fixed
|
|
@@ -391,7 +391,7 @@ const centralMessageTexts = {
|
|
|
391
391
|
'syntax-deprecated-value': { // Warning
|
|
392
392
|
std: 'Deprecated representation of the value in property $(PROP)',
|
|
393
393
|
replace: 'Replace value in $(PROP) by $(VALUE)',
|
|
394
|
-
'zero-parens': 'Deprecated CSN
|
|
394
|
+
'zero-parens': 'Deprecated CSN v0.1.0 representation of expressions in parentheses',
|
|
395
395
|
'zero-replace': 'Replace CSN v0.1.0 value in $(PROP) by $(VALUE)',
|
|
396
396
|
},
|
|
397
397
|
'syntax-deprecated-type-ref': {
|
|
@@ -416,9 +416,19 @@ function csn2annotationEdm(reqDefs, csnVocabularies, serviceName,
|
|
|
416
416
|
function relParList() {
|
|
417
417
|
// we rely on the order of params in the csn being the correct one
|
|
418
418
|
const params = [];
|
|
419
|
-
if (entityNameIfBound
|
|
420
|
-
|
|
419
|
+
if (entityNameIfBound) {
|
|
420
|
+
// If this is an action and has an explicit binding parameter add it here
|
|
421
|
+
if(cAction.$bindingParam && cAction.kind === 'action') {
|
|
422
|
+
params.push(cAction.$bindingParam.items ? 'Collection(' + entityNameIfBound + ')' : entityNameIfBound);
|
|
423
|
+
}
|
|
424
|
+
// If action/function has no explicit binding parameter add it here
|
|
425
|
+
else if (!cAction.$bindingParam) {
|
|
426
|
+
params.push(cAction['@cds.odata.bindingparameter.collection'] ? 'Collection(' + entityNameIfBound + ')' : entityNameIfBound);
|
|
427
|
+
}
|
|
421
428
|
}
|
|
429
|
+
// In case this is a function the explicit binding parameter is part of
|
|
430
|
+
// the functions params dictionary. Only for functions all parameters must
|
|
431
|
+
// be listed in the annotation target
|
|
422
432
|
if (cAction.kind === 'function') {
|
|
423
433
|
if(cAction.params) {
|
|
424
434
|
cAction.params && Object.values(cAction.params).forEach(p => {
|
package/lib/edm/csn2edm.js
CHANGED
|
@@ -687,14 +687,15 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
687
687
|
The binding parameter remains in the CSN and is rendered as any other
|
|
688
688
|
parameter (including default value/not null/ etc) and acts as annotation carrier.
|
|
689
689
|
*/
|
|
690
|
-
|
|
690
|
+
|
|
691
|
+
let bpName = 'in';
|
|
691
692
|
if(actionCsn.params) {
|
|
692
693
|
const entries = Object.entries(actionCsn.params);
|
|
693
694
|
const firstParam = entries[0][1];
|
|
694
695
|
const type = firstParam?.items?.type || firstParam?.type;
|
|
695
696
|
if(type === special$self) {
|
|
696
|
-
|
|
697
|
-
|
|
697
|
+
bpName = entries[0][0];
|
|
698
|
+
setProp(actionCsn, '$bindingParam', firstParam);
|
|
698
699
|
if(bpType) {
|
|
699
700
|
if(firstParam.items?.type)
|
|
700
701
|
firstParam.items.type = bpType;
|
|
@@ -707,16 +708,15 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
707
708
|
}
|
|
708
709
|
|
|
709
710
|
// bpName is eventually used later for EntitySetPath
|
|
710
|
-
const bpNameAnno = actionCsn['@cds.odata.bindingparameter.name'];
|
|
711
|
-
let bpName = 'in';
|
|
712
|
-
if(bpNameAnno != null) {
|
|
713
|
-
if(typeof bpNameAnno === 'string')
|
|
714
|
-
bpName = bpNameAnno;
|
|
715
|
-
if(typeof bpNameAnno === 'object' && bpNameAnno['='])
|
|
716
|
-
bpName = bpNameAnno['='];
|
|
717
|
-
}
|
|
718
711
|
// No explicit binding parameter, check (user defined) annotation value)
|
|
719
|
-
if(!actionCsn.$
|
|
712
|
+
if(!actionCsn.$bindingParam) {
|
|
713
|
+
const bpNameAnno = actionCsn['@cds.odata.bindingparameter.name'];
|
|
714
|
+
if(bpNameAnno != null) {
|
|
715
|
+
if(typeof bpNameAnno === 'string')
|
|
716
|
+
bpName = bpNameAnno;
|
|
717
|
+
if(typeof bpNameAnno === 'object' && bpNameAnno['='])
|
|
718
|
+
bpName = bpNameAnno['='];
|
|
719
|
+
}
|
|
720
720
|
if(!edmUtils.isODataSimpleIdentifier(bpName))
|
|
721
721
|
message('odata-spec-violation-id', [...loc, '@cds.odata.bindingparameter.name'], { id: bpName });
|
|
722
722
|
if(actionCsn.params && actionCsn.params[bpName]) {
|
|
@@ -726,7 +726,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
726
726
|
if(entityCsn != undefined)
|
|
727
727
|
{
|
|
728
728
|
actionNode.setEdmAttribute('IsBound', true);
|
|
729
|
-
if(!actionCsn.$
|
|
729
|
+
if(!actionCsn.$bindingParam) {
|
|
730
730
|
// Binding Parameter: 'in' at first position in sequence, this is decisive!
|
|
731
731
|
if(actionCsn['@cds.odata.bindingparameter.collection'])
|
|
732
732
|
actionNode.append(new Edm.Parameter(v, { Name: bpName, Type: bpType, Collection:true/*, Nullable: false*/ } ));
|
package/lib/edm/edm.js
CHANGED
|
@@ -1217,13 +1217,16 @@ function getEdm(options, messageFunctions) {
|
|
|
1217
1217
|
// V4 referential constraints!
|
|
1218
1218
|
addReferentialConstraintNodes()
|
|
1219
1219
|
{
|
|
1220
|
+
// flip the constrains if this is a $self partner
|
|
1220
1221
|
let _constraints = this._csn._constraints;
|
|
1222
|
+
let [i,j] = [0,1];
|
|
1221
1223
|
if(this._csn._constraints._partnerCsn) {
|
|
1222
1224
|
_constraints = this._csn._constraints._partnerCsn._constraints;
|
|
1225
|
+
[i,j] = [1,0];
|
|
1223
1226
|
}
|
|
1224
1227
|
_constraints.constraints && Object.values(_constraints.constraints).forEach(c =>
|
|
1225
1228
|
this.append(new ReferentialConstraint(this._v,
|
|
1226
|
-
{ Property: c[
|
|
1229
|
+
{ Property: c[i].join(options.pathDelimiter), ReferencedProperty: c[j].join(options.pathDelimiter) } ) )
|
|
1227
1230
|
);
|
|
1228
1231
|
}
|
|
1229
1232
|
}
|
package/lib/json/from-csn.js
CHANGED
|
@@ -1881,10 +1881,10 @@ function refSplit( name, prop ) {
|
|
|
1881
1881
|
return { path: path.map( id => ({ id, location: location() }) ), location: location() };
|
|
1882
1882
|
}
|
|
1883
1883
|
|
|
1884
|
-
function replaceZeroValue( spec, msgVariant,
|
|
1884
|
+
function replaceZeroValue( spec, msgVariant, newValue ) {
|
|
1885
1885
|
if (!csnVersionZero && !spec.vZeroFor) {
|
|
1886
1886
|
warning( 'syntax-deprecated-value', location(true),
|
|
1887
|
-
{ '#': msgVariant, prop: spec.msgProp,
|
|
1887
|
+
{ '#': msgVariant, prop: spec.msgProp, value: newValue } );
|
|
1888
1888
|
}
|
|
1889
1889
|
}
|
|
1890
1890
|
|
|
@@ -413,6 +413,12 @@ function checkExtensionDict( dict ) {
|
|
|
413
413
|
def[prop] = dup[prop]; // continuation semantics: last wins
|
|
414
414
|
}
|
|
415
415
|
}
|
|
416
|
+
if (dup.$annotations) { // update deprecated $annotations for cds-lsp / annotation modeler
|
|
417
|
+
if (def.$annotations)
|
|
418
|
+
def.$annotations.push( ...dup.$annotations );
|
|
419
|
+
else
|
|
420
|
+
def.$annotations = dup.$annotations;
|
|
421
|
+
}
|
|
416
422
|
}
|
|
417
423
|
def.$duplicates = null;
|
|
418
424
|
}
|
|
@@ -346,44 +346,41 @@ function transform4odataWithCsn(inputModel, options) {
|
|
|
346
346
|
setAnnotation(node, name.replace(setPrefix, setMappings[setPrefix]), node[name]);
|
|
347
347
|
}
|
|
348
348
|
}
|
|
349
|
-
|
|
349
|
+
});
|
|
350
350
|
// Special case: '@readonly' becomes a triplet of capability restrictions for entities,
|
|
351
351
|
// but '@Core.Immutable' for everything else.
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
}
|
|
352
|
+
if (!(node['@readonly'] && node['@insertonly'])) {
|
|
353
|
+
if (node['@readonly']) {
|
|
354
|
+
if (node.kind === 'entity' || node.kind === 'aspect') {
|
|
355
|
+
setAnnotation(node, '@Capabilities.DeleteRestrictions.Deletable', false);
|
|
356
|
+
setAnnotation(node, '@Capabilities.InsertRestrictions.Insertable', false);
|
|
357
|
+
setAnnotation(node, '@Capabilities.UpdateRestrictions.Updatable', false);
|
|
358
|
+
} else {
|
|
359
|
+
setAnnotation(node, '@Core.Computed', true);
|
|
361
360
|
}
|
|
361
|
+
}
|
|
362
362
|
// @insertonly is effective on entities/queries only
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
setAnnotation(node, '@Capabilities.UpdateRestrictions.Updatable', false);
|
|
368
|
-
}
|
|
369
|
-
}
|
|
363
|
+
if (node['@insertonly'] && (node.kind === 'entity' || node.kind === 'aspect')) {
|
|
364
|
+
setAnnotation(node, '@Capabilities.DeleteRestrictions.Deletable', false);
|
|
365
|
+
setAnnotation(node, '@Capabilities.ReadRestrictions.Readable', false);
|
|
366
|
+
setAnnotation(node, '@Capabilities.UpdateRestrictions.Updatable', false);
|
|
370
367
|
}
|
|
368
|
+
}
|
|
371
369
|
// Only on element level: translate @mandatory
|
|
372
|
-
|
|
370
|
+
if (node['@mandatory'] &&
|
|
373
371
|
node.kind === undefined && node['@Common.FieldControl'] === undefined) {
|
|
374
|
-
|
|
375
|
-
|
|
372
|
+
setAnnotation(node, '@Common.FieldControl', { '#': 'Mandatory' });
|
|
373
|
+
}
|
|
376
374
|
|
|
377
|
-
|
|
378
|
-
|
|
375
|
+
if (node['@assert.format'] != null)
|
|
376
|
+
setAnnotation(node, '@Validation.Pattern', node['@assert.format']);
|
|
379
377
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
}
|
|
378
|
+
if (node['@assert.range'] != null) {
|
|
379
|
+
if (Array.isArray(node['@assert.range']) && node['@assert.range'].length === 2) {
|
|
380
|
+
setAnnotation(node, '@Validation.Minimum', node['@assert.range'][0]);
|
|
381
|
+
setAnnotation(node, '@Validation.Maximum', node['@assert.range'][1]);
|
|
385
382
|
}
|
|
386
|
-
}
|
|
383
|
+
}
|
|
387
384
|
}
|
|
388
385
|
|
|
389
386
|
// Apply default type facets to each type definition and every member
|
|
@@ -511,7 +511,7 @@ function _addLocalizationViews(csn, options, useJoins, config) {
|
|
|
511
511
|
// For view convenience views (i.e. transitive views) we need to rewrite `from`
|
|
512
512
|
// references as well as need to handle `mixin` elements.
|
|
513
513
|
// a.k.a 'LOCALIZED-VERTICAL'
|
|
514
|
-
forAllQueries(art.query || art.projection, (query) => {
|
|
514
|
+
forAllQueries(art.query || { SELECT: art.projection }, (query) => {
|
|
515
515
|
query = query.SELECT || query.SET || query;
|
|
516
516
|
if (query.from)
|
|
517
517
|
rewriteFrom(query.from);
|
package/lib/utils/file.js
CHANGED
|
@@ -140,12 +140,12 @@ function cdsFs( fileCache, enableTrace ) {
|
|
|
140
140
|
traceFS( 'ISFILE:cache:', filename, body );
|
|
141
141
|
if (body instanceof Error)
|
|
142
142
|
cb( body ); // no need for process.nextTick( cb, body ) with moduleResolve
|
|
143
|
-
else
|
|
144
|
-
cb( null, !!body );
|
|
143
|
+
else // body could be empty string
|
|
144
|
+
cb( null, !!body || typeof body === 'string');
|
|
145
145
|
}
|
|
146
146
|
else {
|
|
147
147
|
traceFS( 'ISFILE:start:', filename, body );
|
|
148
|
-
// in the future (if we do module resolve
|
|
148
|
+
// in the future (if we do module resolve ourselves with just readFile),
|
|
149
149
|
// we avoid parallel readFile by storing having an array of `cb`s in
|
|
150
150
|
// fileCache[ filename ] before starting fs.readFile().
|
|
151
151
|
try {
|
|
@@ -213,7 +213,7 @@ function resolveCDS( moduleName, options, callback ) {
|
|
|
213
213
|
options.realpath(resolvedBaseDir, (realPathErr, realPath) => {
|
|
214
214
|
// There may be an error in resolving the symlink.
|
|
215
215
|
// We ignore the error and simply use the original path.
|
|
216
|
-
// Otherwise cds-lsp tests would fail because they don't have real
|
|
216
|
+
// Otherwise, cds-lsp tests would fail because they don't have real
|
|
217
217
|
// files in their tests.
|
|
218
218
|
if (!realPathErr)
|
|
219
219
|
resolvedBaseDir = realPath;
|