@sap/cds-compiler 3.4.2 → 3.5.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 (143) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +1 -0
  3. package/bin/cds_update_identifiers.js +5 -5
  4. package/bin/cdsc.js +15 -16
  5. package/bin/cdshi.js +19 -6
  6. package/doc/CHANGELOG_ARCHIVE.md +2 -2
  7. package/doc/CHANGELOG_BETA.md +9 -1
  8. package/doc/CHANGELOG_DEPRECATED.md +2 -0
  9. package/lib/api/main.js +61 -59
  10. package/lib/api/options.js +4 -2
  11. package/lib/api/validate.js +2 -2
  12. package/lib/base/cleanSymbols.js +2 -3
  13. package/lib/base/dictionaries.js +6 -6
  14. package/lib/base/error.js +2 -2
  15. package/lib/base/keywords.js +6 -6
  16. package/lib/base/location.js +11 -12
  17. package/lib/base/message-registry.js +177 -58
  18. package/lib/base/messages.js +252 -180
  19. package/lib/base/model.js +14 -11
  20. package/lib/base/node-helpers.js +9 -10
  21. package/lib/base/optionProcessorHelper.js +138 -129
  22. package/lib/checks/.eslintrc.json +2 -0
  23. package/lib/checks/actionsFunctions.js +5 -5
  24. package/lib/checks/annotationsOData.js +4 -4
  25. package/lib/checks/arrayOfs.js +1 -1
  26. package/lib/checks/cdsPersistence.js +1 -1
  27. package/lib/checks/checkForTypes.js +3 -3
  28. package/lib/checks/defaultValues.js +3 -3
  29. package/lib/checks/elements.js +7 -7
  30. package/lib/checks/emptyOrOnlyVirtual.js +2 -2
  31. package/lib/checks/foreignKeys.js +1 -1
  32. package/lib/checks/invalidTarget.js +4 -4
  33. package/lib/checks/managedInType.js +1 -1
  34. package/lib/checks/managedWithoutKeys.js +1 -1
  35. package/lib/checks/nonexpandableStructured.js +5 -3
  36. package/lib/checks/nullableKeys.js +1 -1
  37. package/lib/checks/onConditions.js +5 -6
  38. package/lib/checks/parameters.js +1 -1
  39. package/lib/checks/queryNoDbArtifacts.js +2 -2
  40. package/lib/checks/selectItems.js +4 -4
  41. package/lib/checks/sql-snippets.js +4 -4
  42. package/lib/checks/types.js +7 -7
  43. package/lib/checks/utils.js +4 -4
  44. package/lib/checks/validator.js +16 -13
  45. package/lib/compiler/.eslintrc.json +4 -1
  46. package/lib/compiler/assert-consistency.js +8 -7
  47. package/lib/compiler/builtins.js +14 -14
  48. package/lib/compiler/checks.js +123 -48
  49. package/lib/compiler/define.js +12 -13
  50. package/lib/compiler/extend.js +266 -60
  51. package/lib/compiler/finalize-parse-cdl.js +10 -5
  52. package/lib/compiler/index.js +17 -14
  53. package/lib/compiler/populate.js +14 -6
  54. package/lib/compiler/propagator.js +2 -0
  55. package/lib/compiler/resolve.js +2 -15
  56. package/lib/compiler/shared.js +27 -16
  57. package/lib/compiler/tweak-assocs.js +5 -6
  58. package/lib/compiler/utils.js +20 -0
  59. package/lib/edm/annotations/genericTranslation.js +604 -358
  60. package/lib/edm/annotations/preprocessAnnotations.js +39 -35
  61. package/lib/edm/csn2edm.js +275 -222
  62. package/lib/edm/edm.js +17 -3
  63. package/lib/edm/edmAnnoPreprocessor.js +6 -6
  64. package/lib/edm/edmInboundChecks.js +2 -2
  65. package/lib/edm/edmPreprocessor.js +107 -77
  66. package/lib/edm/edmUtils.js +44 -5
  67. package/lib/gen/Dictionary.json +210 -8
  68. package/lib/gen/language.checksum +1 -1
  69. package/lib/gen/language.interp +67 -63
  70. package/lib/gen/language.tokens +81 -81
  71. package/lib/gen/languageLexer.interp +4 -10
  72. package/lib/gen/languageLexer.js +854 -869
  73. package/lib/gen/languageLexer.tokens +79 -81
  74. package/lib/gen/languageParser.js +14309 -13832
  75. package/lib/inspect/inspectModelStatistics.js +2 -2
  76. package/lib/inspect/inspectPropagation.js +6 -6
  77. package/lib/inspect/inspectUtils.js +2 -2
  78. package/lib/json/from-csn.js +102 -55
  79. package/lib/json/to-csn.js +119 -198
  80. package/lib/language/antlrParser.js +5 -2
  81. package/lib/language/docCommentParser.js +6 -6
  82. package/lib/language/errorStrategy.js +43 -23
  83. package/lib/language/genericAntlrParser.js +113 -133
  84. package/lib/language/language.g4 +1550 -1506
  85. package/lib/language/multiLineStringParser.js +3 -3
  86. package/lib/language/textUtils.js +2 -2
  87. package/lib/main.js +3 -3
  88. package/lib/model/csnRefs.js +5 -0
  89. package/lib/model/csnUtils.js +130 -122
  90. package/lib/model/revealInternalProperties.js +1 -1
  91. package/lib/model/sortViews.js +4 -6
  92. package/lib/modelCompare/compare.js +2 -2
  93. package/lib/modelCompare/utils/.eslintrc.json +22 -0
  94. package/lib/modelCompare/utils/filter.js +100 -0
  95. package/lib/optionProcessor.js +5 -0
  96. package/lib/render/.eslintrc.json +1 -0
  97. package/lib/render/DuplicateChecker.js +1 -1
  98. package/lib/render/manageConstraints.js +12 -12
  99. package/lib/render/toCdl.js +311 -276
  100. package/lib/render/toHdbcds.js +97 -94
  101. package/lib/render/toRename.js +5 -5
  102. package/lib/render/toSql.js +127 -223
  103. package/lib/render/utils/common.js +141 -108
  104. package/lib/render/utils/delta.js +227 -0
  105. package/lib/render/utils/sql.js +22 -6
  106. package/lib/render/utils/stringEscapes.js +3 -3
  107. package/lib/transform/db/.eslintrc.json +2 -0
  108. package/lib/transform/db/applyTransformations.js +3 -3
  109. package/lib/transform/db/assertUnique.js +13 -12
  110. package/lib/transform/db/associations.js +5 -5
  111. package/lib/transform/db/cdsPersistence.js +10 -8
  112. package/lib/transform/db/constraints.js +14 -14
  113. package/lib/transform/db/expansion.js +20 -22
  114. package/lib/transform/db/flattening.js +24 -42
  115. package/lib/transform/db/groupByOrderBy.js +3 -3
  116. package/lib/transform/db/temporal.js +6 -6
  117. package/lib/transform/db/transformExists.js +23 -23
  118. package/lib/transform/db/views.js +16 -16
  119. package/lib/transform/draft/.eslintrc.json +1 -35
  120. package/lib/transform/draft/db.js +10 -10
  121. package/lib/transform/draft/odata.js +2 -2
  122. package/lib/transform/forOdataNew.js +8 -29
  123. package/lib/transform/forRelationalDB.js +16 -6
  124. package/lib/transform/localized.js +11 -10
  125. package/lib/transform/odata/toFinalBaseType.js +41 -27
  126. package/lib/transform/odata/typesExposure.js +113 -47
  127. package/lib/transform/parseExpr.js +209 -106
  128. package/lib/transform/transformUtilsNew.js +17 -10
  129. package/lib/transform/translateAssocsToJoins.js +24 -19
  130. package/lib/transform/universalCsn/coreComputed.js +10 -10
  131. package/lib/transform/universalCsn/universalCsnEnricher.js +26 -26
  132. package/lib/transform/universalCsn/utils.js +3 -3
  133. package/lib/utils/file.js +5 -5
  134. package/lib/utils/moduleResolve.js +13 -13
  135. package/lib/utils/objectUtils.js +6 -6
  136. package/lib/utils/term.js +5 -2
  137. package/lib/utils/timetrace.js +51 -24
  138. package/package.json +5 -8
  139. package/share/messages/check-proper-type-of.md +1 -1
  140. package/share/messages/message-explanations.json +1 -1
  141. package/share/messages/redirected-to-complex.md +4 -4
  142. package/share/messages/{syntax-expecting-integer.md → syntax-expecting-unsigned-int.md} +7 -4
  143. package/lib/modelCompare/filter.js +0 -83
