@sap/cds-compiler 4.7.6 → 4.8.0

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 (93) hide show
  1. package/CHANGELOG.md +37 -2
  2. package/bin/cdsc.js +15 -1
  3. package/bin/cdshi.js +13 -3
  4. package/doc/CHANGELOG_BETA.md +5 -1
  5. package/lib/api/main.js +61 -23
  6. package/lib/api/options.js +40 -0
  7. package/lib/base/builtins.js +89 -0
  8. package/lib/base/keywords.js +5 -1
  9. package/lib/base/location.js +91 -14
  10. package/lib/base/message-registry.js +50 -33
  11. package/lib/base/messages.js +71 -16
  12. package/lib/base/model.js +0 -2
  13. package/lib/checks/actionsFunctions.js +1 -1
  14. package/lib/checks/elements.js +2 -1
  15. package/lib/checks/enricher.js +2 -2
  16. package/lib/checks/queryNoDbArtifacts.js +2 -1
  17. package/lib/checks/utils.js +1 -1
  18. package/lib/checks/validator.js +6 -22
  19. package/lib/compiler/assert-consistency.js +3 -5
  20. package/lib/compiler/builtins.js +0 -74
  21. package/lib/compiler/checks.js +61 -11
  22. package/lib/compiler/define.js +3 -3
  23. package/lib/compiler/extend.js +2 -2
  24. package/lib/compiler/index.js +9 -9
  25. package/lib/compiler/populate.js +13 -5
  26. package/lib/compiler/propagator.js +3 -0
  27. package/lib/compiler/resolve.js +6 -20
  28. package/lib/compiler/shared.js +1 -1
  29. package/lib/compiler/tweak-assocs.js +2 -2
  30. package/lib/compiler/utils.js +3 -3
  31. package/lib/compiler/{classes.js → xsn-model.js} +0 -16
  32. package/lib/edm/annotations/edmJson.js +7 -5
  33. package/lib/edm/annotations/genericTranslation.js +113 -55
  34. package/lib/edm/csn2edm.js +25 -9
  35. package/lib/edm/edm.js +3 -3
  36. package/lib/edm/edmInboundChecks.js +24 -5
  37. package/lib/edm/edmPreprocessor.js +46 -20
  38. package/lib/edm/edmUtils.js +3 -16
  39. package/lib/gen/Dictionary.json +9 -0
  40. package/lib/gen/language.checksum +1 -1
  41. package/lib/gen/language.interp +1 -1
  42. package/lib/gen/languageParser.js +1941 -1850
  43. package/lib/json/csnVersion.js +7 -4
  44. package/lib/json/from-csn.js +8 -7
  45. package/lib/json/to-csn.js +12 -7
  46. package/lib/language/antlrParser.js +1 -1
  47. package/lib/language/genericAntlrParser.js +9 -10
  48. package/lib/language/multiLineStringParser.js +2 -2
  49. package/lib/language/textUtils.js +1 -1
  50. package/lib/main.d.ts +23 -0
  51. package/lib/main.js +8 -1
  52. package/lib/model/cloneCsn.js +15 -6
  53. package/lib/model/csnRefs.js +141 -35
  54. package/lib/model/csnUtils.js +1 -4
  55. package/lib/model/enrichCsn.js +1 -1
  56. package/lib/modelCompare/compare.js +106 -92
  57. package/lib/optionProcessor.js +23 -1
  58. package/lib/render/toCdl.js +3 -2
  59. package/lib/render/toHdbcds.js +4 -48
  60. package/lib/render/toSql.js +6 -3
  61. package/lib/transform/addTenantFields.js +58 -35
  62. package/lib/transform/db/applyTransformations.js +1 -1
  63. package/lib/transform/db/expansion.js +3 -0
  64. package/lib/transform/db/flattening.js +71 -46
  65. package/lib/transform/db/views.js +1 -4
  66. package/lib/transform/effective/main.js +6 -3
  67. package/lib/transform/effective/misc.js +18 -8
  68. package/lib/transform/effective/types.js +4 -3
  69. package/lib/transform/forOdata.js +8 -7
  70. package/lib/transform/forRelationalDB.js +103 -112
  71. package/lib/transform/odata/flattening.js +82 -44
  72. package/lib/transform/odata/toFinalBaseType.js +9 -25
  73. package/lib/transform/odata/typesExposure.js +28 -15
  74. package/lib/transform/parseExpr.js +0 -3
  75. package/lib/transform/transformUtils.js +12 -8
  76. package/lib/transform/translateAssocsToJoins.js +2 -2
  77. package/lib/transform/universalCsn/coreComputed.js +2 -1
  78. package/lib/transform/universalCsn/universalCsnEnricher.js +1 -1
  79. package/package.json +2 -2
  80. package/share/messages/README.md +4 -0
  81. package/share/messages/anno-duplicate-unrelated-layer.md +1 -1
  82. package/share/messages/check-proper-type-of.md +1 -1
  83. package/share/messages/def-duplicate-autoexposed.md +1 -1
  84. package/share/messages/extend-repeated-intralayer.md +3 -16
  85. package/share/messages/extend-unrelated-layer.md +1 -1
  86. package/share/messages/message-explanations.json +1 -0
  87. package/share/messages/redirected-to-ambiguous.md +1 -1
  88. package/share/messages/redirected-to-complex.md +1 -1
  89. package/share/messages/redirected-to-unrelated.md +1 -1
  90. package/share/messages/rewrite-not-supported.md +1 -1
  91. package/share/messages/syntax-expecting-unsigned-int.md +2 -2
  92. package/share/messages/type-missing-enum-value.md +59 -0
  93. package/share/messages/wildcard-excluding-one.md +1 -1
