@sap/cds-compiler 6.3.6 → 6.4.2

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.
Files changed (55) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/LICENSE +32 -0
  3. package/README.md +14 -2
  4. package/bin/cdsse.js +0 -3
  5. package/doc/CHANGELOG_BETA.md +1 -1
  6. package/doc/CHANGELOG_DEPRECATED.md +1 -1
  7. package/lib/base/message-registry.js +7 -0
  8. package/lib/base/messages.js +1 -1
  9. package/lib/base/model.js +2 -0
  10. package/lib/compiler/assert-consistency.js +1 -0
  11. package/lib/compiler/checks.js +37 -26
  12. package/lib/compiler/define.js +1 -1
  13. package/lib/compiler/extend.js +39 -50
  14. package/lib/compiler/finalize-parse-cdl.js +1 -1
  15. package/lib/compiler/lsp-api.js +1 -1
  16. package/lib/compiler/populate.js +2 -2
  17. package/lib/compiler/propagator.js +29 -6
  18. package/lib/compiler/resolve.js +13 -3
  19. package/lib/compiler/shared.js +31 -25
  20. package/lib/compiler/tweak-assocs.js +86 -28
  21. package/lib/compiler/xpr-rewrite.js +70 -38
  22. package/lib/edm/annotations/edmJson.js +206 -37
  23. package/lib/edm/csn2edm.js +13 -0
  24. package/lib/edm/edmUtils.js +2 -2
  25. package/lib/gen/BaseParser.js +106 -72
  26. package/lib/gen/CdlGrammar.checksum +1 -1
  27. package/lib/gen/CdlParser.js +1500 -1509
  28. package/lib/json/to-csn.js +8 -5
  29. package/lib/language/genericAntlrParser.js +0 -0
  30. package/lib/main.js +19 -16
  31. package/lib/model/csnRefs.js +589 -521
  32. package/lib/model/csnUtils.js +8 -5
  33. package/lib/model/enrichCsn.js +1 -0
  34. package/lib/parsers/AstBuildingParser.js +72 -27
  35. package/lib/render/toCdl.js +2 -1
  36. package/lib/render/toHdbcds.js +6 -3
  37. package/lib/render/toSql.js +5 -0
  38. package/lib/transform/db/applyTransformations.js +1 -1
  39. package/lib/transform/db/assertUnique.js +4 -1
  40. package/lib/transform/db/cdsPersistence.js +17 -18
  41. package/lib/transform/db/expansion.js +179 -3
  42. package/lib/transform/db/flattening.js +16 -5
  43. package/lib/transform/db/rewriteCalculatedElements.js +79 -283
  44. package/lib/transform/effective/main.js +8 -1
  45. package/lib/transform/forOdata.js +1 -1
  46. package/lib/transform/forRelationalDB.js +21 -80
  47. package/lib/transform/localized.js +65 -110
  48. package/lib/transform/odata/foreignKeyRefsInXprAnnos.js +89 -63
  49. package/lib/transform/transformUtils.js +23 -21
  50. package/lib/transform/translateAssocsToJoins.js +7 -5
  51. package/lib/transform/tupleExpansion.js +16 -3
  52. package/package.json +1 -1
  53. package/doc/DeprecatedOptions_v2.md +0 -150
  54. package/doc/NameResolution.md +0 -837
  55. package/lib/transform/parseExpr.js +0 -415
package/CHANGELOG.md CHANGED
@@ -8,6 +8,40 @@ Note: `beta` fixes, changes and features are usually not listed in this ChangeLo
8
8
  but in [doc/CHANGELOG_BETA.md](doc/CHANGELOG_BETA.md).
9
9
  The compiler behavior concerning `beta` features can change at any time without notice.
10
10
 
11
+ ## Version 6.4.2 - 2025-10-07
12
+
13
+ ### Fixed
14
+
15
+ - parser:
16
+ + improve error recovery with empty expression as annotation value
17
+ + avoid clutter in message text for syntax errors: use `‹Value›` instead of listing value tokens
18
+ - compiler: fix suppression of warnings when annotating backend-generated things
19
+ like draft entities or localized convenience views
20
+ - to.sql|hdi|hdbcds: Fix handling of structured columns when calculated elements are used
21
+ don't add explicit casts too eagerly
22
+
23
+ ## Version 6.4.0 - 2025-09-26
24
+
25
+ ### Added
26
+
27
+ - compiler: `annotate … with @extension.code: [..., 'additional code']` even works
28
+ if no value for that annotation has been provided with the base definition.
29
+ - to.sql: Calculated elements can now be used next to (but not in) nested projections.
30
+ - to.edm(x): The `@cds.api.ignore` annotation can now be applied to actions, functions, and their parameters.
31
+
32
+ ### Changed
33
+
34
+ - to.sql:
35
+ + generation of localized convenience views now use the ON-condition of the `localized` element
36
+ to create the FROM clause.
37
+
38
+ ### Fixed
39
+
40
+ - parser: minor improvements in error reporting and error recovery
41
+ - to.sql:
42
+ + columns selecting variables did not always get a column alias.
43
+ + when excluding a structure, the SQL backend incorrectly emits `wildcard-excluding-one`.
44
+
11
45
  ## Version 6.3.6 - 2025-09-19
12
46
 
13
47
  ### Fixed
@@ -218,6 +252,20 @@ The compiler behavior concerning `beta` features can change at any time without
218
252
 
219
253
  - to.edm(x): Fixed crash for rare case if annotation expressions were used.
220
254
 
