@sap/cds-compiler 5.9.8 → 5.9.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.
package/CHANGELOG.md CHANGED
@@ -7,13 +7,30 @@
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 5.9.12 - 2025-09-19
11
+
12
+ ### Fixed
13
+
14
+ - to.sql: Topological ordering of views did not always account for subqueries (fixes regression from v5.9.0)
15
+
16
+ ## Version 5.9.10 - 2025-09-11
17
+
18
+ ### Fixed
19
+
20
+ - parser: Keep parentheses around lists on the right side of an `in` operator.
21
+ - compiler: For calculated elements using associations with filters and cardinality, CSN recompilation could
22
+ fail for `gensrc` CSN, as happens for MTX.
10
23
 
11
24
  ## Version 5.9.8 - 2025-07-14
12
25
 
26
+ ### Fixed
27
+
13
28
  - compiler: Calculated elements can now have a localized type
14
29
 
15
30
  ## Version 5.9.6 - 2025-06-18
16
31
 
32
+ ### Fixed
33
+
17
34
  - to.sql: Fix error when calculated element refers to a localized element.
18
35
  - to.edm(x):
19
36
  + Fix errors for service entities containing multiple path steps (e.g. `Service.Prefix.MyEntity`).
@@ -21,6 +38,8 @@ The compiler behavior concerning `beta` features can change at any time without
21
38
 
22
39
  ## Version 5.9.4 - 2025-05-22
23
40
 
41
+ ### Fixed
42
+
24
43
  - to.edm(x): Parameters are marked optional unless explicitly marked as `not null`.
25
44
  Annotation `Core.OptionalParameter` will be added to optional parameters.
26
45
 