package/CHANGELOG.md CHANGED
@@ -8,6 +8,40 @@ Note: `beta` fixes, changes and features are usually not listed in this ChangeLo
8
8
  The compiler behavior concerning `beta` features can change at any time without notice.
9
9
 
10
10
 
11
+ ## Version 4.8.0 - 2024-03-21
12
+
13
+ ### Added
14
+
15
+ - compiler: Type `cds.Vector` was added. It is mapped to `REAL_VECTOR` on SAP HANA.
16
+ - Support associations to/from entities with parameters for SAP HANA SQL (hdi/direct).
17
+ - to.sql/to.hdi:
18
+ + SAP HANA keywords `ABSOLUTE`, `REAL_VECTOR`, and `ST_ASESRIJSON` are now included for smart quoting.
19
+ +PostgreSQL keyword `SYSTEM_USER` is now included for smart quoting.
20
+ - API: Added `to.sql.postgres.keywords` and `to.sql.h2.keywords`.
21
+ They contain keywords for the respective SQL dialect.
22
+
23
+ ### Changed
24
+
25
+ - compiler: Overriding an included element must not change the type to an association
26
+ if it wasn't an association before and vice versa.
27
+ - Update OData vocabularies: 'Authorization', 'Common', 'UI'.
28
+
29
+ ### Fixed
30
+
31
+ - compiler: `cast()`s to structured types and associations are now rejected. They could lead to crashes before.
32
+ - to.edm(x):
33
+ + Reject action/function return types that are declared `many of many`.
34
+ + Render user defined annotation type `cds.Integer` as `Edm.Int`.
35
+ - to.sql|hdi|hdbcds:
36
+ + Correctly handle `.list` during flattening.
37
+ + Improve handling of `.items`.
38
+ - to.sql|hdi.migration:
39
+ + Turn types and aspects into dummies to reduce CSN size.
40
+ + Correctly detect a removed `.default` and forcefully set the default to `null`.
41
+
42
+ ### Removed
43
+
44
+
11
45
  ## Version 4.7.6 - 2024-02-29
12
46
 
13
47
  ### Fixed
@@ -27,14 +61,15 @@ The compiler behavior concerning `beta` features can change at any time without
27
61
 
28
62
  ### Fixed
29
63
 
30
- - Restored compatibility with `@sap/cds-dk` for Java runtime
64
+ - Restored compatibility with `@sap/cds-dk` for Java runtime.
65
+
31
66
 
32
67
 
33
68
  ## Version 4.7.0 - 2024-02-23
34
69
 
35
70
  ### Added
36
71
 
37
- - compiler: Virtual elements can now be referenced in expressions in annotation
72
+ - compiler: Virtual elements can now be referenced in expressions in annotation.
38
73
 
39
74
  ### Changed
40
75
 