255
+ ## Version 5.9.12 - 2025-09-19
256
+
257
+ ### Fixed
258
+
259
+ - to.sql: Topological ordering of views did not always account for subqueries (fixes regression from v5.9.0)
260
+
261
+ ## Version 5.9.10 - 2025-09-11
262
+
263
+ ### Fixed
264
+
265
+ - parser: Keep parentheses around lists on the right side of an `in` operator.
266
+ - compiler: For calculated elements using associations with filters and cardinality, CSN recompilation could
267
+ fail for `gensrc` CSN, as happens for MTX.
268
+
221
269
  ## Version 5.9.8 - 2025-07-14
222
270
 
223
271
  ### Fixed
package/LICENSE ADDED
@@ -0,0 +1,32 @@
1
+ SAP DEVELOPER LICENSE AGREEMENT
2
+
3
+ Version 3.2 CAP
4
+
5
+ Please scroll down and read the following Developer License Agreement carefully ("Developer Agreement"). By clicking "I Accept" or by attempting to download, or install, or use the SAP software and other materials that accompany this Developer Agreement ("SAP Materials"), You agree that this Developer Agreement forms a legally binding agreement between You ("You" or "Your") and SAP SE, for and on behalf of itself and its subsidiaries and affiliates (as defined in Section 15 of the German Stock Corporation Act) and You agree to be bound by all of the terms and conditions stated in this Developer Agreement. If You are trying to access or download the SAP Materials on behalf of Your employer or as a consultant or agent of a third party (either "Your Company"), You represent and warrant that You have the authority to act on behalf of and bind Your Company to the terms of this Developer Agreement and everywhere in this Developer Agreement that refers to 'You' or 'Your' shall also include Your Company. If You do not agree to these terms, do not click "I Accept", and do not attempt to access or use the SAP Materials.
6
+
7
+ 1. LICENSE: SAP grants You a non-exclusive, non-transferable, non-sublicensable, revocable, limited use license to copy and reproduce the application programming interfaces ("API"), documentation, plug-ins, templates, scripts and sample code, libraries, software development kits ("Tools") to create new applications ("Customer Applications") being developed either for (a) testing and only non-productive use (“Customer Test Applications”) or (b) for productive use deployed and operated exclusively on “SAP Business Technology Platform (BTP)” or any other platform licensed from SAP (“Customer Productive Applications”). Only under this prerequisite SAP will grant You a non-exclusive, non-transferable, revocable, limited use license to copy, reproduce and distribute SAP’s underlying rights in the Customer Productive Application. You agree that any Customer Applications will not: (a) unreasonably impair, degrade or reduce the performance or security of any SAP software applications, services or related technology ("Software"); (b) enable the bypassing or circumventing of SAP's license restrictions and/or provide users with access to the Software to which such users are not licensed; (c) render or provide, without prior written consent from SAP, any information concerning SAP software license terms, Software, or any other information related to SAP products; or (d) permit mass data extraction from an SAP product to a non-SAP product, including use, modification, saving or other processing of such data in the non-SAP product, except and only to the extent that the extraction is solely used for and required for interoperability with an SAP product. In exchange for the right to develop any Customer Applications under this Agreement, You covenant not to assert any Intellectual Property Rights in Customer Applications created by You against any SAP product, service, or future SAP development.
8
+
9
+ 2. INTELLECTUAL PROPERTY: (a) SAP or its licensors retain all ownership and intellectual property rights in the APIs, Tools and Software. You may not: a) remove or modify any marks or proprietary notices of SAP, b) provide or make the APIs, Tools or Software available to any third party, except in cases APIs and Tools have been made part of the overall Customer Productive Application to function, c) assign this Developer Agreement or give or transfer the APIs, Tools or Software or an interest in them to another individual or entity, d) decompile, disassemble or reverse engineer (except to the extent permitted by applicable law) the APIs Tools or Software, e) create derivative works of or based on the APIs, Tools or Software, subject to Customer Productive Applications, being exclusively deployed and operated on “SAP Business Technology Platform (BTP)” or on any other platform licensed from SAP, f) use any SAP name, trademark or logo, or g) use the APIs or Tools to modify existing Software or other SAP product functionality or to access the Software or other SAP products' source code or metadata. (b) Subject to SAP's underlying rights in any part of the APIs, Tools or Software, You retain all ownership and intellectual property rights in Your Customer Applications.
10
+
11
+ 3. ARTIFICIAL INTELLIGENCE TRAINING: You are expressly prohibited from using the Software, Tools or APIs as well as any Customer Applications or any part thereof for the purpose of training (developing) artificial intelligence models or systems (“AI Training”). Prohibition of AI Training includes, but is not limited to, using the Software, Tools, APIs and/or Customer Applications or part thereof in any training data set, algorithm development, model development or refinement (including language learning models) related to artificial intelligence, as well as text and data mining in accordance with §44b UrhG and Art. 4 of EU Directive 2019/790. For the avoidance of doubt, by accepting this Developer Agreement You agree that Your ownership of Customer Applications shall not create nor encompass any right to use Customer Applications for AI Training and, hence, You will not use Customer Applications or any part of it for AI Training.
12
+
13
+ 4. FREE AND OPEN SOURCE COMPONENTS: The SAP Materials may include certain third party free or open source components ("FOSS Components"). You may have additional rights in such FOSS Components that are provided by the third party licensors of those components.
14
+
15
+ 5. THIRD PARTY DEPENDENCIES: The SAP Materials may require certain third party software dependencies ("Dependencies") for the use or operation of such SAP Materials. These dependencies may be identified by SAP in Maven POM files, product documentation or by other means. SAP does not grant You any rights in or to such Dependencies under this Developer Agreement. You are solely responsible for the acquisition, installation and use of Dependencies. SAP DOES NOT MAKE ANY REPRESENTATIONS OR WARRANTIES IN RESPECT OF DEPENDENCIES, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY AND OF FITNESS FOR A PARTICULAR PURPOSE. IN PARTICULAR, SAP DOES NOT WARRANT THAT DEPENDENCIES WILL BE AVAILABLE, ERROR FREE, INTEROPERABLE WITH THE SAP MATERIALS, SUITABLE FOR ANY PARTICULAR PURPOSE OR NON-INFRINGING. YOU ASSUME ALL RISKS ASSOCIATED WITH THE USE OF DEPENDENCIES, INCLUDING WITHOUT LIMITATION RISKS RELATING TO QUALITY, AVAILABILITY, PERFORMANCE, DATA LOSS, UTILITY IN A PRODUCTION ENVIRONMENT, AND NON-INFRINGEMENT. IN NO EVENT WILL SAP BE LIABLE DIRECTLY OR INDIRECTLY IN RESPECT OF ANY USE OF DEPENDENCIES BY YOU.
16
+
17
+ 6. WARRANTY: a) If You are located outside the US or Canada: AS THE API AND TOOLS ARE PROVIDED TO YOU FREE OF CHARGE, SAP DOES NOT GUARANTEE OR WARRANT ANY FEATURES OR QUALITIES OF THE TOOLS OR API OR GIVE ANY UNDERTAKING WITH REGARD TO ANY OTHER QUALITY OR TO YOUR CUSTOMERS. NO SUCH WARRANTY OR UNDERTAKING SHALL BE IMPLIED BY YOU FROM ANY DESCRIPTION IN THE API OR TOOLS OR ANY AVAILABLE DOCUMENTATION OR ANY OTHER COMMUNICATION OR ADVERTISEMENT. IN PARTICULAR, SAP DOES NOT WARRANT THAT THE SOFTWARE WILL BE AVAILABLE UNINTERRUPTED, ERROR FREE, OR PERMANENTLY AVAILABLE. FOR THE TOOLS AND API ALL WARRANTY CLAIMS ARE SUBJECT TO THE LIMITATION OF LIABILITY STIPULATED IN SECTION 4 BELOW. b) If You are located in the US or Canada: THE API AND TOOLS ARE LICENSED TO YOU "AS IS", WITHOUT ANY WARRANTY, ESCROW, TRAINING, MAINTENANCE, OR SERVICE OBLIGATIONS WHATSOEVER ON THE PART OF SAP. SAP MAKES NO EXPRESS OR IMPLIED WARRANTIES OR CONDITIONS OF SALE OF ANY TYPE WHATSOEVER, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY AND OF FITNESS FOR A PARTICULAR PURPOSE. IN PARTICULAR, SAP DOES NOT WARRANT THAT THE SOFTWARE WILL BE AVAILABLE UNINTERRUPTED, ERROR FREE, OR PERMANENTLY AVAILABLE. YOU ASSUME ALL RISKS ASSOCIATED WITH THE USE AND DISTRIBUTION (IF ANY) OF THE API AND TOOLS, INCLUDING WITHOUT LIMITATION RISKS RELATING TO QUALITY, AVAILABILITY, PERFORMANCE, DATA LOSS, AND UTILITY IN A PRODUCTION ENVIRONMENT.
18
+
19
+ 7. LIMITATION OF LIABILITY: a) If You are located outside the US or Canada: IRRESPECTIVE OF THE LEGAL REASONS, SAP SHALL ONLY BE LIABLE FOR DAMAGES UNDER THIS AGREEMENT IF SUCH DAMAGE (I) CAN BE CLAIMED UNDER THE GERMAN PRODUCT LIABILITY ACT OR (II) IS CAUSED BY INTENTIONAL MISCONDUCT OF SAP OR (III) CONSISTS OF PERSONAL INJURY. IN ALL OTHER CASES, NEITHER SAP NOR ITS EMPLOYEES, AGENTS AND SUBCONTRACTORS SHALL BE LIABLE FOR ANY KIND OF DAMAGE OR CLAIMS HEREUNDER.
20
+ b) If You are located in the US or Canada: IN NO EVENT SHALL SAP BE LIABLE TO YOU, YOUR COMPANY, YOUR CUSTOMERS OR TO ANY THIRD PARTY FOR ANY DAMAGES IN AN AMOUNT IN EXCESS OF $100 ARISING IN CONNECTION WITH YOUR USE OF OR INABILITY TO USE THE TOOLS OR API OR IN CONNECTION WITH SAP'S PROVISION OF OR FAILURE TO PROVIDE SERVICES PERTAINING TO THE TOOLS OR API, OR AS A RESULT OF ANY DEFECT IN THE API OR TOOLS OR ANY THIRD PARTY RIGHTS INFRINGEMENT BY THE APIs, TOOLS OR SOFTWARE. THIS DISCLAIMER OF LIABILITY SHALL APPLY REGARDLESS OF THE FORM OF ACTION THAT MAY BE BROUGHT AGAINST SAP, WHETHER IN CONTRACT OR TORT, INCLUDING WITHOUT LIMITATION ANY ACTION FOR NEGLIGENCE. YOUR SOLE REMEDY IN THE EVENT OF BREACH OF THIS DEVELOPER AGREEMENT BY SAP OR FOR ANY OTHER CLAIM RELATED TO THE API OR TOOLS SHALL BE TERMINATION OF THIS AGREEMENT. NOTWITHSTANDING ANYTHING TO THE CONTRARY HEREIN, UNDER NO CIRCUMSTANCES SHALL SAP AND ITS LICENSORS BE LIABLE TO YOU OR ANY OTHER PERSON IN PARTICULAR COMPANY AND YOUR CUSTOMERS OR ENTITY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, OR INDIRECT DAMAGES, LOSS OF GOOD WILL OR BUSINESS PROFITS, WORK STOPPAGE, DATA LOSS, COMPUTER FAILURE OR MALFUNCTION, ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSS, OR EXEMPLARY OR PUNITIVE DAMAGES.
21
+
22
+ 8. INDEMNITY: You will fully indemnify, hold harmless and defend SAP against law suits based on any claim: (a) that any Customer Application created by You infringes or misappropriates any patent, copyright, trademark, trade secrets, or other proprietary rights of a third party, or (b) related to Your alleged violation of the terms of this Developer Agreement
23
+
24
+ 9. EXPORT: The Tools and API are subject to German, EU and US export control regulations. You confirm that: a) You will not use the Tools or API for, and will not allow the Tools or API to be used for, any purposes prohibited by German, EU and US law, including, without limitation, for the development, design, manufacture or production of nuclear, chemical or biological weapons of mass destruction; b) You are not located in and/or will not download or otherwise export or re-export the API or Tools, directly or indirectly, to Cuba, Iran, North Korea, Syria, Crimea/Sevastopol or the so-called Donetsk People’s Republic (DNR) / Luhansk People’s Republic (LNR)nor any other country to which Germany, the European Union and/or the United States has prohibited export; c) You are not listed on any applicable sanctioned party lists (e.g., European Union Sanctions List, U.S. Specially Designated National (SDN) lists, U.S. Denied Persons List, BIS Entity List, United Nations Security Council Sanctions); d) You will not download or otherwise export or re-export the API or Tools , directly or indirectly, to persons on the above-mentioned lists.
25
+
26
+ 10. SUPPORT: Other than what is made available on the SAP Community Website (SCN) by SAP at its sole discretion and by SCN members, SAP does not offer support for the API or Tools which are the subject of this Developer Agreement. In case of Customer Productive Applications developed and made available by You in accordance with this Developer Agreement, You and third parties may request support in line with Your licensing agreement for SAP.
27
+
28
+ 11. TERM AND TERMINATION: You may terminate this Developer Agreement by destroying all copies of the API and Tools on Your Computer(s). SAP may terminate Your license to use the API and Tools immediately if You fail to comply with any of the terms of this Developer Agreement, or, for SAP's convenience by providing you with ten (10) day's written notice of termination (including email). In case of termination or expiration of this Developer Agreement, You must destroy all copies of the API and Tools immediately. In the event Your Company or any of the intellectual property you create using the API, Tools or Software are acquired (by merger, purchase of stock, assets or intellectual property or exclusive license), or You become employed, by a direct competitor of SAP, then this Development Agreement and all licenses granted in this Developer Agreement shall immediately terminate upon the date of such acquisition.
29
+
30
+ 12. LAW/VENUE: a) If You are located outside the US or Canada: This Developer Agreement is governed by and construed in accordance with the laws of the Germany. You and SAP agree to submit to the exclusive jurisdiction of, and venue in, the courts of Karlsruhe in Germany in any dispute arising out of or relating to this Developer Agreement. b) If You are located in the US or Canada: This Developer Agreement shall be governed by and construed under the Commonwealth of Pennsylvania law without reference to its conflicts of law principles. In the event of any conflicts between foreign law, rules, and regulations, and United States of America law, rules, and regulations, United States of America law, rules, and regulations shall prevail and govern. The United Nations Convention on Contracts for the International Sale of Goods shall not apply to this Developer Agreement. The Uniform Computer Information Transactions Act as enacted shall not apply.
31
+
32
+ 13. MISCELLANEOUS: This Developer Agreement is the complete agreement for the API and Tools licensed (including reference to information/documentation contained in a URL). This Developer Agreement supersedes all prior or contemporaneous agreements or representations with regards to the subject matter of this Developer Agreement. If any term of this Developer Agreement is found to be invalid or unenforceable, the surviving provisions shall remain effective. SAP's failure to enforce any right or provisions stipulated in this Developer Agreement will not constitute a waiver of such provision, or any other provision of this Developer Agreement.
package/README.md CHANGED
@@ -6,6 +6,8 @@
6
6
 
