@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
@@ -8,7 +8,7 @@
8
8
 
9
9
  const { setProp } = require('../../base/model');
10
10
  const { defNameWithoutServiceOrContextName, isArtifactInService } = require('./utils');
11
- const { cloneCsnNonDict, isBuiltinType, forEachDefinition, forEachMember } = require('../../model/csnUtils');
11
+ const { cloneCsnNonDict, isBuiltinType, forEachDefinition, forEachMember, forEachGeneric } = require('../../model/csnUtils');
12
12
  const { copyAnnotations } = require('../../model/csnUtils');
13
13
  const { isBetaEnabled } = require('../../base/model.js');
14
14
 
@@ -49,6 +49,31 @@ function typesExposure(csn, whatsMyServiceName, requestedServiceNames, fallBackS
49
49
  }
50
50
  });
51
51
 
52
+ if(isBetaEnabled(options, 'odataTerms')) {
53
+ forEachGeneric(csn, 'vocabularies', (def, defName, _propertyName, path) => {
54
+ // we do expose types only for definition from inside services
55
+ const serviceName = whatsMyServiceName(defName, false);
56
+ // run type exposure only on requested services if not in multi schema mode
57
+ // multi schema mode requires a proper type exposure for all services as a prerequisite
58
+ // for the proxy exposure
59
+ if (serviceName && requestedServiceNames.includes(serviceName)) {
60
+ if(csn.definitions[defName]) {
61
+ // error, duplicate definitions not allowed!
62
+ // TODO: Use path as error location as soon as refs outside definitions are supported
63
+ error('odata-definition-exists', ['vocabularies', defName], { anno: defName, '#':'anno' });
64
+ }
65
+ else {
66
+ // link def into definitions for later use
67
+ def.kind = 'annotation';
68
+ csn.definitions[defName] = def;
69
+ const artificialName = `term_${defName.replace(/\./g, '_')}`;//_${paramName}`;
70
+ const newTypeName = getNewTypeName(undefined, undefined, artificialName, serviceName);
71
+ exposeTypeOf(def, false, defName, defName, serviceName, newTypeName, path.concat(['vocabularies', defName]), undefined, true);
72
+ }
73
+ }
74
+ });
75
+ }
76
+
52
77
  return schemas;
53
78
 
54
79
  /**
@@ -82,14 +107,14 @@ function typesExposure(csn, whatsMyServiceName, requestedServiceNames, fallBackS
82
107
  * @param {String} serviceName
83
108
  * @param {String} newTypeName
84
109
  */
