@sap/cds-compiler 3.1.0 → 3.3.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 (100) hide show
  1. package/CHANGELOG.md +90 -3
  2. package/bin/cdsc.js +1 -1
  3. package/doc/CHANGELOG_BETA.md +18 -0
  4. package/lib/api/main.js +8 -13
  5. package/lib/base/error.js +2 -2
  6. package/lib/base/keywords.js +2 -24
  7. package/lib/base/message-registry.js +43 -14
  8. package/lib/base/messages.js +20 -10
  9. package/lib/base/model.js +1 -1
  10. package/lib/checks/actionsFunctions.js +1 -1
  11. package/lib/checks/annotationsOData.js +2 -2
  12. package/lib/checks/arrayOfs.js +15 -7
  13. package/lib/checks/cdsPersistence.js +1 -1
  14. package/lib/checks/checkForTypes.js +48 -0
  15. package/lib/checks/defaultValues.js +2 -2
  16. package/lib/checks/elements.js +81 -6
  17. package/lib/checks/foreignKeys.js +12 -13
  18. package/lib/checks/invalidTarget.js +10 -11
  19. package/lib/checks/managedInType.js +21 -15
  20. package/lib/checks/nullableKeys.js +1 -1
  21. package/lib/checks/onConditions.js +9 -9
  22. package/lib/checks/parameters.js +21 -0
  23. package/lib/checks/selectItems.js +1 -1
  24. package/lib/checks/types.js +2 -2
  25. package/lib/checks/utils.js +17 -7
  26. package/lib/checks/validator.js +26 -14
  27. package/lib/compiler/assert-consistency.js +13 -6
  28. package/lib/compiler/builtins.js +8 -0
  29. package/lib/compiler/checks.js +40 -33
  30. package/lib/compiler/define.js +50 -44
  31. package/lib/compiler/extend.js +303 -37
  32. package/lib/compiler/kick-start.js +2 -35
  33. package/lib/compiler/populate.js +83 -62
  34. package/lib/compiler/propagator.js +1 -1
  35. package/lib/compiler/resolve.js +61 -104
  36. package/lib/compiler/shared.js +16 -6
  37. package/lib/compiler/tweak-assocs.js +25 -12
  38. package/lib/compiler/utils.js +2 -2
  39. package/lib/edm/annotations/genericTranslation.js +15 -5
  40. package/lib/edm/csn2edm.js +10 -10
  41. package/lib/edm/edm.js +17 -9
  42. package/lib/edm/edmPreprocessor.js +82 -42
  43. package/lib/edm/edmUtils.js +18 -16
  44. package/lib/gen/Dictionary.json +14 -0
  45. package/lib/gen/language.checksum +1 -1
  46. package/lib/gen/language.interp +3 -2
  47. package/lib/gen/languageParser.js +4205 -4100
  48. package/lib/inspect/inspectModelStatistics.js +1 -1
  49. package/lib/inspect/inspectPropagation.js +23 -9
  50. package/lib/json/csnVersion.js +1 -1
  51. package/lib/json/from-csn.js +26 -19
  52. package/lib/json/to-csn.js +47 -5
  53. package/lib/language/antlrParser.js +1 -1
  54. package/lib/language/genericAntlrParser.js +29 -13
  55. package/lib/language/language.g4 +28 -8
  56. package/lib/main.d.ts +3 -6
  57. package/lib/model/.eslintrc.json +13 -0
  58. package/lib/model/api.js +4 -2
  59. package/lib/model/csnRefs.js +74 -47
  60. package/lib/model/csnUtils.js +236 -218
  61. package/lib/model/enrichCsn.js +41 -31
  62. package/lib/model/revealInternalProperties.js +61 -57
  63. package/lib/model/sortViews.js +31 -31
  64. package/lib/modelCompare/compare.js +6 -6
  65. package/lib/optionProcessor.js +5 -0
  66. package/lib/render/manageConstraints.js +2 -2
  67. package/lib/render/toCdl.js +31 -44
  68. package/lib/render/toHdbcds.js +7 -5
  69. package/lib/render/toRename.js +4 -4
  70. package/lib/render/toSql.js +11 -5
  71. package/lib/render/utils/common.js +20 -9
  72. package/lib/render/utils/sql.js +5 -5
  73. package/lib/transform/db/applyTransformations.js +32 -3
  74. package/lib/transform/db/expansion.js +81 -37
  75. package/lib/transform/db/flattening.js +1 -1
  76. package/lib/transform/db/temporal.js +1 -1
  77. package/lib/transform/db/transformExists.js +1 -1
  78. package/lib/transform/forOdataNew.js +10 -7
  79. package/lib/transform/{forHanaNew.js → forRelationalDB.js} +7 -7
  80. package/lib/transform/localized.js +28 -19
  81. package/lib/transform/odata/toFinalBaseType.js +8 -11
  82. package/lib/transform/odata/typesExposure.js +1 -1
  83. package/lib/transform/transformUtilsNew.js +101 -39
  84. package/lib/transform/translateAssocsToJoins.js +5 -4
  85. package/lib/utils/moduleResolve.js +5 -5
  86. package/lib/utils/objectUtils.js +3 -3
  87. package/package.json +2 -2
  88. package/share/messages/anno-duplicate-unrelated-layer.md +6 -6
  89. package/share/messages/check-proper-type-of.md +4 -4
  90. package/share/messages/check-proper-type.md +2 -2
  91. package/share/messages/duplicate-autoexposed.md +4 -4
  92. package/share/messages/extend-repeated-intralayer.md +4 -5
  93. package/share/messages/extend-unrelated-layer.md +4 -4
  94. package/share/messages/message-explanations.json +3 -1
  95. package/share/messages/redirected-to-ambiguous.md +7 -6
  96. package/share/messages/redirected-to-complex.md +63 -0
  97. package/share/messages/redirected-to-unrelated.md +6 -5
  98. package/share/messages/rewrite-not-supported.md +4 -4
  99. package/share/messages/syntax-expected-integer.md +3 -3
  100. package/share/messages/wildcard-excluding-one.md +37 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,91 @@
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 3.3.2 - 2022-09-30
11
+
12
+ ### Fixed
13
+
14
+ - to.edm(x): Set `Scale` (V4) or `@sap:variable-scale` (V2) attributes correctly when overwriting `cds.Decimal`
15
+ with `@odata.Scale`.
16
+ - to.sql: For dialect `postgres`, add braces around `$now`, `$at.from` and `$at.to`.
17
+
18
+ ## Version 3.3.0 - 2022-09-29
19
+
20
+ ### Added
21
+
22
+ - Nested projections can be used without `beta` option:
23
+ + Support `expand`: columns can look like `assoc_or_struct_or_tabalias { col_expression1, … }`,
24
+ `longer.ref as name { *, … } excluding { … }`, `{ col_expression1 as sub1, … } as name`, etc.
25
+ + Support `inline`: columns can look like `assoc_or_struct_or_tabalias.{ col_expression1, … }`,
26
+ `longer.ref[filter = condition].{ *, … } excluding { … }`, `assoc_or_struct_or_tabalias.*`, etc.
27
+ - to.sql/hdi/hdbcds/edm(x)/for.odata: Allow to structure comparison against `is [not] null`.
28
+ - to.sql: Support dialect `postgres` - generates SQL intended for PostgreSQL. Not supported are `cds.hana` data types and views with parameters.
29
+
30
+ ### Changed
31
+
32
+ - A valid redirection target does not depend on parameters anymore. This
33
+ change could induce a redirection error, which could easily solved by assigning
34
+ `@cds.redirection.target: false` to the entity with “non-matching” parameters.
35
+ - Properly issue an error when projecting associations with parameter
36
+ references in the `on` condition. Before this change, the compiler dumped
37
+ when projecting such an association in a view on top.
38
+ - Update OData vocabularies 'Capabilities', 'Common', 'UI'.
39
+ - to.cdl:
40
+ + Extensions are now always put into property `model` of `to.cdl()`s result.
41
+ + Actions on views and projections are now rendered as part of the definition, instead of an extension.
42
+ - to.edm(x): `@Capabilities` 'pull up' supports all counterpart properties of `@Capabilities.NavigationPropertyRestriction`
43
+ except for properties `NavigationProperty` and `Navigability`.
44
+ - to.hdi: Updated list of `keywords` which must be quoted in naming mode `plain`.
45
+ - to.sql/hdi/hdbcds/edm(x)/for.odata: Reject structure comparison with operators `<,>,<=,>=`. Message id `expr-unexpected-operator`
46
+ is downgradable to a warning.
47
+
48
+ ### Fixed
49
+
50
+ - Do not issue a warning anymore when adding elements via multiple `extend` statements in the same file.
51
+ - An info message for annotating builtins through `extend` statements is now reported, similar to `annotate`.
52
+ - Fix auto-redirection for target of new assoc in query entity
53
+ - for.odata: `@readonly/insertonly/mandatory: false` are not expanded.
54
+
55
+ ## Version 3.2.0 - 2022-08-30
56
+
57
+ ### Added
58
+
59
+ - New Integer types with these mappings:
60
+
61
+ | CDS | OData | SQL | HANA CDS |
62
+ | --------- | --------- | -------- | ------------- |
63
+ | cds.UInt8 | Edm.Byte | TINYINT | hana.TINYINT |
64
+ | cds.Int16 | Edm.Int16 | SMALLINT | hana.SMALLINT |
65
+ | cds.Int32 | Edm.Int32 | INTEGER | cds.Integer |
66
+ | cds.Int64 | Edm.Int64 | BIGINT | cds.Integer64 |
67
+
68
+ - Properties of type definitions and types of direct elements can now be extended,
69
+ e.g. `extend T with (length: 10);`
70
+
71
+ - CDL parser: support SQL function `substr_regexpr` with its special argument syntax.
72
+
73
+ ### Fixed
74
+
75
+ - An internal dump could have occurred in certain situations
76
+ for models with cyclic type definitions.
77
+ - Annotations on inferred enum elements of views were lost during recompilation.
78
+ - to.cdl: Annotations on enum value in query elements were lost.
79
+ - for.odata: Allow dynamic shortcut annotation values (`$edmJson`).
80
+ - to.edm(x):
81
+ + Don't overwrite annotations of input model.
82
+ + Ignore `null` values in `$edmJson` strings.
83
+ - to.hdi.migration: Don't interpret bound action changes as element changes.
84
+
85
+ ## Version 3.1.2 - 2022-08-19
86
+
87
+ ### Fixed
88
+
89
+ - to.edm(x):
90
+ + `@Capabilities` 'pull up' for containment trees should not prefix the
91
+ dynamic annotation paths of the root container.
92
+ + Remove service namespace prefix of a parameter type for function/action annotation targets
93
+ in multi schema mode if the parameter type is defined in an alternative schema.
94
+
10
95
  ## Version 3.1.0 - 2022-08-04