@@ -601,7 +601,7 @@ function assertConsistency( model, stage ) {
601
601
  cardinality: {
602
602
  kind: true,
603
603
  requires: [ 'location' ],
604
- optional: [ 'sourceMin', 'sourceMax', 'targetMin', 'targetMax' ],
604
+ optional: [ 'sourceMin', 'sourceMax', 'targetMin', 'targetMax', '$inferred' ],
605
605
  },
606
606
  sourceMin: { test: isNumberVal },
607
607
  sourceMax: { test: isNumberVal, also: [ '*' ] },
@@ -505,6 +505,7 @@ function tweakAssocs( model ) {
505
505
  if (lastStep.cardinality) {
506
506
  elem.cardinality ??= { ...assoc.cardinality };
507
507
  elem.cardinality.location = location;
508
+ elem.cardinality.$inferred = 'rewrite';
508
509
  for (const card of [ 'sourceMin', 'targetMin', 'targetMax' ]) {
509
510
  if (lastStep.cardinality[card])
510
511
  elem.cardinality[card] = copyExpr( lastStep.cardinality[card], location );
@@ -1 +1 @@
1
- 226c8854e08665b3eaae3ae1a1276db7
1
+ 6012ce87566963a5c785b624177ac737
@@ -3950,7 +3950,7 @@ case 683:switch(this.l()){
3950
3950
  case',':this.continueExpressionslist($,684);continue
3951
3951
  default:this.s=684;continue
3952
3952
  }
3953
- case 684:if(this.m(0,')')){ this.surroundByParens( $.expr ); }continue
3953
+ case 684:if(this.m(0,')')){ if ($.expr.op?.val !== 'list' || $.expr.location) this.surroundByParens( $.expr ); else this.attachLocation( $.expr ); }continue
3954
3954
  default:return this.exit_()
3955
3955
  }
3956
3956
  }
@@ -3958,7 +3958,7 @@ continueExpressionslist($,$next){
3958
3958
  let e;let _
3959
3959
  this.rule_(686,$next)
3960
3960
  for(;;)switch(this.s){
3961
- case 686:if(this.m(687,',')){ $.expr = { op: this.valueWithLocation( 'list' ), args: [ $.expr ], location: { ... $.expr.$parens?.at( -1 ) ?? $.expr.location } }; }continue
3961
+ case 686:if(this.m(687,',')){ $.expr = { op: this.valueWithLocation( 'list' ), args: [ $.expr ], location: null }; }continue
3962
3962
  case 687:switch(this.lk()){
3963
3963
  case'Id':case'#':case'(':case'+':case'-':case':':case'?':case'not':case'case':case'cast':case'null':case'true':case'false':case'Number':case'String':case'exists':case'QuotedLiteral':this.s=688;continue
3964
3964
  default:this.ei();continue
@@ -3971,10 +3971,7 @@ case 689:switch(this.l()){
3971
3971
  case',':this.c(688);continue
3972
3972
  default:this.gr([')']);continue
3973
3973
  }
3974
- case 0:{ this.attachLocation( $.expr ); }
3975
- default:
3976
- this.attachLocation( $.expr )
3977
- return this.exit_()
3974
+ default:return this.exit_()
3978
3975
  }
3979
3976
  }
3980
3977
  newAndValuePath($,$next){
@@ -629,7 +629,7 @@ function combinedLocation( start, end ) {
629
629
  function secureParens( expr ) {
630
630
  const op = expr?.op?.val;
631
631
  const $parens = expr?.$parens;
632
- if (!$parens || expr.query || op && op !== 'call' && op !== 'cast')
632
+ if (!$parens || expr.query || op && op !== 'call' && op !== 'cast' && op !== 'list')
633
633
  return expr;
634
634
  // ensure that references, literals and functions keep their surrounding parentheses
635
635
  // (is for expressions the case anyway)
@@ -602,8 +602,7 @@ function forAllQueries( query, queryCallback, path ) {
602
602
  const expr = query[prop];
603
603
  if (expr && typeof expr === 'object') {
604
604
  if (Array.isArray(expr)) {
605
- for (let i = 0; i < expr.length; i++)
606
- forAllQueries(expr[i], queryCallback, [ ...path, prop, i ]);
605
+ traverseStructurizedExpression(expr, [ ...path, prop ]);
607
606
  }
608
607
  else {
609
608
  for (const argName of Object.keys( expr ))
@@ -611,6 +610,23 @@ function forAllQueries( query, queryCallback, path ) {
611
610
  }
612
611
  }
613
612
  }
613
+
614
+ /**
615
+ * Traverse the possibly structured xpr. A structured expression may contain arrays inside arrays
616
+ * to show precedence of operators.
617
+ *
618
+ * @param {any} xpr
619
+ * @param {CSN.Path} csnPath
620
+ */
621
+ function traverseStructurizedExpression( xpr, csnPath ) {
622
+ if (Array.isArray(xpr)) {
623
+ for (let i = 0; i < xpr.length; i++)
624
+ traverseStructurizedExpression(xpr[i], [ ...csnPath, i ]);
625
+ }
626
+ else {
627
+ forAllQueries(xpr, queryCallback, csnPath);
628
+ }
629
+ }
614
630
  }
615
631
 
616
632
  /**
@@ -1129,7 +1129,7 @@ class AstBuildingParser extends BaseParser {
1129
1129
  secureParens( expr ) {
1130
1130
  const op = expr?.op?.val;
1131
1131
  const $parens = expr?.$parens;
1132
- if (!$parens || expr.query || op && op !== 'call' && op !== 'cast')
1132
+ if (!$parens || expr.query || op && op !== 'call' && op !== 'cast' && op !== 'list')
1133
1133
  return expr;
1134
1134
  // ensure that references, literals and functions keep their surrounding parentheses
1135
1135
  // (is for expressions the case anyway)
@@ -1650,18 +1650,16 @@ expressionOrQueryParens returns[ default expr ]
1650
1650
  | queryExpression[ ...$ ]
1651
1651
  )
1652
1652
  ')'
1653
- { this.surroundByParens( $expr ); }
1653
+ { if ($expr.op?.val !== 'list' || $expr.location) this.surroundByParens( $expr ); else this.attachLocation( $expr ); }
1654
1654
  ;
1655
1655
 
1656
1656
  continueExpressionslist[ expr ]
1657
- @finally{ this.attachLocation( $expr ); }
1658
1657
  :
1659
- ',' { $expr = { op: this.valueWithLocation( 'list' ), args: [ $expr ], location: { ... $expr.$parens?.at( -1 ) ?? $expr.location } }; }
1658
+ ',' { $expr = { op: this.valueWithLocation( 'list' ), args: [ $expr ], location: null }; }
1660
1659
  (
1661
1660
  e=expression { $expr.args.push( $e ); }
1662
1661
  ( ',' | <exitLoop> )
1663
1662
  )+
1664
- { this.attachLocation( $expr ); }
1665
1663
  ;
1666
1664
 
1667
1665
  newAndValuePath returns[ default expr ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds-compiler",
3
- "version": "5.9.8",
3
+ "version": "5.9.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)",