85
- function exposeTypeOf(node, isKey, memberName, defName, serviceName, newTypeName, path, parentName) {
86
- const { isExposable, typeDef, typeName, elements, isAnonymous } = isTypeExposable(node);
110
+ function exposeTypeOf(node, isKey, memberName, defName, serviceName, newTypeName, path, parentName, isTermDef=false) {
111
+ const { isExposable, typeDef, typeName, elements, isAnonymous } = isTypeExposable();
87
112
  if (isExposable) {
88
113
  // this is the name used to register the new type in csn.definitions
89
114
  let fullQualifiedNewTypeName =
90
115
  isMultiSchema
91
- ? (node.type || (node.items && node.items.type)
92
- ? getTypeNameInMultiSchema(node.type|| (node.items && node.items.type), serviceName)
116
+ ? (node.type || (node.items?.type)
117
+ ? getTypeNameInMultiSchema(node.type|| (node.items?.type), serviceName)
93
118
  : getAnonymousTypeNameInMultiSchema(newTypeName, parentName || defName))
94
119
  : `${serviceName}.${newTypeName}`;
95
120
 
@@ -100,7 +125,7 @@ function typesExposure(csn, whatsMyServiceName, requestedServiceNames, fallBackS
100
125
  isKey = false;
101
126
  // in case this was a named type and if the openess does not match the type definition
102
127
  // expose the type as a new one not changing the original definition.
103
- if((!!node['@open'] !== !!typeDef['@open']) && isBetaEnabled(options, 'odataOpenType'))
128
+ if(elements && (!!node['@open'] !== !!typeDef['@open']) && isBetaEnabled(options, 'odataOpenType'))
104
129
  fullQualifiedNewTypeName += node['@open'] ? '_open' : '_closed';
105
130
  }
106
131
  // check if that type is already defined
@@ -108,41 +133,73 @@ function typesExposure(csn, whatsMyServiceName, requestedServiceNames, fallBackS
108
133
  if (newType) {
109
134
  // error, if it was not exposed by us
110
135
  if (!exposedTypes[fullQualifiedNewTypeName]) {
136
+ setProp(node, '$NameClashReported', true);
111
137
  error(null, path, { type: fullQualifiedNewTypeName, name: memberName },
112
138
  'Can\'t create artificial type $(TYPE) for $(NAME) because the name is already used');
113
- return;
139
+ return { isExposable, typeDef, typeName, isAnonymous };
114
140
  }
115
141
  }
116
142
  else {
117
143
  /* Expose new structured type
118
144
  * Treat items.elements as ordinary elements for now.
119
145
  */
120
- newType = createNewStructType(elements);
121
- // if using node enforces open/closed, set it on type
122
- if(node['@open'] !== undefined)
123
- newType['@open'] = node['@open']
124
- if (node.$location)
125
- setProp(newType, '$location', node.$location);
146
+ if(elements) {
147
+ newType = createNewStructType(elements);
148
+ // if using node enforces open/closed, set it on type
149
+ if(node['@open'] !== undefined)
150
+ newType['@open'] = node['@open']
151
+ if (node.$location)
152
+ setProp(newType, '$location', node.$location);
126
153
 
127
- csn.definitions[fullQualifiedNewTypeName] = newType;
128
- exposedTypes[fullQualifiedNewTypeName] = 1;
154
+ csn.definitions[fullQualifiedNewTypeName] = newType;
155
+ exposedTypes[fullQualifiedNewTypeName] = 1;
129
156
 
130
- // Recurse into elements of 'type' (if any) and expose them as well (is needed)
131
- newType.elements && Object.entries(newType.elements).forEach(([elemName, newElem]) => {
132
- if (node.elements && node.elements[elemName].$location)
133
- setProp(newElem, '$location', node.elements[elemName].$location);
134
- defName = typeDef.kind === 'type' ? typeName : defName;
135
- exposeTypeOf(newElem, isKey, elemName, defName, serviceName,
136
- getNewTypeName(newElem, elemName, newTypeName, serviceName), path, fullQualifiedNewTypeName);
137
- });
138
- copyAnnotations(typeDef, newType);
139
- // if the origin type had items, add items to exposed type
140
- if(typeDef.kind === 'type') {
141
- if(typeDef.items) {
142
- newType.items = { elements: newType.elements };
143
- delete newType.elements;
157
+ // Recurse into elements of 'type' (if any) and expose them as well (is needed)
158
+ newType.elements && Object.entries(newType.elements).forEach(([elemName, newElem]) => {
159
+ if (node.elements && node.elements[elemName].$location)
160
+ setProp(newElem, '$location', node.elements[elemName].$location);
161
+ defName = typeDef.kind === 'type' ? typeName : defName;
162
+ {
163
+ const { isExposable, typeDef, typeName } = exposeTypeOf(newElem, isKey, elemName, defName, serviceName,
164
+ getNewTypeName(newElem, elemName, newTypeName, serviceName), path, fullQualifiedNewTypeName, isTermDef);
165
+ // if the type for the newElem was not exposed it may be a scalar type def from an external service that hasn't
166
+ // been catched by expandToFinalBaseType() (forODataNew must not modify external imported services)
167
+ if(!isExposable && isBuiltinType(typeName) && !isBuiltinType((newElem.items?.type || newElem.type))) {
168
+ if(typeDef.items) {
169
+ newElem.items = typeDef.items;
170
+ delete newElem.type;
171
+ }
172
+ else if(newElem.items) {
173
+ newElem.items.type = typeName;
174
+ if(typeDef.enum)
175
+ newElem.items.enum = typeDef.enum;
176
+ }
177
+ else {
178
+ newElem.type = typeName;
179
+ if(typeDef.enum)
180
+ newElem.enum = typeDef.enum;
181
+ }
182
+ }
183
+ }
184
+ });
185
+ copyAnnotations(typeDef, newType);
186
+ // if the origin type had items, add items to exposed type
187
+ if(typeDef.kind === 'type') {
188
+ if(typeDef.items) {
189
+ newType.items = { elements: newType.elements };
190
+ delete newType.elements;
191
+ }
144
192
  }
145
193
  }
194
+ else if(isTermDef) {
195
+ newType = Object.create(null);
196
+ for(let n in typeDef) {
197
+ newType[n] = typeDef[n];
198
+ }
199
+ newType.kind = 'type';
200
+ csn.definitions[fullQualifiedNewTypeName] = newType;
201
+ exposedTypes[fullQualifiedNewTypeName] = 1;
202
+ }
146
203
  }
147
204
  // adjust current node to new type
148
205
  if(node.items) {
@@ -155,6 +212,7 @@ function typesExposure(csn, whatsMyServiceName, requestedServiceNames, fallBackS
155
212
  node.type = fullQualifiedNewTypeName;
156
213
  }
157
214
  }
215
+ return { isExposable, typeDef, typeName, isAnonymous };
158
216
 
159
217
  /**
160
218
  * Check if the node's type can be exposed:
@@ -166,38 +224,46 @@ function typesExposure(csn, whatsMyServiceName, requestedServiceNames, fallBackS
166
224
  * - the elements dictionary that needs to be cloned
167
225
  * - the typeDef, either the resolved type def or the node itself
168
226
  * - if structured type was anonymously defined
169
- * @param {object} node
170
227
  * @returns {object} { isExposable, typeDef, typeName, elements, isAnonymous }
171
228
  */
172
- function isTypeExposable(node) {
229
+ function isTypeExposable() {
173
230
  let typeName = undefined;
174
231
  let typeDef = node;
175
- let elements = (node.items && node.items.elements || node.elements)
232
+ let elements = (node.items?.elements || node.elements)
176
233
  // anonymous structured type
177
234
  if(elements)
178
235
  return { isExposable: true, typeDef, typeName, elements, isAnonymous: true };
179
236
  // named type, resolve the type to inspect it
180
- let type = node.items && node.items.type || node.type;
237
+ let type = node.items?.type || node.type;
181
238
  if(type) {
182
239
  typeName = (type.ref && csnUtils.getFinalType(type)) || type;
183
- typeDef = csnUtils.getFinalTypeDef(typeName);
184
240
  const rc = { isExposable: true, typeDef, typeName, isAnonymous: false };
185
- if(!isBuiltinType(typeName) && !isArtifactInService(typeName, serviceName)) {
186
- while(!isBuiltinType(typeName)) {
187
- typeDef = csnUtils.getFinalTypeDef(typeName);
188
- if(typeDef) {
189
- if((rc.elements = (typeDef.items && typeDef.items.elements || typeDef.elements)) !== undefined)
190
- return rc;
191
- type = typeDef.items && typeDef.items.type || typeDef.type;
192
- typeName = (type.ref && csnUtils.getFinalType(type)) || type;
193
- }
194
- else {
195
- throw Error(`Please debug me: ${typeName} not found`);
241
+ if(!isBuiltinType(typeName)) {
242
+ rc.typeDef = typeDef = csnUtils.getFinalTypeDef(typeName);
243
+ if(!isArtifactInService(typeName, serviceName)) {
244
+ while(!isBuiltinType(typeName)) {
245
+ typeDef = csnUtils.getFinalTypeDef(typeName);
246
+ if(typeDef) {
247
+ if((isTermDef && typeDef.enum) || (rc.elements = (typeDef.items?.elements || typeDef.elements)) !== undefined)
248
+ return rc;
249
+ type = typeDef.items?.type || typeDef.type;
250
+ typeName = (type.ref && csnUtils.getFinalType(type)) || type;
251
+ }
252
+ else {
253
+ throw Error(`Please debug me: ${typeName} not found`);
254
+ }
196
255
  }
197
256
  }
257
+ else {
258
+ rc.isExposable = false;
259
+ return rc;
260
+ }
198
261
  }
262
+ // else if(isTermDef && typeDef.enum) {
263
+ // return rc;
264
+ // }
199
265
  }
200
- return { isExposable: false };
266
+ return { isExposable: false, typeDef, typeName, isAnonymous: false };
201
267
  }
202
268
 
203
269
 
@@ -286,7 +352,7 @@ function typesExposure(csn, whatsMyServiceName, requestedServiceNames, fallBackS
286
352
  */
287
353
  function getNewTypeName(element, elementName, typeNamePrefix, serviceName) {
288
354
  // for the new type name node.type has precedence over node.items.type
289
- const typeName = (!element.elements && element.type || element.items && !element.items.elements && element.items.type);
355
+ const typeName = (!element?.elements && element?.type || !element?.items?.elements && element?.items?.type);
290
356
  return typeName
291
357
  ? `${isMultiSchema
292
358
  ? typeName.split('.').pop() // use leaf element