11
96
 
12
97
  ### Added
@@ -15,8 +100,8 @@ The compiler behavior concerning `beta` features can change at any time without
15
100
  `extend SomeEntity with FirstInclude, SecondInclude;`
16
101
  - Aspects can now have actions and functions, similar to entities. Aspects can be extended by actions as well.
17
102
  - `cdsc`:
18
- - `toCsn` now supports `--with-locations` which adds a `$location` property to artifacts
19
- - `toHana`/`toSql` now supports `--disable-hana-comments`, which disables rendering of doc-comments for HANA.
103
+ + `toCsn` now supports `--with-locations` which adds a `$location` property to artifacts
104
+ + `toHana`/`toSql` now supports `--disable-hana-comments`, which disables rendering of doc-comments for HANA.
20
105
  - to.hdi/sql/hdbcds: Support FK-access in `ORDER BY` and `GROUP BY`
21
106
  - to.hdi.migration: Detect an implicit change from `not null` to `null` and render corresponding `ALTER`
22
107
 
@@ -41,8 +126,10 @@ The compiler behavior concerning `beta` features can change at any time without
41
126
  - compiler:
42
127
  + `cast(elem as EnumType)` crashed the compiler.
43
128
  + Annotations on sub-elements in query entities were lost during re-compilation.