7
7
  [Installation and Usage](#installation-and-usage)
8
8
  [Documentation](#documentation)
9
+ [How to Obtain Support](#how-to-obtain-support)
10
+ [History and License](#history-and-license)
9
11
 
10
12
  ## Installation and Usage
11
13
 
@@ -23,15 +25,25 @@ Or maintain your package.json dependencies as follows:
23
25
  }
24
26
  ```
25
27
 
28
+ If your project already has a dependency to `@sap/cds`, nothing has to be done.
29
+
26
30
 
27
31
  ## Documentation
28
32
 
29
33
  Please refer to the [official CDS documentation](https://cap.cloud.sap/docs/cds/).
30
34
 
35
+
31
36
  ## How to Obtain Support
32
37
 
33
38
  In case you find a bug, please report an [incident](https://cap.cloud.sap/docs/resources/#reporting-incidents) on SAP Support Portal.
34
39
 
35
- ## License
36
40
 
37
- This package is provided under the terms of the [SAP Developer License Agreement](https://cap.cloud.sap/resources/license/developer-license-3_2_CAP.txt).
41
+ ## History and License
42
+
43
+ The cds-compiler uses [Semantic Versioning](./doc/Versioning.md) for its version numbers.
44
+
45
+ Our [changelog](./CHANGELOG.md) lists recent changes.
46
+ <!-- If you upgrade from a previous version, TODO: incompatible changes -->
47
+
48
+ This package is provided under the terms of the [SAP Developer License Agreement, Version 3.2 CAP](LICENSE).
49
+ <!-- https://cap.cloud.sap/resources/license/developer-license-3_2_CAP.txt -->
package/bin/cdsse.js CHANGED
@@ -174,9 +174,6 @@ function tokensAt( buf, _offset, col, symbol ) {
174
174
  else if (/^[A-Z_]+$/.test( n )) {
175
175
  console.log( n.toLowerCase(), 'keyword' );
176
176
  }
177
- else if (n === 'Boolean') {
178
- console.log( 'true keyword\nfalse keyword' );
179
- }
180
177
  else if (n !== 'Identifier') {
181
178
  console.log( n, 'unknown' );
182
179
  }
@@ -1,4 +1,4 @@
1
- # ChangeLog of Beta Features for cdx compiler and backends
1
+ # ChangeLog of beta Features for CDS compiler and backends
2
2
 
3
3
  <!-- markdownlint-disable MD024 -->
4
4
  <!-- markdownlint-disable MD004 -->
@@ -1,4 +1,4 @@
1
- # ChangeLog of deprecated Features for cdx compiler and backends
1
+ # ChangeLog of deprecated features for CDS compiler and backends
2
2
 
3
3
  <!-- markdownlint-disable MD024 -->
4
4
  <!-- (no-duplicate-heading)-->
@@ -669,6 +669,7 @@ const centralMessageTexts = {
669
669
  tableAlias: 'A filter can only be provided when navigating along associations, but found table alias',
670
670
  from: 'A filter can only be provided for the source entity or associations',
671
671
  'model-only': 'A filter can\'t be provided for a to-many association without ON-condition',
672
+ 'last-empty-filter': 'Unexpected empty filter in last path step',
672
673
  },
673
674
 
674
675
  // multi-line strings: --------------------------------------------------------
@@ -1011,6 +1012,11 @@ const centralMessageTexts = {
1011
1012
  // TODO: Better message?
1012
1013
  include: '$(ART) can\'t have localized elements (through include)',
1013
1014
  },
1015
+ 'def-expected-localized': {
1016
+ std: 'Skipped creation of convenience view for $(NAME)', // unused
1017
+ 'non-assoc': 'Skipped creation of convenience view for $(NAME) because element $(ALIAS) is not an association',
1018
+ missing: 'Skipped creation of convenience view for $(NAME) because element $(ALIAS) is missing',
1019
+ },
1014
1020
  'def-unexpected-localized-struct': '$(KEYWORD) is not fully supported for structures',
1015
1021
  'def-unexpected-localized-anno': 'Annotations can\'t have localized elements',
1016
1022
  'def-unexpected-virtual': 'Unexpected $(KEYWORD): an element can\'t be virtual and an association/composition',
@@ -1428,6 +1434,7 @@ const centralMessageTexts = {
1428
1434
  },
1429
1435
  'odata-anno-xpr': {
1430
1436
  std: 'unused',
1437
+ invalid: 'Invalid expression around $(OP) in $(ANNO); can\'t be rendered as a dynamic expression',
1431
1438
  notadynexpr: '$(OP) is not a renderable dynamic expression in $(ANNO)',
1432
1439
  use: 'Function $(OP) is not a renderable dynamic expression in $(ANNO), use $(CODE) instead',
1433
1440
  canonfuncalias: 'Expected function name $(CODE) to be of the form $(META).$(OTHERMETA) for $(OP) in $(ANNO)',
@@ -1724,7 +1724,7 @@ function constructSemanticLocationFromCsnPath( model, options, csnPath ) {
1724
1724
  else if (step === 'targetAspect') {
1725
1725
  // skip
1726
1726
  }
1727
- else if (step === 'xpr' || step === 'default' || step === 'ref' || step === 'as' || step === 'value') {
1727
+ else if (step === 'xpr' || step === 'list' || step === 'default' || step === 'ref' || step === 'as' || step === 'value') {
1728
1728
  break; // don't go into xprs, refs, aliases, values, etc.
1729
1729
  }
1730
1730
  else if (step === 'returns') {
package/lib/base/model.js CHANGED
@@ -29,6 +29,8 @@ const availableBetaFlags = {
29
29
  rewriteAnnotationExpressionsViaType: true,
30
30
  sqlServiceDummies: true,
31
31
  projectionViews: true,
32
+ draftAdminDataHiddenFilter: true,
33
+ $calcForDraft: true,
32
34
  // disabled by --beta-mode
33
35
  nestedServices: false,
34
36
  };
@@ -480,6 +480,7 @@ function assertConsistency( model, stage ) {
480
480
  },
481
481
  query: { requires: [ 'query', 'location' ], optional: [ 'stored', '$parens' ] },
482
482
  },
483
+ $calc: { kind: true, test: TODO }, // TODO: rename to `value`?
483
484
  literal: { // TODO: check value against literal
484
485
  test: isString,
485
486
  enum: [
@@ -258,37 +258,46 @@ function check( model ) {
258
258
  : xpr._artifact;
259
259
 
260
260
  const typeArt = isSqlCast ? xpr : user;
261
- if (!elem || !isSqlCast && typeArt.type?.$inferred)
262
- return; // e.g. $inferred:'generated'
261
+ if (!elem || typeArt.$inferred || !isSqlCast && typeArt.type?.$inferred)
262
+ return; // e.g. $inferred: 'generated'
263
263
 
264
- const { type } = typeArt;
265
- if (type) { // has explicit type
266
- if (type._artifact?._effectiveType?.name.id === 'cds.Map') {
267
- error( 'type-invalid-cast', [ type.location, user ], { '#': 'std', type: 'cds.Map' } );
268
- }
269
- else if (type._artifact?.elements) {
270
- error( 'type-invalid-cast', [ type.location, user ], { '#': 'to-structure' } );
271
- }
272
- else if (elem.elements) { // TODO: calc elements
273
- error( 'type-invalid-cast', [ type.location, user ], { '#': 'from-structure' } );
274
- }
275
- else if (elem.target && !type._artifact?.target) {
276
- error( 'type-invalid-cast', [ type.location, user ], { '#': 'from-assoc' } );
277
- }
278
- else if (!elem.target && // referenced element is not association
264
+ const typeItems = typeArt.items ?? typeArt;
265
+
266
+ // explicit type, elements, or items -> has type cast
267
+ const hasCast = typeItems.type ||
268
+ (typeItems.elements && !typeArt.expand && !typeArt.$expand && !elem.$expand);
269
+
270
+ if (!hasCast)
271
+ return;
272
+
273
+ const { type } = typeItems;
274
+ const loc = [ (type || typeItems).location, user ];
275
+
276
+ if (type?._artifact?._effectiveType?.name.id === 'cds.Map') {
277
+ error( 'type-invalid-cast', loc, { '#': 'std', type: 'cds.Map' } );
278
+ }
279
+ else if (elem.elements && !typeArt.$expand) { // TODO: calc elements
280
+ error( 'type-invalid-cast', loc, { '#': 'from-structure' } );
281
+ }
282
+ else if (elem.target && (typeArt.items || !type?._artifact?.target)) {
283
+ error( 'type-invalid-cast', loc, { '#': 'from-assoc' } );
284
+ }
285
+ else if ((typeArt.elements && !typeArt.$expand) || type?._artifact?.elements) {
286
+ error( 'type-invalid-cast', loc, { '#': 'to-structure' } );
287
+ }
288
+ else if (!elem.target && // referenced element is not association
279
289
  !user.type?.$inferred && // $inferred types already reported in resolve.js.
280
290
  (
281
291
  // assoc used in SQL cast
282
- type._artifact?.target && isSqlCast ||
292
+ type?._artifact?.target && isSqlCast ||
283
293
  // there is a target and the type is a direct `cds.Association`;
284
294
  // other types handled by resolver already.
285
- typeArt.target && type._artifact?.category === 'relation'
295
+ typeItems.target && type?._artifact?.category === 'relation'
286
296
  )
287
- ) {
288
- // - redirection-check in resolve.js already checks this for CDL-casts
289
- // - `"cast": { "target": "…", "type": "cds.Association", … }` via CSN input.
290
- error('type-invalid-cast', [ type.location, user ], { '#': 'assoc' });
291
- }
297
+ ) {
298
+ // - redirection-check in resolve.js already checks this for CDL-casts
299
+ // - `"cast": { "target": "…", "type": "cds.Association", … }` via CSN input.
300
+ error('type-invalid-cast', loc, { '#': 'assoc' });
292
301
  }
293
302
  }
294
303
 
@@ -827,8 +836,10 @@ function check( model ) {
827
836
  error( 'ref-unexpected-structured', [ sourceLoc, elem ],
828
837
  { '#': 'struct-expr', elemref: xpr } );
829
838
  }
830
- else if (xpr._artifact.target !== undefined && (!lastStep.where || isStored)) {
831
- // Allow using an association _with filter_, but only for on-read calculated elements.
839
+ else if (xpr._artifact.target !== undefined &&
840
+ (!lastStep.where || lastStep.where.args?.length === 0 || isStored)) {
841
+ // Allow using an association _with non-empty filter_, but only for on-read
842
+ // calculated elements.
832
843
  // TODO: Also allow bare unmanaged association references and remove beta.
833
844
  const variant = (isStored && lastStep.where && 'assoc-stored') ||
834
845
  (isComposition( model, xpr._artifact ) && 'expr-comp') ||
@@ -395,7 +395,7 @@ function define( model ) {
395
395
  function addExtension( ext, block ) {
396
396
  setLink( ext, '_block', block );
397
397
  initExprAnnoBlock( ext, block );
398
- const absolute = ext.name && resolveUncheckedPath( ext.name, '_extensions', ext );
398
+ const absolute = ext.name && resolveUncheckedPath( ext.name, '_uncheckedExtension', ext );
399
399
  if (!absolute) // broken path
400
400
  return;
401
401
  delete ext.name.path[0]._artifact; // might point to wrong JS object in phase 1
@@ -261,8 +261,7 @@ function extend( model ) {
261
261
  const { name } = ext;
262
262
  const { path } = name;
263
263
  if (name._artifact === undefined) {
264
- const refCtx = (name.id.startsWith( 'localized.' )) ? '_extensions' : ext.kind;
265
- resolvePath( name, refCtx, ext ); // for LSP
264
+ resolvePath( name, ext.kind, ext ); // induce error & for LSP
266
265
  }
267
266
  else if (model.options.lspMode && path?.[0]._artifact === undefined) {
268
267
  // we don't use resolvePath(…,'extend'), as that would add a dependency
@@ -487,13 +486,17 @@ function extend( model ) {
487
486
  return anno;
488
487
  const hasBase = previousAnno?.literal === 'array';
489
488
  if (!previousAnno) {
490
- const location = firstEllipsis.location || anno.name.location;
491
- message( 'anno-unexpected-ellipsis', [ location, art ], { code: '...' } );
489
+ const { location } = anno.name;
490
+ if (annoName !== '@extension.code') {
491
+ // Remark: we could allow that for all annotations which are not propagated
492
+ message( 'anno-unexpected-ellipsis', [ firstEllipsis.location || location, art ],
493
+ { code: '...' } );
494
+ }
492
495
  previousAnno = {
493
496
  kind: '$annotation',
494
497
  val: [],
495
498
  literal: 'array',
496
- name: { id: annoName.slice( 1 ) },
499
+ name: anno.name,
497
500
  location,
498
501
  };
499
502
  }
@@ -899,11 +902,9 @@ function extend( model ) {
899
902
  function createSuperAnnotate( annotate ) {
900
903
  const extensions = annotate._extensions;
901
904
  if (extensions && !annotate._main) {
902
- const { id } = annotate.name;
903
- const isLocalized = id.startsWith( 'localized.' ); // TODO: && anno
904
- const art = model.definitions[id];
905
+ const art = model.definitions[annotate.name.id];
905
906
  for (const ext of extensions)
906
- checkRemainingMainExtensions( art, ext, isLocalized );
907
+ checkRemainingMainExtensions( art, ext );
907
908
  if (art?.builtin && art.kind !== 'namespace') { // TODO: do not set `builtin` on cds, cds.hana
908
909
  setLink( annotate, '_extensions', art._extensions ); // for messages and member extensions
909
910
  // direct annotations on builtins or on the builtins for propagation, and
@@ -923,24 +924,14 @@ function extend( model ) {
923
924
  forEachMember( annotate, createSuperAnnotate );
924
925
  }
925
926
 
926
- function checkRemainingMainExtensions( art, ext, localized ) {
927
- const isExtend = ext.kind === 'extend';
928
- if (localized) {
929
- if (isExtend) {
930
- // In v5, reject any `extend` on localized.
931
- error( 'ref-undefined-art', [ ext.location || ext.name.location, ext ],
932
- { '#': 'localized', keyword: 'annotate' } );
933
- }
934
- return;
935
- }
936
-
927
+ function checkRemainingMainExtensions( art, ext ) {
937
928
  if (!resolvePath( ext.name, ext.kind, ext )) // error for extend, info for annotate
938
929
  return;
939
930
 
940
931
  if (art?.builtin) {
941
932
  info( 'anno-builtin', [ ext.name.location, ext ], {} ); // TODO: better location?
942
933
  }
943
- else if (isExtend && art?.kind === 'namespace') {
934
+ else if (ext.kind === 'extend' && art?.kind === 'namespace') {
944
935
  // `annotate` on namespaces already handled before
945
936
  const hasAnnotations = Object.keys(ext).find(a => a.charAt(0) === '@');
946
937
  const firstAnno = ext[hasAnnotations];
@@ -992,7 +983,7 @@ function extend( model ) {
992
983
  * includes, do so without includes.
993
984
  */
994
985
  function applyExtensions() {
995
- let noIncludes = false;
986
+ let cyclicIncludeNames = false;
996
987
  let extNames = Object.keys( extensionsDict ).sort();
997
988
 
998
989
  while (extNames.length) {
@@ -1000,35 +991,37 @@ function extend( model ) {
1000
991
  for (const name of extNames) {
1001
992
  const art = model.definitions[name];
1002
993
  if (art && art.kind !== 'namespace' &&
1003
- extendArtifact( extensionsDict[name], art, noIncludes ))
994
+ extendArtifact( extensionsDict[name], art, cyclicIncludeNames ))
1004
995
  delete extensionsDict[name];
1005
996
  }
1006
997
  extNames = Object.keys( extensionsDict ); // no sort() required anymore
1007
998
  if (extNames.length >= length)
1008
- noIncludes = Object.keys( extensionsDict ); // = no includes
999
+ cyclicIncludeNames = Object.keys( extensionsDict ); // = no includes
1009
1000
  }
1010
1001
  }
1011
1002
 
1012
1003
  /**
1013
- * Extend artifact `art` by `extensions`. `noIncludes` can have values:
1014
- * - false: includes are applied, extend and annotate is performed
1015
- * - true: includes are not applied, extend and annotate is performed
1016
- * - 'gen': no includes and no extensions allowed, annotate is performed
1004
+ * Extend artifact `art` by `extensions`. `cyclicIncludeNames` can have values:
1005
+ * - falsy: try to apply include, then perform extend and annotate
1006
+ * - an array of include names with cyclic dependencies: includes are not applied,
1007
+ * extend and annotate is performed
1008
+ * remark: we could have applied includes without cycle
1009
+ *
1010
+ * Returns true if extend and annotate are performed.
1017
1011
  *
1018
1012
  * @param {XSN.Extension[]} extensions
1019
1013
  * @param {XSN.Definition} art
1020
- * @param {boolean|'gen'} [noIncludes=false]
1014
+ * @param {String[]|false} [cyclicIncludeNames=false]
1021
1015
  */
1022
- function extendArtifact( extensions, art, noIncludes = false ) {
1023
- if (!noIncludes && !(canApplyIncludes( art, art ) &&
1016
+ function extendArtifact( extensions, art, cyclicIncludeNames = null ) {
1017
+ if (!cyclicIncludeNames && !(canApplyIncludes( art, art ) &&
1024
1018
  extensions.every( ext => canApplyIncludes( ext, art ) )))
1025
1019
  return false;
1026
- if (Array.isArray( noIncludes )) {
1027
- canApplyIncludes( art, art, noIncludes );
1028
- extensions.forEach( ext => canApplyIncludes( ext, art, noIncludes ) );
1020
+ if (cyclicIncludeNames) {
1021
+ canApplyIncludes( art, art, cyclicIncludeNames );
1022
+ extensions.forEach( ext => canApplyIncludes( ext, art, cyclicIncludeNames ) );
1029
1023
  }
1030
- else if (!noIncludes &&
1031
- !(canApplyIncludes( art, art ) &&
1024
+ else if (!(canApplyIncludes( art, art ) &&
1032
1025
  extensions.every( ext => canApplyIncludes( ext, art ) ))) {
1033
1026
  // console.log( 'FALSE:',art.name, extensions.map( e => e.name ) )
1034
1027
  return false;
@@ -1038,17 +1031,18 @@ function extend( model ) {
1038
1031
  art.$entity = ++model.$entity;
1039
1032
  }
1040
1033
  if (art.includes) {
1041
- if (!noIncludes) {
1034
+ if (!cyclicIncludeNames) {
1042
1035
  applyIncludes( art, art );
1043
1036
  }
1044
1037
  else {
1038
+ // resolve artifacts to induce errors: either ref-invalid-include or ref-cyclic
1045
1039
  for (const ref of art.includes)
1046
1040
  resolvePath( ref, 'include', art );
1047
1041
  }
1048
1042
  }
1049
1043
  // checkExtensionsKind( extensions, art );
1050
- extendMembers( extensions, art, noIncludes === 'gen' );
1051
- if (!noIncludes && art.includes) {
1044
+ extendMembers( extensions, art );
1045
+ if (!cyclicIncludeNames && art.includes) {
1052
1046
  // early propagation of specific annotation assignments
1053
1047
  propagateEarly( art, '@cds.autoexpose' );
1054
1048
  propagateEarly( art, '@fiori.draft.enabled' );
@@ -1057,7 +1051,7 @@ function extend( model ) {
1057
1051
  return true;
1058
1052
  }
1059
1053
 
1060
- function extendMembers( extensions, art, noExtend ) {
1054
+ function extendMembers( extensions, art ) {
1061
1055
  // TODO: do the whole extension stuff lazily if the elements are requested
1062
1056
  const elemExtensions = [];
1063
1057
  if (art._main) // extensions already sorted for main artifacts
@@ -1069,11 +1063,6 @@ function extend( model ) {
1069
1063
  // 'Info', 'EXT').toString())
1070
1064
  if (ext.name._artifact === undefined) { // not already applied
1071
1065
  setArtifactLink( ext.name, art );
1072
- if (noExtend && ext.kind === 'extend') {
1073
- error( 'extend-for-generated', [ ext.name.location, ext ], { art, keyword: 'extend' },
1074
- 'You can\'t use $(KEYWORD) on the generated $(ART)' );
1075
- continue;
1076
- }
1077
1066
  if (ext.includes) {
1078
1067
  // TODO: currently, re-compiling from gensrc does not give the exact
1079
1068
  // element sequence - we need something like
@@ -1207,17 +1196,17 @@ function extend( model ) {
1207
1196
  *
1208
1197
  * @param {XSN.Definition} art
1209
1198
  * @param {XSN.Artifact} target
1210
- * @param {string[]} [justResolveCyclic]
1199
+ * @param {string[]} [cyclicIncludeNames]
1211
1200
  * @returns {boolean}
1212
1201
  */
1213
- function canApplyIncludes( art, target, justResolveCyclic ) {
1202
+ function canApplyIncludes( art, target, cyclicIncludeNames ) {
1214
1203
  if (!art.includes)
1215
1204
  return true;
1216
1205
  for (const ref of art.includes) {
1217
1206
  const name = resolveUncheckedPath( ref, 'include', art );
1218
- // console.log('CAI:',justResolveCyclic, name, ref.path, Object.keys(extensionsDict))
1219
- if (justResolveCyclic) {
1220
- if (!justResolveCyclic.includes( name ))
1207
+ // console.log('CAI:',cyclicIncludeNames, name, ref.path, Object.keys(extensionsDict))
1208
+ if (cyclicIncludeNames) {
1209
+ if (!cyclicIncludeNames.includes( name ))
1221
1210
  continue;
1222
1211
  delete ref._artifact;
1223
1212
  }
@@ -40,7 +40,7 @@ function finalizeParseCdl( model ) {
40
40
  // TODO: why not just use the extensions as they are from the first source?
41
41
  for (const name in late) {
42
42
  for (const ext of late[name]._extensions) {
43
- ext.name.id = resolveUncheckedPath( ext.name, '_extensions', ext );
43
+ ext.name.id = resolveUncheckedPath( ext.name, '_uncheckedExtension', ext );
44
44
  // Initialize members and define annotations in sub-elements.
45
45
  initMembers( ext, ext, ext._block, true );
46
46
  extensions.push( ext );
@@ -7,7 +7,7 @@
7
7
  //
8
8
  // This files includes an iterator over "semantic tokens" in an XSN model.
9
9
  // "Semantic tokens" are identifiers, but also the "return" parameter.
10
- // See `internalDoc/lsp/IdentifierCrawling.md` for details.
10
+ // See <../../internalDoc/lsp/IdentifierCrawling.md> for details.
11
11
 
12
12
  const { CompilerAssertion } = require('../base/error');
13
13
  const $inferred = Symbol.for( 'cds.$inferred' );
@@ -882,7 +882,7 @@ function populate( model ) {
882
882
  for (const name in env) {
883
883
  const navElem = env[name];
884
884
  // TODO: remove all access to masked (use 'grep')
885
- if (excludingDict[name] || navElem.masked && navElem.masked.val)
885
+ if (excludingDict[name] || navElem.masked?.val)
886
886
  continue;
887
887
  const sibling = siblingElements[name];
888
888
  if (sibling) { // is explicitly provided (without duplicate)
@@ -917,7 +917,7 @@ function populate( model ) {
917
917
  const elemLocation = !query._main.$inferred && location;
918
918
  const origin = envParent ? navElem : navElem._origin;
919
919
  const elem = linkToOrigin( origin, name, query, null, elemLocation );
920
- if (origin.$calcDepElement) // TODO: this will be changed in the next PR
920
+ if (origin.$calcDepElement)
921
921
  dependsOn( elem, origin.$calcDepElement, location );
922
922
 
923
923
  // TODO: check assocToMany { * }