@@ -10,12 +10,12 @@ const { forEachDefinition } = require('../../model/csnUtils.js');
10
10
  * options:
11
11
  * v
12
12
  *
13
- * This module never produces errors. In case of "unexpected" situations we issue a warning and
13
+ * This module never produces errors. In case of "unexpected" situations we issue a message and
14
14
  * try to proceed with the processing as good as possible.
15
15
  *
16
16
  */
17
17
  function preprocessAnnotations(csn, serviceName, options) {
18
- const { warning } = makeMessageFunction(csn, options);
18
+ const { message } = makeMessageFunction(csn, options);
19
19
  let fkSeparator = '_';
20
20
 
21
21
  resolveShortcuts();
@@ -32,7 +32,7 @@ function preprocessAnnotations(csn, serviceName, options) {
32
32
  }
33
33
 
34
34
  // return value can be null is target has no key
35
- function getKeyOfTargetOfManagedAssoc(assoc) {
35
+ function getKeyOfTargetOfManagedAssoc(anno, assoc) {
36
36
  // assoc.target can be the name of the target or the object itself
37
37
  let targetName = (typeof assoc.target === 'object') ? assoc.target.name : assoc.target;
38
38
  let target = (typeof assoc.target === 'object') ? assoc.target : csn.definitions[assoc.target];
@@ -40,10 +40,11 @@ function preprocessAnnotations(csn, serviceName, options) {
40
40
  let keyNames = Object.keys(target.elements).filter(x => target.elements[x].key && !target.elements[x].target);
41
41
  if (keyNames.length === 0) {
42
42
  keyNames.push('MISSING');
43
- warning(null, null, `in annotation preprocessing: target ${targetName} has no key`);
43
+ message('odata-anno-preproc', null, { anno, name: targetName, '#': 'nokey' },
44
+ 'target $(NAME) has no key');
44
45
  }
45
46
  else if (keyNames.length > 1)
46
- warning(null, null, `in annotation preprocessing: target ${targetName} has multiple key elements`);
47
+ message('odata-anno-preproc', null, { anno, name: targetName, '#': 'multkeys' });
47
48
 
48
49
  return keyNames[0];
49
50
  }
@@ -58,32 +59,29 @@ function preprocessAnnotations(csn, serviceName, options) {
58
59
  let art = null;
59
60
 
60
61
  forEachDefinition(csn, (artifact, artifactName) => {
62
+ const location = [ 'definitions', artifactName ];
61
63
  if(artifactName === serviceName || artifactName.startsWith(serviceName + '.')) {
62
64
  art = artifactName;
63
- handleAnnotations(artifactName, artifact);
65
+ handleAnnotations(artifactName, artifact, location);
64
66
  artifact.elements && Object.entries(artifact.elements).forEach(([elementName, element]) => {
65
- handleAnnotations(elementName, element);
67
+ handleAnnotations(elementName, element, [ ...location, 'elements', elementName ]);
66
68
  });
67
69
  artifact.actions && Object.values(artifact.actions).forEach(action => {
68
70
  action.params && Object.entries(action.params).forEach(([paramName, param]) => {
69
- handleAnnotations(paramName, param);
71
+ handleAnnotations(paramName, param, [ ...location, 'actions', action, 'params', paramName ]);
70
72
  });
71
73
  });
72
74
  }
73
75
  });
74
76
 
75
- function handleAnnotations(carrierName, carrier) {
77
+ function handleAnnotations(carrierName, carrier, location) {
76
78
 
77
79
  // collect the names of the carrier's annotation properties
78
- let annoNames = Object.keys(carrier).filter( x => x.substr(0,1) === '@')
80
+ let annoNames = Object.keys(carrier).filter( x => x[0] === '@')
79
81
 
80
82
  for (let aName of annoNames) {
81
83
  let aNameWithoutQualifier = aName.split('#')[0];
82
84
 
83
- //for warning messages
84
- let ctx = 'target: ' + art + '/' + carrierName;
85
-
86
-
87
85
  // Always - draft annotations, value is action name
88
86
  // - v2: prefix with entity name
89
87
  // - prefix with service name
@@ -91,11 +89,11 @@ function preprocessAnnotations(csn, serviceName, options) {
91
89
 
92
90
  // Always - FixedValueListShortcut
93
91
  // expand shortcut form of ValueList annotation
94
- fixedValueListShortCut(carrier, aNameWithoutQualifier, ctx);
92
+ fixedValueListShortCut(carrier, aNameWithoutQualifier);
95
93
 
96
94
  // Always - TextArrangementReordering
97
95
  // convert @Common.TextArrangement annotation that is on same level as Text annotation into a nested annotation
98
- textArrangementReordering(carrier, aName, aNameWithoutQualifier, ctx);
96
+ textArrangementReordering(carrier, aName, aNameWithoutQualifier);
99
97
  }
100
98
 
101
99
  // inner functions
@@ -121,9 +119,9 @@ function preprocessAnnotations(csn, serviceName, options) {
121
119
  }
122
120
  }
123
121
 
124
- function fixedValueListShortCut(carrier, aNameWithoutQualifier, ctx) {
125
- if (aNameWithoutQualifier === '@Common.ValueList.entity' ||
126
- aNameWithoutQualifier === '@Common.ValueList.viaAssociation') {
122
+ function fixedValueListShortCut(carrier, anno) {
123
+ if (anno === '@Common.ValueList.entity' ||
124
+ anno === '@Common.ValueList.viaAssociation') {
127
125
 
128
126
  const _fixedValueListShortCut = () => {
129
127
  // note: we loop over all annotations that were originally present, even if they are
@@ -136,7 +134,7 @@ function preprocessAnnotations(csn, serviceName, options) {
136
134
  }
137
135
 
138
136
  if (carrier.kind === 'entity') {
139
- warning(null, null, `annotation preprocessing/${aNameWithoutQualifier}: annotation must not be used for an entity, ${ctx}`);
137
+ message('odata-anno-preproc', [...location, anno], { anno, '#': 'notforentity' });
140
138
  return false;
141
139
  }
142
140
 
@@ -146,32 +144,37 @@ function preprocessAnnotations(csn, serviceName, options) {
146
144
  let enameShort = null; // (string) name of value list entity, short (i.e. name within service)
147
145
  let enameFull = null; // (string) name of value list entity, fully qualified name
148
146
 
149
- if (aNameWithoutQualifier === '@Common.ValueList.viaAssociation') {
147
+ if (anno === '@Common.ValueList.viaAssociation') {
150
148
  // value is expected to be an expression, namely the path to an association of the carrier entity
151
149
  let assocName = carrier['@Common.ValueList.viaAssociation']['='];
152
150
  if (!assocName) {
153
- warning(null, null, `in annotation preprocessing/${aNameWithoutQualifier}: value of 'viaAssociation' must be a path, ${ctx}`);
151
+ message('odata-anno-preproc', [...location, anno], { anno, '#': 'viaassoc' });
154
152
  return false;
155
153
  }
156
154
  let assoc = csn.definitions[art].elements[assocName];
157
155
  if (!assoc || !assoc.target) {
158
- warning(null, null, `in annotation preprocessing/${aNameWithoutQualifier}: there is no association "${assocName}", ${ctx}`);
156
+ message('odata-anno-preproc', [...location, anno], { anno, id: assocName, '#': 'noassoc' });
159
157
  return false;
160
158
  }
161
159
 
162
160
  enameFull = assoc.target.name || assoc.target; // full name
163
161
  enameShort = enameFull.split('.').pop();
164
162
  }
165
- else if (aNameWithoutQualifier === '@Common.ValueList.entity') {
163
+ else if (anno === '@Common.ValueList.entity') {
166
164
  // if both annotations are present, ignore 'entity' and raise a message
167
165
  if (annoNames.map(x=>x.split('#')[0]).find(x=>(x==='@Common.ValueList.viaAssociation'))) {
168
- warning(null, null, `in annotation preprocessing/@Common.ValueList: 'entity' is ignored, as 'viaAssociation' is present, ${ctx}`);
166
+ message('odata-anno-preproc', [...location, anno],
167
+ {
168
+ name: '@Common.ValueList.entity', anno: '@Common.ValueList',
169
+ value: 'entity', code: 'viaAssociation', '#': 'vallistignored'
170
+ });
169
171
  return false;
170
172
  }
171
173
 
172
174
  let annoVal = carrier['@Common.ValueList.entity']; // name of value list entity
173
175
  if (annoVal['=']) {
174
- warning(null, null, `in annotation preprocessing/${aNameWithoutQualifier}: annotation value must be a string, ${ctx}`);
176
+ message('odata-anno-preproc', [...location, anno], { anno, '#': 'notastring' },
177
+ );
175
178
  }
176
179
 
177
180
  let nameprefix = art.replace(/.[^.]+$/, ''); // better way of getting the service name?
@@ -182,7 +185,7 @@ function preprocessAnnotations(csn, serviceName, options) {
182
185
 
183
186
  let vlEntity = csn.definitions[enameFull]; // (object) value list entity
184
187
  if (!vlEntity) {
185
- warning(null, null, `in annotation preprocessing/${aNameWithoutQualifier}: entity "${enameFull}" does not exist, ${ctx}`);
188
+ message('odata-anno-preproc', [...location, anno ], { anno, id: enameFull, '#': 'notexist' });
186
189
  return false;
187
190
  }
188
191
 
@@ -196,7 +199,8 @@ function preprocessAnnotations(csn, serviceName, options) {
196
199
  // if this is a managed assoc, use fk field instead (if there is a single one)
197
200
  let localDataProp = carrierName.split('/').pop();
198
201
  if (carrier.target && carrier.on === undefined) {
199
- localDataProp = localDataProp + fkSeparator + getKeyOfTargetOfManagedAssoc(carrier);
202
+ localDataProp = localDataProp + fkSeparator +
203
+ getKeyOfTargetOfManagedAssoc(anno, carrier);
200
204
  }
201
205
 
202
206
  // if this carrier is a generated foreign key field and the association is marked @cds.api.ignore
@@ -209,15 +213,15 @@ function preprocessAnnotations(csn, serviceName, options) {
209
213
  }
210
214
 
211
215
  // valueListProp: the (single) key field of the value list entity
212
- // if no key or multiple keys -> warning
216
+ // if no key or multiple keys -> message
213
217
  let valueListProp = null;
214
218
  let keys = Object.keys(vlEntity.elements).filter( x => vlEntity.elements[x].key && !vlEntity.elements[x].target );
215
219
  if (keys.length === 0) {
216
- warning(null, null, `in annotation preprocessing/value help shortcut: entity "${enameFull}" has no key, ${ctx}`);
220
+ message('odata-anno-preproc', [...location, anno], { anno, name: enameFull, '#': 'vhlnokey' });
217
221
  return false;
218
222
  }
219
223
  else if (keys.length > 1)
220
- warning(null, null, `in annotation preprocessing/value help shortcut: entity "${enameFull}" has more than one key, ${ctx}`);
224
+ message('odata-anno-preproc', [...location, anno], { anno, name: enameFull, '#': 'vhlmultkeys' });
221
225
  valueListProp = keys[0];
222
226
 
223
227
  // textField:
@@ -278,20 +282,20 @@ function preprocessAnnotations(csn, serviceName, options) {
278
282
 
279
283
  const success = _fixedValueListShortCut();
280
284
  if (!success) {
281
- // In case of failure, avoid subsequent warnings
282
- delete carrier[aNameWithoutQualifier];
285
+ // In case of failure, avoid subsequent messages
286
+ delete carrier[anno];
283
287
  delete carrier['@Common.ValueList.type'];
284
288
  }
285
289
  }
286
290
  }
287
291
 
288
- function textArrangementReordering(carrier, aName, aNameWithoutQualifier, ctx) {
292
+ function textArrangementReordering(carrier, aName, aNameWithoutQualifier) {
289
293
  if (aNameWithoutQualifier === '@Common.TextArrangement') {
290
294
  let value = carrier[aName];
291
295
  let textAnno = carrier['@Common.Text'];
292
296
  // can only occur if there is a @Common.Text annotation at the same target
293
297
  if (!textAnno) {
294
- warning(null, null, `in annotation preprocessing: TextArrangement shortcut without Text annotation, ${ctx}`);
298
+ message('odata-anno-preproc', [...location, '@Common.TextArrangement'], { anno: '@Common.TextArrangement', name: '@Common.Text', '#': 'txtarr' });
295
299
  }
296
300
 
297
301
  //change the scalar anno into a "pseudo-structured" one