44
- + An association's cardinality was lost for associations published in projections.
129
+ + An association's cardinality was lost for new associations published in projections.
45
130
  + Annotations on indirect action parameters were lost in CSN flavor `gensrc`.
131
+ + Re-allow `annotate` statements referring to the same element twice,
132
+ even if there are annotation assignments for sub elements.
46
133
  + If a file's content starts with `{` and if neither file extension is known nor
47
134
  `fallbackParser` is set, assume the source is CSN.
48
135
  - all backends: references in `order by` _expressions_ are correctly resolved.
package/bin/cdsc.js CHANGED
@@ -409,7 +409,7 @@ function executeCommandLine(command, options, args) {
409
409
  }
410
410
  else {
411
411
  const sqlResult = main.to.sql(csn, options);
412
- writeToFileOrDisplay(options.out, 'model.sql', sqlResult.join('\n'), true);
412
+ writeToFileOrDisplay(options.out, 'model.sql', sqlResult.join('\n\n'), true);
413
413
  }
414
414
  return model;
415
415
  }
@@ -8,6 +8,24 @@ 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 3.3.0 - 2022-09-29
12
+
13
+ ### Removed `nestedProjections`
14
+
15
+ - This is now the default - see CHANGELOG entry for 3.3.0.
16
+
17
+ ### Fixed `nestedProjections`
18
+
19
+ - Issue an error for an unexpected `as ‹alias›` for references with `inline`;
20
+ people likely have confused `inline` with `expand`.
21
+ - Resolving references in the user-provided `on` condition of projected or newly-defined
22
+ associations inside `expand` and `inline` now works correctly.
23
+ - Correct `key` propagation for references with `expand` or `inline`.
24
+ - If an element is projected with sibling `expand`, the original data structure is usually
25
+ _not preserved_ (why use an `expand` if it is?). Therefore, the compiler cannot auto-rewrite
26
+ the `on` condition of unmanaged associations if such an element is referred to in the original
27
+ `on` condition. In that case, provide your own via `…: redirected to … on ‹condition›`.
28
+
11
29
  ## Version 3.1.0 - 2022-08-04
12
30
 
13
31
  ### Added `optionalActionFunctionParameters`
package/lib/api/main.js CHANGED
@@ -15,7 +15,7 @@ const modelCompare = lazyload('../modelCompare/compare');
15
15
  const sortViews = lazyload('../model/sortViews');
16
16
  const csnUtils = lazyload('../model/csnUtils');
17
17
  const timetrace = lazyload('../utils/timetrace');
18
- const forHanaNew = lazyload('../transform/forHanaNew');
18
+ const forRelationalDB = lazyload('../transform/forRelationalDB');
19
19
 
20
20
  /**
21
21
  * Return the artifact name for use for the hdbresult object
@@ -93,12 +93,12 @@ function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMism
93
93
 
94
94
  for (const name of relevantOptionNames ) {
95
95
  if (options[name] !== csn.meta.options[name])
96
- error('wrong-pretransformed-csn', null, `Expected pre-processed CSN to have option "${ name }" set to "${ options[name] }". Found: "${ csn.meta.options[name] }"`);
96
+ error('wrong-pretransformed-csn', null, {}, `Expected pre-processed CSN to have option "${ name }" set to "${ options[name] }". Found: "${ csn.meta.options[name] }"`);
97
97
  }
98
98
 
99
99
  for (const name of warnAboutMismatch ) {
100
100
  if (options[name] !== csn.meta.options[name])
101
- warning('options-mismatch-pretransformed-csn', null, `Expected pre-processed CSN to have option "${ name }" set to "${ options[name] }". Found: "${ csn.meta.options[name] }"`);
101
+ warning('options-mismatch-pretransformed-csn', null, {}, `Expected pre-processed CSN to have option "${ name }" set to "${ options[name] }". Found: "${ csn.meta.options[name] }"`);
102
102
  }
103
103
 
104
104
  throwWithAnyError();
@@ -147,7 +147,7 @@ function odata(csn, options = {}) {
147
147
  *
148
148
  * @param {object} csn CSN to process
149
149
  * @param {object} [externalOptions={}] Options
150
- * @returns {object} { model: string, namespace: string, unappliedExtensions: string }
150
+ * @returns {object} { model: string, namespace: string }
151
151
  */