package/bin/cdsc.js CHANGED
@@ -217,7 +217,7 @@ function cdsc_main() {
217
217
  * @param {object} args
218
218
  */
219
219
  function validateDirectBackendOption( command, options, args ) {
220
- if (![ 'toCdl', 'toOdata', 'toHana', 'toCsn', 'toSql' ].includes(command)) {
220
+ if (![ 'toCdl', 'toOdata', 'toHana', 'toCsn', 'toSql', 'forJava' ].includes(command)) {
221
221
  displayUsage(`Option '--direct-backend' can't be used with command '${command}'`,
222
222
  optionProcessor.helpText, 2);
223
223
  }
@@ -272,6 +272,7 @@ function executeCommandLine( command, options, args ) {
272
272
  toCsn,
273
273
  toHana,
274
274
  toOdata,
275
+ forJava,
275
276
  toRename,
276
277
  manageConstraints,
277
278
  toSql,
@@ -317,6 +318,11 @@ function executeCommandLine( command, options, args ) {
317
318
  }
318
319
 
319
320
  function toEffectiveCsn( model ) {
321
+ const features = [ 'resolveSimpleTypes', 'resolveProjections' ];
322
+ for (const feature of features) {
323
+ if (options[feature]) // map to boolean equivalent
324
+ options[feature] = options[feature] === 'true';
325
+ }
320
326
  const csn = options.directBackend ? model : compactModel(model, options);
321
327
  displayNamedCsn(main.for.effective(csn, options), 'effective');
322
328
 
@@ -336,6 +342,14 @@ function executeCommandLine( command, options, args ) {
336
342
  return model;
337
343
  }
338
344
 
345
+ // Execute the command line command 'forJava' and display the results.
346
+ // Return the original model
347
+ function forJava( model ) {
348
+ const csn = options.directBackend ? model : compactModel(model, options);
349
+ displayNamedCsn( main.for.java( csn, options ), 'java');
350
+ return model;
351
+ }
352
+
339
353
  // Execute the command line option '--to-hana' and display the results.
340
354
  // Return the original model (for chaining)
341
355
  function toHana( model ) {
package/bin/cdshi.js CHANGED
@@ -15,16 +15,26 @@ const compiler = require('../lib/compiler');
15
15
  const fs = require('fs');
16
16
  fs.readFile( '/dev/stdin', 'utf8', highlight );
17
17
 
18
- const categoryChars = {
18
+ const categoryChars = { // default: first char of category name
19
+ // first char lowercase = reference other than via extend/annotate:
19
20
  artref: 'm',
21
+ uncheckedRef: 'r',
22
+ uncheckedAnno: 'a',
20
23
  paramname: 'b',
24
+ typeparamname: 'b',
25
+ // first char uppercase = definition, extend/annotate ref, or path after `namespace`:
21
26
  Entity: 'D',
22
27
  Enum: 'H',
23
28
  Index: 'J',
24
29
  AnnoDef: 'V',
25
- Extend: 'Z',
26
- Annotate: 'Z',
30
+ Ext: 'Z', // extend/annotate on main def other than service/context
31
+ ExtService: 'S', // highlight like service definition
32
+ ExtContext: 'C', // highlight like context definition
33
+ // ExtElement: 'E', // using the first letter is the default
34
+ ExtBoundAction: 'B', // highlight like bound action definition
35
+ ExtParam: 'P', // highlight like entity/action parameter definition
27
36
  Event: 'Y',
37
+ // Remark: do not use `x`/`X` (hex literal `x'1e3d'`)
28
38
  };
29
39
 
30
40
  function highlight( err, buf ) {
@@ -8,7 +8,11 @@ Note: `beta` fixes, changes and features are listed in this ChangeLog just for i
8
8
  The compiler behavior concerning `beta` features can change at any time without notice.
9
9
  **Don't use `beta` fixes, changes and features in productive mode.**
10
10
 
11
- ## Version 4.x.x - 2024-mm-dd
11
+ ## Version 4.8.0 - 2024-03-21
12
+
13
+ ### Removed `vectorType`
14
+
15
+ It is now always enabled.
12
16
 
13
17
  ### Added `v5preview`
14
18
 
package/lib/api/main.js CHANGED
@@ -9,6 +9,8 @@ const messages = lazyload('../base/messages');
9
9
  const compiler = lazyload('../compiler/index');
10
10
  const toCsn = lazyload('../json/to-csn');
11
11
  const forOdataNew = lazyload('../transform/forOdata.js');
12
+ const generateDrafts = lazyload('../transform/draft/odata');
13
+ const tenant = lazyload('../transform/addTenantFields');
12
14
  const toSql = lazyload('../render/toSql');
13
15
  const toCdl = require('../render/toCdl');
14
16
  const modelCompare = lazyload('../modelCompare/compare');
@@ -155,11 +157,32 @@ function odataInternal( csn, internalOptions, messageFunctions ) {
155
157
  * @returns {oDataCSN} Return an oData-pre-processed CSN
156
158
  */
157
159
  function odata( csn, options, messageFunctions ) {
158
- trace.traceApi('for.odata', options);
159
160
  const internalOptions = prepareOptions.for.odata(options);
161
+ messageFunctions.setOptions( internalOptions );
160
162
  return odataInternal(csn, internalOptions, messageFunctions);
161
163
  }
162
164
 
165
+ /**
166
+ * Return a structured CSN for the Java Runtime: with drafts and tenant support
167
+ *
168
+ * @param {CSN.Model} csn Clean input CSN
169
+ * @param {ODataOptions} options Options
170
+ * @param {object} messageFunctions Message functions such as `error()`, `info()`, …
171
+ * @returns {CSN.Model} a CSN for the Java Runtime
172
+ */
173
+ function java( csn, options, messageFunctions ) {
174
+ const internalOptions = prepareOptions.for.java(options);
175
+ internalOptions.transformation = 'odata'; // otherwise generateDrafts adds tenant
176
+ messageFunctions.setOptions( internalOptions );
177
+ handleTenantDiscriminator(options, internalOptions, messageFunctions);
178
+
179
+ const clone = cloneCsn.cloneFullCsn(csn, internalOptions);
180
+ const draft = generateDrafts(clone, internalOptions, undefined, messageFunctions);
181
+ if (internalOptions.tenantDiscriminator)
182
+ tenant.addTenantFields(draft, internalOptions, messageFunctions );
183
+ return draft;
184
+ }
185
+
163
186
  /**
164
187
  * Process the given csn back to cdl.
165
188
  *
@@ -169,8 +192,8 @@ function odata( csn, options, messageFunctions ) {
169
192
  * @returns {object} { model: string, namespace: string }
170
193
  */
171
194
  function cdl( csn, options, messageFunctions ) {
172
- trace.traceApi('to.cdl', options);
173
195
  const internalOptions = prepareOptions.to.cdl(options);
196
+ messageFunctions.setOptions( internalOptions );
174
197
  return toCdl.csnToCdl(csn, internalOptions, messageFunctions);
175
198
  }
176
199
 
@@ -204,6 +227,7 @@ function csnForSql( csn, internalOptions, messageFunctions ) {
204
227
  */
205
228
  function forSql( csn, options, messageFunctions ) {
206
229
  const internalOptions = prepareOptions.to.sql(options);
230
+ messageFunctions.setOptions( internalOptions );
207
231
  return csnForSql(csn, internalOptions, messageFunctions); // already sorted for test mode
208
232
  }
209
233
 
@@ -219,6 +243,7 @@ function forSql( csn, options, messageFunctions ) {
219
243
  function forHdi( csn, options, messageFunctions ) {
220
244
  const internalOptions = prepareOptions.to.hdi(options);
221
245
  internalOptions.transformation = 'sql';
246
+ messageFunctions.setOptions( internalOptions );
222
247
  const transformedCsn = forRelationalDB.transformForRelationalDBWithCsn(
223
248
  csn, internalOptions, messageFunctions
224
249
  );
@@ -236,6 +261,7 @@ function forHdi( csn, options, messageFunctions ) {
236
261
  function forHdbcds( csn, options, messageFunctions ) {
237
262
  const internalOptions = prepareOptions.to.hdbcds(options);
238
263
  internalOptions.transformation = 'hdbcds';
264
+ messageFunctions.setOptions( internalOptions );
239
265
  const hanaCsn = forRelationalDB.transformForRelationalDBWithCsn(
240
266
  csn, internalOptions, messageFunctions
241
267
  );
@@ -252,8 +278,9 @@ function forHdbcds( csn, options, messageFunctions ) {
252
278
  * @private
253
279
  */
254
280
  function forEffective( csn, options, messageFunctions ) {
255
- const internalOptions = prepareOptions.to.sql(options);
281
+ const internalOptions = prepareOptions.for.effective(options);
256
282
  internalOptions.transformation = 'effective';
283
+ messageFunctions.setOptions( internalOptions );
257
284
  if (options.tenantDiscriminator) {
258
285
  messageFunctions.error('api-invalid-option', null, {
259
286
  '#': 'forbidden',
@@ -276,9 +303,9 @@ function forEffective( csn, options, messageFunctions ) {
276
303
  * @returns {SQL[]} Array of SQL statements, tables first, views second
277
304
  */
278
305
  function sql( csn, options, messageFunctions ) {
279
- trace.traceApi('to.sql', options);
280
306
  const internalOptions = prepareOptions.to.sql(options);
281
307
  internalOptions.transformation = 'sql';
308
+ messageFunctions.setOptions( internalOptions );
282
309
 
283
310
  handleTenantDiscriminator(options, internalOptions, messageFunctions);
284
311
 
@@ -303,8 +330,8 @@ function sql( csn, options, messageFunctions ) {
303
330
  * @returns {HDIArtifacts} { <filename>:<content>, ...}
304
331
  */
305
332
  function hdi( csn, options, messageFunctions ) {
306
- trace.traceApi('to.hdi', options);
307
333
  const internalOptions = prepareOptions.to.hdi(options);
334
+ messageFunctions.setOptions( internalOptions );
308
335
 
309
336
  handleTenantDiscriminator(options, internalOptions, messageFunctions);
310
337
 
@@ -410,8 +437,8 @@ function remapName( key, csn, filter = () => true ) {
410
437
  * - createsAndAlters: An array of SQL statements to ALTER/CREATE tables/views
411
438
  */
412
439
  function sqlMigration( csn, options, messageFunctions, beforeImage ) {
413
- trace.traceApi('to.sql.migration', options);
414
440
  const internalOptions = prepareOptions.to.sql(options);
441
+ messageFunctions.setOptions( internalOptions );
415
442
  handleTenantDiscriminator(options, internalOptions, messageFunctions);
416
443
  const { error, throwWithError } = messageFunctions;
417
444
 
@@ -563,8 +590,8 @@ function sqlMigration( csn, options, messageFunctions, beforeImage ) {
563
590
  * @returns {migration} The migration result
564
591
  */
565
592
  function hdiMigration( csn, options, messageFunctions, beforeImage ) {
566
- trace.traceApi('to.hdi.migration', options);
567
593
  const internalOptions = prepareOptions.to.hdi(options);
594
+ messageFunctions.setOptions( internalOptions );
568
595
  handleTenantDiscriminator(options, internalOptions, messageFunctions);
569
596
 
570
597
  // Prepare after-image.
@@ -651,9 +678,9 @@ sql.migration = sqlMigration;
651
678
  * @returns {HDBCDS} { <filename>:<content>, ...}
652
679
  */
653
680
  function hdbcds( csn, options, messageFunctions ) {
654
- trace.traceApi('to.hdbcds', options);
655
681
  const internalOptions = prepareOptions.to.hdbcds(options);
656
682
  internalOptions.transformation = 'hdbcds';
683
+ messageFunctions.setOptions( internalOptions );
657
684
 
658
685
  if (options.tenantDiscriminator) {
659
686
  messageFunctions.error('api-invalid-option', null, {
@@ -678,12 +705,12 @@ function hdbcds( csn, options, messageFunctions ) {
678
705
  * @returns {edm} The JSON representation of the service
679
706
  */
680
707
  function edm( csn, options, messageFunctions ) {
681
- trace.traceApi('to.edm', options);
682
708
  // If not provided at all, set service to 'undefined' to trigger validation
683
709
  const internalOptions = prepareOptions.to.edm(
684
710
  // eslint-disable-next-line comma-dangle
685
711
  options.service ? options : Object.assign({ service: undefined }, options)
686
712
  );
713
+ messageFunctions.setOptions( internalOptions );
687
714
 
688
715
  const { service } = options;
689
716
 
@@ -712,8 +739,8 @@ edm.all = edmall;
712
739
  * @returns {edms} { <service>:<JSON representation>, ...}
713
740
  */
714
741
  function edmall( csn, options, messageFunctions ) {
715
- trace.traceApi('to.edm.all', options);
716
742
  const internalOptions = prepareOptions.to.edm(options);
743
+ messageFunctions.setOptions( internalOptions );
717
744
  const { error } = messageFunctions;
718
745
 
719
746
  if (internalOptions.odataVersion === 'v2')
@@ -747,12 +774,12 @@ function edmall( csn, options, messageFunctions ) {
747
774
  * @returns {edmx} The XML representation of the service
748
775
  */
749
776
  function edmx( csn, options, messageFunctions ) {
750
- trace.traceApi('to.edmx', options);
751
777
  // If not provided at all, set service to 'undefined' to trigger validation
752
778
  const internalOptions = prepareOptions.to.edmx(
753
779
  // eslint-disable-next-line comma-dangle
754
780
  options.service ? options : Object.assign({ service: undefined }, options)
755
781
  );
782
+ messageFunctions.setOptions( internalOptions );
756
783
 
757
784
  const { service } = options;
758
785
 
@@ -782,8 +809,8 @@ edmx.all = edmxall;
782
809
  * @returns {edmxs} { <service>:<XML representation>, ...}
783
810
  */
784
811
  function edmxall( csn, options, messageFunctions ) {
785
- trace.traceApi('to.edmx.all', options);
786
812
  const internalOptions = prepareOptions.to.edmx(options);
813
+ messageFunctions.setOptions( internalOptions );
787
814
 
788
815
  const result = {};
789
816
  let oDataCsn = csn;
@@ -813,18 +840,18 @@ function edmxall( csn, options, messageFunctions ) {
813
840
  * If odataVersion is not 'v4', then no JSON is rendered
814
841
  *
815
842
  * @param {CSN|oDataCSN} csn Clean input CSN or a pre-transformed CSN
816
- * @param {ODataOptions} [options={}] Options
843
+ * @param {ODataOptions} options Options
817
844
  * @param {object} messageFunctions Message functions such as `error()`, `info()`, …
818
845
  * @returns {object} { <protocol> : { <ServiceName>: { edmx: <XML representation>, edm: <JSON representation> } } }
819
846
  */
820
847
  // @ts-ignore
821
- function odata2( csn, options = {}, messageFunctions ) {
822
- trace.traceApi('to.odata', options);
848
+ function odata2( csn, options, messageFunctions ) {
823
849
  // If not provided at all, set service to undefined to trigger validation
824
850
  const internalOptions = prepareOptions.to.odata(
825
851
  // eslint-disable-next-line comma-dangle
826
852
  options.service ? options : Object.assign({ service: undefined }, options)
827
853
  );
854
+ messageFunctions.setOptions( internalOptions );
828
855
 
829
856
  const { service } = options;
830
857
 
@@ -859,13 +886,13 @@ odata2.all = odataall;
859
886
  * If odataVersion is not 'v4', then no JSON is rendered
860
887
  *
861
888
  * @param {CSN|oDataCSN} csn Clean input CSN or a pre-transformed CSN
862
- * @param {ODataOptions} [options={}] Options
889
+ * @param {ODataOptions} options Options
863
890
  * @param {object} messageFunctions Message functions such as `error()`, `info()`, …
864
891
  * @returns {object} { <protocol>: { <serviceName>: { edmx: <XML representation>, edm: <JSON representation> } } }
865
892
  */
866
- function odataall( csn, options = {}, messageFunctions ) {
867
- trace.traceApi('to.odata.all', options);
893
+ function odataall( csn, options, messageFunctions ) {
868
894
  const internalOptions = prepareOptions.to.odata(options);
895
+ messageFunctions.setOptions( internalOptions );
869
896
  const { error } = messageFunctions;
870
897
 
871
898
  if (internalOptions.odataVersion === 'v2')
@@ -999,6 +1026,7 @@ function flattenResultStructure( toProcess ) {
999
1026
 
1000
1027
  module.exports = {
1001
1028
  odata: publishCsnProcessor(odata, 'for.odata'),
1029
+ java: publishCsnProcessor(java, 'for.java'),
1002
1030
  cdl: publishCsnProcessor(cdl, 'to.cdl'),
1003
1031
  sql: publishCsnProcessor(sql, 'to.sql'),
1004
1032
  hdi: publishCsnProcessor(hdi, 'to.hdi'),
@@ -1048,6 +1076,7 @@ function publishCsnProcessor( processor, _name ) {
1048
1076
  * @returns {any} What ever the processor returns
1049
1077
  */
1050
1078
  function api( csn, options = {}, ...args ) {
1079
+ trace.traceApi(_name, options);
1051
1080
  const originalMessageLength = options.messages?.length;
1052
1081
  try {
1053
1082
  const messageFunctions = messages.makeMessageFunction(csn, options, _name);
@@ -1086,7 +1115,6 @@ function publishCsnProcessor( processor, _name ) {
1086
1115
  if (options.testMode) // Attach recompilation reason in testMode
1087
1116
  recompileMsg.message += `\n ↳ cause: ${ err.message }`;
1088
1117
 
1089
- // next line to be replaced by CSN parser call which reads the CSN object
1090
1118
  const xsn = compiler.recompileX(csn, options);
1091
1119
  const recompiledCsn = toCsn.compactModel(xsn);
1092
1120
  messageFunctions.setModel(recompiledCsn);
@@ -1220,7 +1248,8 @@ function lazyload( moduleName ) {
1220
1248
  }
1221
1249
 
1222
1250
  /**
1223
- * Error when tenantDiscriminator and withHanaAssociations is set by the user.
1251
+ * Error when tenantDiscriminator and withHanaAssociations is set by the user, or
1252
+ * if tenantDiscriminator is used with anything but "plain" mode.
1224
1253
  *
1225
1254
  * Set withHanaAssociations to false when tenantDiscriminator is used.
1226
1255
  *
@@ -1234,12 +1263,21 @@ function handleTenantDiscriminator( options, internalOptions, messageFunctions )
1234
1263
  option: 'tenantDiscriminator',
1235
1264
  prop: 'withHanaAssociations',
1236
1265
  });
1266
+ }
1237
1267
 
1238
- messageFunctions.throwWithAnyError();
1268
+ if (options.tenantDiscriminator && internalOptions.sqlMapping !== 'plain') {
1269
+ messageFunctions.error('api-invalid-combination', null, {
1270
+ '#': 'tenant-and-naming',
1271
+ option: 'tenantDiscriminator',
1272
+ prop: internalOptions.sqlMapping,
1273
+ value: 'plain',
1274
+ });
1239
1275
  }
1240
- else if (internalOptions.tenantDiscriminator) {
1276
+
1277
+ messageFunctions.throwWithError();
1278
+
1279
+ if (internalOptions.tenantDiscriminator)
1241
1280
  internalOptions.withHanaAssociations = false;
1242
- }
1243
1281
  }
1244
1282
 
1245
1283
 
@@ -35,6 +35,7 @@ const publicOptionsNewAPI = [
35
35
  'withHanaAssociations',
36
36
  // ODATA
37
37
  'odataOpenapiHints',
38
+ 'edm4OpenAPI',
38
39
  'odataVersion',
39
40
  'odataFormat',
40
41
  'odataContainment',
@@ -48,6 +49,9 @@ const publicOptionsNewAPI = [
48
49
  'serviceNames',
49
50
  //
50
51
  'dictionaryPrototype',
52
+ // for.effective
53
+ 'resolveSimpleTypes',
54
+ 'resolveProjections',
51
55
  ];
52
56
 
53
57
  // Internal options used for testing/debugging etc.
@@ -119,6 +123,8 @@ function translateOptions( input = {}, defaults = {}, hardRequire = {},
119
123
  // Overwrite with the hardRequire options - like src: sql in to.sql()
120
124
  Object.assign(options, hardRequire);
121
125
 
126
+ reclassifyErrorsForOpenApi( options );
127
+
122
128
  // Convenience for $user -> $user.id replacement
123
129
  if (options.variableReplacements && options.variableReplacements.$user && typeof options.variableReplacements.$user === 'string')
124
130
  options.variableReplacements.$user = { id: options.variableReplacements.$user };
@@ -126,6 +132,30 @@ function translateOptions( input = {}, defaults = {}, hardRequire = {},
126
132
  return options;
127
133
  }
128
134
 
135
+ /**
136
+ * Reclassify certain OData errors to warnings for the OData/EDM/EDMX backends.
137
+ * Some errors are not necessary for openAPI generation.
138
+ *
139
+ * @param {CSN.Options} options OData options
140
+ */
141
+ function reclassifyErrorsForOpenApi( options ) {
142
+ if (options.edm4OpenAPI) {
143
+ // shallow clone, so that we can modify severities without changing the user's.
144
+ options.severities = Object.assign({}, options.severities ?? {});
145
+
146
+ options.severities['odata-spec-violation-array'] = 'Warning';
147
+ options.severities['odata-spec-violation-assoc'] = 'Warning';
148
+ options.severities['odata-spec-violation-namespace'] = 'Warning';
149
+ options.severities['odata-spec-violation-param'] = 'Warning';
150
+ options.severities['odata-spec-violation-returns'] = 'Warning';
151
+ options.severities['odata-spec-violation-type-unknown'] = 'Warning';
152
+ options.severities['odata-spec-violation-no-key'] = 'Warning';
153
+ options.severities['odata-spec-violation-key-type'] = 'Warning';
154
+ options.severities['odata-spec-violation-property-name'] = 'Warning';
155
+ }
156
+ }
157
+
158
+
129
159
  module.exports = {
130
160
  to: {
131
161
  cdl: options => translateOptions(options, undefined, undefined, undefined, undefined, 'to.cdl'),
@@ -181,6 +211,16 @@ module.exports = {
181
211
  const defaultOptions = { sqlMapping: 'plain', sqlDialect: 'hana' };
182
212
  return translateOptions(options, defaultOptions, hardOptions, undefined, undefined, 'for.hana');
183
213
  },
214
+ effective: (options) => {
215
+ const hardOptions = {};
216
+ const defaultOptions = {
217
+ sqlMapping: 'plain', resolveSimpleTypes: true, resolveProjections: true,
218
+ };
219
+ const processed = translateOptions(options, defaultOptions, hardOptions, null, [ 'sql-dialect-and-naming' ], 'for.effective');
220
+
221
+ return Object.assign({}, processed);
222
+ },
223
+ java: options => translateOptions(options, { sqlMapping: 'plain' }, {}, undefined, undefined, 'for.java'),
184
224
  },
185
225
  overallOptions, // exported for testing
186
226
  };
@@ -0,0 +1,89 @@
1
+ 'use strict';
2
+
3
+ // Model agnostic builtins.
4
+ // It should not contain any specific to XSN, i.e. neither XSN structures
5
+ // nor any other XSN properties.
6
+
7
+ /**
8
+ * Checks whether the given absolute path is inside a reserved namespace.
9
+ *
10
+ * @param {string} absolute
11
+ * @returns {boolean}
12
+ */
13
+ function isInReservedNamespace( absolute ) {
14
+ return absolute === 'cds' || absolute.startsWith( 'cds.' ) &&
15
+ !absolute.match( /^cds\.foundation(\.|$)/ ) &&
16
+ !absolute.match( /^cds\.outbox(\.|$)/ ) && // Requested by Node runtime
17
+ !absolute.match( /^cds\.xt(\.|$)/ ); // Requested by Mtx
18
+ }
19
+
20
+ /**
21
+ * Tell if a type is (directly) a builtin type
22
+ * Note that in CSN builtins are not in the definition of the model, so we can only
23
+ * check against their absolute names. Builtin types are "cds.<something>", i.e. they
24
+ * are directly in 'cds', but not for example in 'cds.foundation'.
25
+ *
26
+ * @param {string|object} type
27
+ * @returns {boolean}
28
+ */
29
+ function isBuiltinType( type ) {
30
+ type = typeof type === 'string' ? type : type?.ref?.[0];
31
+ return type && isInReservedNamespace( type );
32
+ }
33
+
34
+ const magicVariables = [
35
+ '$user',
36
+ '$at',
37
+ '$valid',
38
+ '$now',
39
+ '$tenant',
40
+ '$session',
41
+ ];
42
+
43
+ /**
44
+ * Tell if a name is a magic variable
45
+ *
46
+ * @param {string} name
47
+ * @returns {boolean}
48
+ */
49
+ function isMagicVariable( name ) {
50
+ return typeof name === 'string' && magicVariables.includes(name);
51
+ }
52
+
53
+ /**
54
+ * Properties that are required next to `=` to make an annotation value an actual expression
55
+ * and not some foreign structure.
56
+ *
57
+ * @type {string[]}
58
+ */
59
+ const xprInAnnoProperties = [
60
+ 'ref', 'xpr', 'list', 'literal', 'val',
61
+ '#', 'func', 'args', 'SELECT', 'SET',
62
+ 'cast',
63
+ ];
64
+
65
+ /**
66
+ * Functions without parentheses in CDL (common standard SQL-92 functions)
67
+ * (do not add more - make it part of the SQL renderer to remove parentheses for
68
+ * other funny SQL functions like CURRENT_UTCTIMESTAMP).
69
+ */
70
+ const functionsWithoutParens = [
71
+ 'CURRENT_DATE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP',
72
+ 'CURRENT_USER', 'SESSION_USER', 'SYSTEM_USER',
73
+ ];
74
+
75
+ /**
76
+ * Return whether JSON object `val` is a representation for an annotation expression
77
+ */
78
+ function isAnnotationExpression( val ) {
79
+ return val?.['='] !== undefined && xprInAnnoProperties.some( prop => val[prop] !== undefined );
80
+ }
81
+
82
+ module.exports = {
83
+ xprInAnnoProperties,
84
+ functionsWithoutParens,
85
+ isInReservedNamespace,
86
+ isBuiltinType,
87
+ isMagicVariable,
88
+ isAnnotationExpression,
89
+ }
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { functionsWithoutParens } = require('../compiler/builtins');
3
+ const { functionsWithoutParens } = require('./builtins');
4
4
 
5
5
  module.exports = {
6
6
  // CDL reserved keywords, used for automatic quoting in 'toCdl' renderer
@@ -207,6 +207,7 @@ module.exports = {
207
207
  'ABAP_TIME',
208
208
  'ABAP_XSTRING',
209
209
  'ABS',
210
+ 'ABSOLUTE',
210
211
  'ACOS',
211
212
  'ADD_DAYS',
212
213
  'ADD_MONTHS',
@@ -529,6 +530,7 @@ module.exports = {
529
530
  'RAW',
530
531
  'RDICT',
531
532
  'REAL',
533
+ 'REAL_VECTOR',
532
534
  'RECORD_COMMIT_TIMESTAMP',
533
535
  'RECORD_COUNT',
534
536
  'RECORD_ID',
@@ -579,6 +581,7 @@ module.exports = {
579
581
  'ST_ALPHASHAPEAGGR',
580
582
  'ST_ALPHASHAPEAREAAGGR',
581
583
  'ST_ALPHASHAPEEDGEAGGR',
584
+ 'ST_ASESRIJSON',
582
585
  'ST_ASGEOJSON',
583
586
  'ST_ASMVT',
584
587
  'ST_ASSVGAGGR',
@@ -828,6 +831,7 @@ module.exports = {
828
831
  'SIMILAR',
829
832
  'SOME',
830
833
  'SYMMETRIC',
834
+ 'SYSTEM_USER',
831
835
  'TABLE',
832
836
  'TABLESAMPLE',
833
837
  'THEN',