152
152
  function cdl(csn, externalOptions = {}) {
153
153
  const internalOptions = prepareOptions.to.cdl(externalOptions);
@@ -165,7 +165,7 @@ function cdl(csn, externalOptions = {}) {
165
165
  function forSql(csn, options = {}) {
166
166
  const internalOptions = prepareOptions.to.sql(options);
167
167
  internalOptions.transformation = 'sql';
168
- const transformedCsn = forHanaNew.transformForHanaWithCsn(csn, internalOptions, 'to.sql');
168
+ const transformedCsn = forRelationalDB.transformForRelationalDBWithCsn(csn, internalOptions, 'to.sql');
169
169
 
170
170
  return internalOptions.testMode ? toCsn.sortCsn(transformedCsn, internalOptions) : transformedCsn;
171
171
  }
@@ -180,7 +180,7 @@ function forSql(csn, options = {}) {
180
180
  function forHdi(csn, options = {}) {
181
181
  const internalOptions = prepareOptions.to.hdi(options);
182
182
  internalOptions.transformation = 'sql';
183
- const transformedCsn = forHanaNew.transformForHanaWithCsn(csn, internalOptions, 'to.hdi');
183
+ const transformedCsn = forRelationalDB.transformForRelationalDBWithCsn(csn, internalOptions, 'to.hdi');
184
184
 
185
185
  return internalOptions.testMode ? toCsn.sortCsn(transformedCsn, internalOptions) : transformedCsn;
186
186
  }
@@ -196,7 +196,7 @@ function forHdbcds(csn, options = {}) {
196
196
  const internalOptions = prepareOptions.to.hdbcds(options);
197
197
  internalOptions.transformation = 'hdbcds';
198
198
 
199
- const hanaCsn = forHanaNew.transformForHanaWithCsn(csn, internalOptions, 'to.hdbcds');
199
+ const hanaCsn = forRelationalDB.transformForRelationalDBWithCsn(csn, internalOptions, 'to.hdbcds');
200
200
 
201
201
  return internalOptions.testMode ? toCsn.sortCsn(hanaCsn, internalOptions) : hanaCsn;
202
202
  }
@@ -212,11 +212,6 @@ function sql(csn, options = {}) {
212
212
  const internalOptions = prepareOptions.to.sql(options);
213
213
  internalOptions.transformation = 'sql';
214
214
 
215
- const { error } = messages.makeMessageFunction(csn, internalOptions, 'for.odata');
216
-
217
- if (internalOptions.sqlDialect === 'postgres' && !baseModel.isBetaEnabled(internalOptions, 'postgres'))
218
- error(null, null, 'sqlDialect: \'postgres\' is only supported with beta-flag \'postgres\'');
219
-
220
215
  // we need the CSN for view sorting
221
216
  const transformedCsn = forSql(csn, options);
222
217
  const sqls = toSql.toSqlDdl(transformedCsn, internalOptions);
@@ -514,7 +509,7 @@ function edmall(csn, options = {}) {
514
509
  const { error } = messages.makeMessageFunction(csn, internalOptions, 'for.odata');
515
510
 
516
511
  if (internalOptions.odataVersion === 'v2')
517
- error(null, null, 'OData JSON output is not available for OData V2');
512
+ error(null, null, {}, 'OData JSON output is not available for OData V2');
518
513
 
519
514
  const result = {};
520
515
  let oDataCsn = csn;
package/lib/base/error.js CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
  class CompilerAssertion extends Error {
8
8
  constructor(message) {
9
- super(message);
9
+ super(`cds-compiler assertion failed: ${message}`);
10
10
  }
11
11
  }
12
12
 
@@ -16,7 +16,7 @@ class CompilerAssertion extends Error {
16
16
  */
17
17
  class ModelError extends Error {
18
18
  constructor(message) {
19
- super(message);
19
+ super(`cds-compiler model error: ${message}`);
20
20
  }
21
21
  }
22
22
 
@@ -188,10 +188,7 @@ module.exports = {
188
188
  'WITHOUT'
189
189
  ],
190
190
  // SAP HANA keywords, used for smart quoting in to-hdi.plain
191
- // Taken from https://help.sap.com/viewer/7c78579ce9b14a669c1f3295b0d8ca16/Cloud/en-US/28bcd6af3eb6437892719f7c27a8a285.html
192
- // Better use keywords in ptime/query/parser/syntax/qp_keyword.cc minus those
193
- // in rule unreserved_keyword_column (=…_common - 'CONSTRAINT') in
194
- // ptime/query/parser/syntax/qp_gram.y of the HANA sources.
191
+ // See './scripts/keywords/hana/generateSqlKeywords.js'
195
192
  hana: [
196
193
  'ABAPITAB',
197
194
  'ABAPSTRUCT',
@@ -215,12 +212,10 @@ module.exports = {
215
212
  'ADD_MONTHS',
216
213
  'ADD_SECONDS',
217
214
  'ADD_YEARS',
218
- 'ADJACENCY',
219
215
  'ADOPT',
220
216
  'ALL',
221
217
  'ALPHANUM',
222
218
  'ALTER',
223
- 'ANALYTIC',
224
219
  'ANY',
225
220
  'APPLY_FILTER',
226
221
  'ARRAY',
@@ -397,7 +392,6 @@ module.exports = {
397
392
  'DISTANCE',
398
393
  'DISTINCT',
399
394
  'DOUBLE',
400
- 'DW_OPTIMIZED',
401
395
  'ELSE',
402
396
  'ELSEIF',
403
397
  'EMPTY',
@@ -411,12 +405,9 @@ module.exports = {
411
405
  'FALSE',
412
406
  'FILTER',
413
407
  'FIRST_VALUE',
414
- 'FLATTEN',
415
408
  'FLOAT',
416
409
  'FLOOR',
417
410
  'FOR',
418
- 'FORCE_FIRST_PASSWORD_CHANGE',
419
- 'FREESTYLESEARCHATTRIBUTE',
420
411
  'FROM',
421
412
  'FULL',
422
413
  'GET_NUM_SERVERS',
@@ -515,7 +506,6 @@ module.exports = {
515
506
  'NUMBER',
516
507
  'NUMERIC',
517
508
  'NVARCHAR',
518
- 'OBJECT',
519
509
  'OCCURRENCES_REGEXPR',
520
510
  'OF',
521
511
  'OLYMP',
@@ -640,16 +630,11 @@ module.exports = {
640
630
  'SYSTEM_TIME',
641
631
  'SYSUUID',
642
632
  'TABLE',
643
- 'TABLES',
644
633
  'TABLESAMPLE',
645
634
  'TAN',
646
635
  'TANH',
647
- 'TARGET',
648
- 'TEMPORARY',
649
636
  'TEXT',
650
637
  'TEXT_FILTER',
651
- 'THEN',
652
- 'THREAD',
653
638
  'TIME',
654
639
  'TIMELINE',
655
640
  'TIMESTAMP',
@@ -662,11 +647,8 @@ module.exports = {
662
647
  'TM_GET_RELEVANT_DOCUMENTS',
663
648
  'TM_GET_RELEVANT_TERMS',
664
649
  'TM_GET_SUGGESTED_TERMS',
665
- 'TOKEN',
666
- 'TOOLOPTION',
650
+ 'TO',
667
651
  'TOP',
668
- 'TOPK',
669
- 'TOTAL',
670
652
  'TO_BIGINT',
671
653
  'TO_BINARY',
672
654
  'TO_BLOB',
@@ -694,11 +676,7 @@ module.exports = {
694
676
  'TO_VARBINARY',
695
677
  'TO_VARCHAR',
696
678
  'TRACE',
697
- 'TRACEPROFILE',
698
- 'TRACES',
699
679
  'TRAILING',
700
- 'TRANSACTION',
701
- 'TREE',
702
680
  'TRIGGER_UPDATE_COLUMN',
703
681
  'TRIM',
704
682
  'TRUE',
@@ -97,6 +97,9 @@ const centralMessages = {
97
97
  'extend-repeated-intralayer': { severity: 'Warning' },
98
98
  'extend-unrelated-layer': { severity: 'Warning' },
99
99
 
100
+ 'ext-duplicate-extend-type': { severity: 'Error' },
101
+ 'ext-duplicate-extend-type-unrelated-layer': { severity: 'Error', configurableFor: true },
102
+
100
103
  'param-default': { severity: 'Error', configurableFor: 'deprecated' }, // not supported yet
101
104
 
102
105
  'query-undefined-element': { severity: 'Error' },
@@ -115,7 +118,8 @@ const centralMessages = {
115
118
  'ref-undefined-var': { severity: 'Error' },
116
119
  'ref-undefined-element': { severity: 'Error' },
117
120
  'ref-unknown-var': { severity: 'Info', errorFor: [ 'to.hdbcds', 'to.sql', 'to.hdi', 'to.rename' ] },
118
- 'ref-obsolete-parameters': { severity: 'Error', configurableFor: true }, // does not hurt us
121
+ 'ref-obsolete-parameters': { severity: 'Error', configurableFor: true },
122
+ // does not hurt us, but makes it tedious to detect parameter refs
119
123
  'ref-undefined-param': { severity: 'Error' },
120
124
  'ref-rejected-on': { severity: 'Error' },
121
125
  'ref-expected-element': { severity: 'Error' },
@@ -131,6 +135,8 @@ const centralMessages = {
131
135
  'service-nested-context': { severity: 'Error', configurableFor: true }, // does not hurt compile, TODO
132
136
  'service-nested-service': { severity: 'Error', configurableFor: 'deprecated' }, // not supported yet
133
137
 
138
+ 'expr-unexpected-operator': { severity: 'Error', configurableFor: true },
139
+
134
140
  // 'syntax-duplicate-annotate' came late with v3 - make it configurable as
135
141
  // fallback, but then parse.cdl is not supposed to work correctly (it can
136
142
  // then either issue an error or produce a CSN missing some annotations):
@@ -162,9 +168,18 @@ const centralMessages = {
162
168
  'unexpected-keys-for-composition': { severity: 'Error' }, // TODO: more than 30 chars
163
169
  'unmanaged-as-key': { severity: 'Error', configurableFor: 'deprecated' }, // is confusing
164
170
  'composition-as-key': { severity: 'Error', configurableFor: 'deprecated' }, // is confusing and not supported
165
- 'odata-spec-violation-array': { severity: 'Warning' }, // more than 30 chars
171
+ // Published! Used in @sap/cds-odata-v2-adapter-proxy; if renamed, add to oldMessageIds
172
+ 'odata-spec-violation-array': { severity: 'Warning' }, // more than 30 chars
173
+ // Published! Used in @sap/cds-odata-v2-adapter-proxy; if renamed, add to oldMessageIds
174
+ 'odata-spec-violation-assoc': { severity: 'Warning' }, // more than 30 chars
175
+ // Published! Used in @sap/cds-odata-v2-adapter-proxy; if renamed, add to oldMessageIds
166
176
  'odata-spec-violation-constraints': { severity: 'Info' }, // more than 30 chars
167
177
  'odata-spec-violation-id': { severity: 'Error', configurableFor: true },
178
+ 'odata-spec-violation-namespace': { severity: 'Warning' }, // more than 30 chars
179
+ // Published! Used in @sap/cds-odata-v2-adapter-proxy; if renamed, add to oldMessageIds
180
+ 'odata-spec-violation-param': { severity: 'Warning' }, // more than 30 chars
181
+ // Published! Used in @sap/cds-odata-v2-adapter-proxy; if renamed, add to oldMessageIds
182
+ 'odata-spec-violation-returns': { severity: 'Warning' }, // more than 30 chars
168
183
  'odata-spec-violation-type': { severity: 'Error', configurableFor: true },
169
184
  'odata-spec-violation-type-unknown': { severity: 'Warning' },
170
185
  'odata-spec-violation-no-key': { severity: 'Warning' },
@@ -180,15 +195,6 @@ const centralMessages = {
180
195
  // The keys will be added to `oldNames` of the new message, which is used for reclassification.
181
196
  const oldMessageIds = createDict({
182
197
  'old-anno-duplicate': 'anno-duplicate', // Example
183
-
184
- // These IDs are used by large stakeholders. If we change them, we should
185
- // be backward-compatible.
186
- // 'redirected-to-complex': 'TODO',
187
- // 'wildcard-excluding-one': 'TODO',
188
- // 'wildcard-excluding-many': 'TODO',
189
- // 'assoc-outside-service': 'TODO',
190
- // 'redirected-to-same': 'TODO',
191
- // 'query-navigate-many': 'TODO',
192
198
  });
193
199
 
194
200
  // Set up the old-to-new message ID mapping in the message registry.
@@ -209,6 +215,8 @@ for (const oldName in oldMessageIds) {
209
215
  // For messageIds, where no text has been provided via code (central def)
210
216
  const centralMessageTexts = {
211
217
  'api-invalid-option': {
218
+ // TODO: too many different error situations for one message id,
219
+ // TODO: use message parameter - do not use quotes in message texts
212
220
  std: 'Option $(NAME) is no longer supported! Use SNAPI options instead',
213
221
  magicVars: 'Option “magicVars” is no longer supported! Use “variableReplacements” instead. See <https://cap.cloud.sap/docs/guides/databases#configuring-variables> for details',
214
222
  user: 'Option “variableReplacements” expects “$user” instead of “user”. See <https://cap.cloud.sap/docs/guides/databases#configuring-variables> for details',
@@ -232,7 +240,7 @@ const centralMessageTexts = {
232
240
  'flatten-fkey-exists': 'Generated foreign key element $(NAME) for association $(ART) conflicts with existing element',
233
241
  },
234
242
 
235
- 'syntax-anno-ignored': {
243
+ 'syntax-ignoring-anno': {
236
244
  std: 'Annotations can\'t be used at prefix references',
237
245
  doc: 'Doc comments can\'t be used at prefix references',
238
246
  },
@@ -403,12 +411,32 @@ const centralMessageTexts = {
403
411
  'expected-entity': 'An entity, projection or view is expected here',
404
412
  'expected-struct': 'A type, entity, aspect or event with direct elements is expected here',
405
413
  'expected-type': 'A type or an element is expected here',
406
- // TOODO: text variant if the association does not start an an entity
414
+ // TODO: text variant if the association does not start an entity
407
415
  'expected-source': 'A query source must be an entity or an association',
408
416
  'expected-target': 'An entity or an aspect is expected here',
409
417
  'extend-columns': 'Artifact $(ART) can\'t be extended with columns, only projections can',
410
418
  'extend-repeated-intralayer': 'Unstable element order due to repeated extensions in same layer',
411
419
 
420
+
421
+ 'ext-duplicate-extend-type': 'Duplicate type extension for type $(TYPE)',
422
+ 'ext-duplicate-extend-type-unrelated-layer': 'Duplicate type extension for type $(TYPE)',
423
+ 'ext-invalid-type-property': {
424
+ std: 'Property $(PROP) can only be extended',
425
+ 'new-prop': 'Property $(PROP) can only be extended, not added',
426
+ // eslint-disable-next-line max-len
427
+ smaller: 'Property $(PROP) can only be extended, but $(LITERAL) is smaller than $(NUMBER) of type definition',
428
+ // eslint-disable-next-line max-len
429
+ 'ext-smaller': 'Property $(PROP) can only be extended, but extended value $(LITERAL) is smaller than $(NUMBER) from previous type extension',
430
+ prop: 'Type property $(PROP) can\'t be extended',
431
+ scale: 'If property $(PROP) is increased, then so must $(OTHERPROP)',
432
+ string: 'Only numerical properties can be extended, but found string for $(PROP)',
433
+ },
434
+ 'ref-expected-scalar-type': {
435
+ std: 'Only scalar type definitions can be extended with type properties',
436
+ unsupported: 'Only integer-, decimal-, binary-, and string-types can be extended but found $(PROP)',
437
+ inferred: 'Only direct types can be extended',
438
+ },
439
+
412
440
  'query-unexpected-assoc-hdbcds': 'Publishing a managed association in a view is not possible for “hdbcds” naming mode',
413
441
  'query-unexpected-structure-hdbcds': 'Publishing a structured element in a view is not possible for “hdbcds” naming mode',
414
442
  'query-ignoring-param-nullability': {
@@ -477,9 +505,10 @@ const centralMessageTexts = {
477
505
  },
478
506
  'odata-navigation': {
479
507
  std: 'No OData navigation property generated, target $(TARGET) is outside of service $(SERVICE)',
480
- oncond: 'No OData navigation property generated for association with arbitrary ON condition and target $(TARGET) outside of service $(SERVICE)'
508
+ oncond: 'No OData navigation property generated for association with arbitrary ON-condition and target $(TARGET) outside of service $(SERVICE)'
481
509
  },
482
510
  'odata-parameter-order': 'Unexpected mandatory after optional parameter',
511
+ 'odata-key-recursive': 'Unexpected recursive key $(NAME)',
483
512
  }
484
513
 
485
514
  /**
@@ -136,14 +136,11 @@ class CompileMessage {
136
136
  this.location = location;
137
137
  this.$location = { ...this.location, address: undefined };
138
138
  this.validNames = null;
139
- if (home) // semantic location, e.g. 'entity:"E"/element:"x"'
140
- this.home = home;
139
+ this.home = home; // semantic location, e.g. 'entity:"E"/element:"x"'
141
140
  this.severity = severity;
142
- if (id)
143
- Object.defineProperty( this, 'messageId', { value: id } );
144
- // this.messageId = id; // ids not yet finalized
145
- if (moduleName)
146
- Object.defineProperty( this, '$module', { value: moduleName, configurable: true } );
141
+ Object.defineProperty( this, 'messageId', { value: id } );
142
+ // this.messageId = id; // ids not yet finalized
143
+ Object.defineProperty( this, '$module', { value: moduleName, configurable: true } );
147
144
  }
148
145
 
149
146
  toString() { // should have no argument...
@@ -676,6 +673,7 @@ const paramsTransform = {
676
673
  elemref: transformElementRef,
677
674
  type: transformArg,
678
675
  offending: tokenSymbol,
676
+ op: quote.prop,
679
677
  expecting: transformManyWith( tokenSymbol ),
680
678
  // msg: m => m,
681
679
  $reviewed: ignoreTextTransform,
@@ -801,6 +799,7 @@ function messageText( texts, params, transform ) {
801
799
  }
802
800
 
803
801
  function replaceInString( text, params ) {
802
+ const usedParams = [ '#', '$reviewed' ];
804
803
  let pattern = /\$\(([A-Z_]+)\)/g;
805
804
  let parts = [];
806
805
  let start = 0;
@@ -808,11 +807,11 @@ function replaceInString( text, params ) {
808
807
  let prop = p[1].toLowerCase();
809
808
  parts.push( text.substring( start, p.index ),
810
809
  (prop in params ? params[prop] : p[0]) );
811
- delete params[prop];
810
+ usedParams.push(prop);
812
811
  start = pattern.lastIndex;
813
812
  }
814
813
  parts.push( text.substring( start ) );
815
- let remain = (params['#']) ? [] : Object.keys( params ).filter( n => params[n] );
814
+ let remain = (params['#']) ? [] : Object.keys( params ).filter( n => !usedParams.includes(n) );
816
815
  return (remain.length)
817
816
  ? parts.join('') + '; ' +
818
817
  remain.map( n => n.toUpperCase() + ' = ' + params[n] ).join(', ')
@@ -1024,6 +1023,7 @@ function compareMessage( a, b ) {
1024
1023
  c( aEnd.endLine, bEnd.endLine ) ||
1025
1024
  c( aEnd.endCol, bEnd.endCol ) ||
1026
1025
  c( homeSortName( a ), homeSortName( b ) ) ||
1026
+ // TODO: severities?
1027
1027
  c( a.message, b.message ) );
1028
1028
  }
1029
1029
  else if (!aFile && !bFile)
@@ -1172,7 +1172,9 @@ function homeNameForExtend( art ) {
1172
1172
 
1173
1173
  // Surrounding parent may be another extension.
1174
1174
  const parent = art._parent;
1175
- if (!parent)
1175
+ if (!parent && art.name.absolute)
1176
+ return kind + ':' + artName(removeBlock(art));
1177
+ else if (!parent)
1176
1178
  return kind + ':' + quoted(absoluteName);
1177
1179
 
1178
1180
  if (art.name.param && parent.params) {
@@ -1199,6 +1201,14 @@ function homeNameForExtend( art ) {
1199
1201
  }
1200
1202
  // This case should not happen, but just in case
1201
1203
  return kind + ':' + artName(parent);
1204
+
1205
+ /**
1206
+ * Remove `select` from the 'art's name to avoid `block:1` in artName().
1207
+ * @TODO: Refactor homeNameForExtend (and possibly artName) to get rid of this function
1208
+ **/
1209
+ function removeBlock(obj) {
1210
+ return { ...obj, name: { ...obj.name, select: null } };
1211
+ }
1202
1212
  }
1203
1213
 
1204
1214
  function constructSemanticLocationFromCsnPath(csnPath, model) {
package/lib/base/model.js CHANGED
@@ -26,8 +26,8 @@ const availableBetaFlags = {
26
26
  hanaAssocRealCardinality: true,
27
27
  mapAssocToJoinCardinality: true,
28
28
  ignoreAssocPublishingInUnion: true,
29
- nestedProjections: true,
30
29
  enableUniversalCsn: true,
30
+ postgres: true,
31
31
  // disabled by --beta-mode
32
32
  nestedServices: false,
33
33
  odataOpenType: true,
@@ -22,7 +22,7 @@ function checkActionOrFunction(art, artName, prop, path) {
22
22
 
23
23
  const serviceName = this.csnUtils.getServiceName(artName);
24
24
  if (!serviceName)
25
- this.warning(null, path, `Functions and actions must be declared in a service`);
25
+ this.warning(null, path, {}, `Functions and actions must be declared in a service`);
26
26
 
27
27
  if (art.kind === 'entity') {
28
28
  for (const [ actName, act ] of Object.entries(art.actions)) {
@@ -36,7 +36,7 @@ function checkCoreMediaTypeAllowence(member) {
36
36
  */
37
37
  function checkAnalytics(member) {
38
38
  if (member['@Analytics.Measure'] && !member['@Aggregation.default']) {
39
- this.info(null, member.$path,
39
+ this.info(null, member.$path, {},
40
40
  'Annotation “@Analytics.Measure” expects “@Aggregation.default” to be assigned for the same element as well');
41
41
  }
42
42
  }
@@ -63,7 +63,7 @@ function checkReadOnlyAndInsertOnly(artifact, artifactName) {
63
63
  if (!this.csnUtils.getServiceName(artifactName))
64
64
  return;
65
65
  if (artifact.kind === 'entity' && artifact['@readonly'] && artifact['@insertonly'])
66
- this.warning(null, artifact.$path, 'Annotations “@readonly” and “@insertonly” can\'t be assigned in combination');
66
+ this.warning(null, artifact.$path, {}, 'Annotations “@readonly” and “@insertonly” can\'t be assigned in combination');
67
67
  }
68
68
 
69
69
  module.exports = {
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const { setProp } = require('../base/model');
4
+
3
5
  // Only to be used with validator.js - a correct `this` value needs to be provided!
4
6
 
5
7
  /**
@@ -24,20 +26,26 @@ function validateAssociationsInItems(member) {
24
26
  if (element.on) { // Unmanaged association
25
27
  // Unmanaged associations are always forbidden for now
26
28
  // TODO: Check if the on-condition only references things inside of the .items
27
- this.error(null, member.$path, 'Unmanaged associations in "array of" or "many" are not allowed');
29
+ this.error(null, member.$path, {}, 'Unmanaged associations in "array of" or "many" are not allowed');
28
30
  }
29
31
  }
30
32
  }
31
33
  }
32
34
  };
33
35
  if (this.artifact && ( this.artifact.kind === 'entity' || this.artifact.query ) && member && member.items && member.$path[2] === 'elements') {
34
- if (member.items.type && member.items.type.ref)
35
- validate(this.artifactRef(member.items.type));
36
-
37
- else if (member.items.type)
38
- validate(this.csn.definitions[member.items.type]);
39
- else
36
+ if (member.items.type) {
37
+ const type = member.items.type.ref
38
+ ? this.artifactRef(member.items.type)
39
+ : this.csn.definitions[member.items.type];
40
+ if (type && !type.$visited) {
41
+ setProp(type, '$visited', true);
42
+ validate(type);
43
+ delete type.$visited;
44
+ }
45
+ }
46
+ else {
40
47
  validate(member.items);
48
+ }
41
49
  }
42
50
  }
43
51
 
@@ -17,7 +17,7 @@ function validateCdsPersistenceAnnotation(artifact, artifactName, prop, path) {
17
17
  // TODO: Why not filter over persistenceAnnos, is shorter!
18
18
  const TableUdfCv = Object.keys(artifact).filter(p => persistenceAnnos.includes(p) && artifact[p]);
19
19
  if (TableUdfCv.length > 1)
20
- this.error(null, path, `Annotations ${ TableUdfCv.join(', ') } can't be used in combination`);
20
+ this.error(null, path, {}, `Annotations ${ TableUdfCv.join(', ') } can't be used in combination`);
21
21
  }
22
22
  }
23
23