@sap/cds-compiler 3.7.2 → 3.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 (70) hide show
  1. package/CHANGELOG.md +63 -4
  2. package/bin/cdsc.js +3 -0
  3. package/doc/CHANGELOG_ARCHIVE.md +6 -6
  4. package/doc/CHANGELOG_BETA.md +15 -0
  5. package/doc/DeprecatedOptions_v2.md +1 -1
  6. package/doc/NameResolution.md +1 -1
  7. package/lib/api/main.js +61 -22
  8. package/lib/api/options.js +1 -0
  9. package/lib/api/validate.js +5 -0
  10. package/lib/base/dictionaries.js +5 -3
  11. package/lib/base/keywords.js +2 -0
  12. package/lib/base/message-registry.js +64 -22
  13. package/lib/base/messages.js +12 -7
  14. package/lib/base/model.js +3 -2
  15. package/lib/checks/arrayOfs.js +1 -1
  16. package/lib/checks/defaultValues.js +1 -1
  17. package/lib/checks/hasPersistedElements.js +1 -1
  18. package/lib/checks/invalidTarget.js +1 -1
  19. package/lib/checks/onConditions.js +9 -6
  20. package/lib/checks/sql-snippets.js +2 -2
  21. package/lib/checks/types.js +1 -2
  22. package/lib/compiler/assert-consistency.js +24 -5
  23. package/lib/compiler/base.js +49 -2
  24. package/lib/compiler/builtins.js +15 -6
  25. package/lib/compiler/checks.js +4 -4
  26. package/lib/compiler/define.js +59 -80
  27. package/lib/compiler/extend.js +701 -498
  28. package/lib/compiler/finalize-parse-cdl.js +4 -3
  29. package/lib/compiler/index.js +1 -1
  30. package/lib/compiler/kick-start.js +2 -2
  31. package/lib/compiler/populate.js +17 -9
  32. package/lib/compiler/propagator.js +12 -5
  33. package/lib/compiler/resolve.js +26 -173
  34. package/lib/compiler/shared.js +12 -53
  35. package/lib/compiler/tweak-assocs.js +1 -1
  36. package/lib/compiler/utils.js +2 -2
  37. package/lib/edm/annotations/genericTranslation.js +124 -46
  38. package/lib/edm/csn2edm.js +22 -1
  39. package/lib/edm/edmPreprocessor.js +41 -21
  40. package/lib/gen/Dictionary.json +4 -0
  41. package/lib/gen/language.checksum +1 -1
  42. package/lib/gen/language.interp +3 -1
  43. package/lib/gen/languageLexer.js +1 -1
  44. package/lib/gen/languageParser.js +4810 -4482
  45. package/lib/inspect/inspectPropagation.js +20 -36
  46. package/lib/json/from-csn.js +55 -5
  47. package/lib/json/to-csn.js +71 -110
  48. package/lib/language/errorStrategy.js +1 -0
  49. package/lib/language/genericAntlrParser.js +47 -8
  50. package/lib/language/language.g4 +88 -62
  51. package/lib/language/textUtils.js +13 -0
  52. package/lib/main.d.ts +43 -3
  53. package/lib/main.js +4 -2
  54. package/lib/model/csnRefs.js +14 -2
  55. package/lib/model/csnUtils.js +11 -74
  56. package/lib/model/revealInternalProperties.js +3 -0
  57. package/lib/optionProcessor.js +3 -0
  58. package/lib/render/toCdl.js +203 -104
  59. package/lib/render/toHdbcds.js +0 -1
  60. package/lib/render/toRename.js +14 -51
  61. package/lib/transform/braceExpression.js +6 -0
  62. package/lib/transform/db/rewriteCalculatedElements.js +55 -14
  63. package/lib/transform/forOdataNew.js +20 -15
  64. package/lib/transform/forRelationalDB.js +21 -14
  65. package/lib/transform/parseExpr.js +2 -0
  66. package/lib/transform/transformUtilsNew.js +36 -9
  67. package/lib/transform/translateAssocsToJoins.js +11 -4
  68. package/lib/transform/universalCsn/coreComputed.js +15 -7
  69. package/lib/transform/universalCsn/universalCsnEnricher.js +4 -4
  70. package/package.json +2 -1
@@ -63,7 +63,6 @@ function getUtils( model, universalReady ) {
63
63
  addStringAnnotationTo,
64
64
  getServiceName,
65
65
  hasAnnotationValue,
66
- cloneWithTransformations,
67
66
  getFinalBaseTypeWithProps,
68
67
  get$combined,
69
68
  getQueryPrimarySource,
@@ -81,7 +80,7 @@ function getUtils( model, universalReady ) {
81
80
  }
82
81
 
83
82
  /**
84
- * Get the union of all elements from the from clause
83
+ * Get the union of all elements from the "from" clause
85
84
  * - descend into unions, following the lead query
86
85
  * - merge all queries in case of joins
87
86
  * - follow subqueries
@@ -93,7 +92,7 @@ function getUtils( model, universalReady ) {
93
92
  function getSources( query, isSubquery = false ) {
94
93
  // Remark CW: better just a while along query.SET.args[0]
95
94
  if (query.SET) {
96
- if (query.SET.args[0].SELECT && query.SET.args[0].SELECT.elements)
95
+ if (query.SET.args[0].SELECT?.elements)
97
96
  return mergeElementsIntoMap(Object.create(null), query.SET.args[0].SELECT.elements, query.SET.args[0].$location);
98
97
 
99
98
  return getSources(query.SET.args[0], isSubquery);
@@ -111,9 +110,12 @@ function getUtils( model, universalReady ) {
111
110
  if (isSubquery && !query.SELECT.elements)
112
111
  throw new ModelError('Expected subquery to have .elements');
113
112
 
114
- return mergeElementsIntoMap(Object.create(null), isSubquery ? query.SELECT.elements : art.elements, art.$location,
115
- query.SELECT.from.as || query.SELECT.from.ref[query.SELECT.from.ref.length - 1],
116
- query.SELECT.from.ref[query.SELECT.from.ref.length - 1] || query.SELECT.from.as );
113
+ const elements = isSubquery ? query.SELECT.elements : art.elements;
114
+ // sub-queries also have an alias that is reachable by outer queries, in contrast to `from.as`.
115
+ const parent = query.as || query.SELECT.from.as || implicitAs(query.SELECT.from.ref);
116
+ // for better error messages, we refer to the actual reference name first
117
+ const errorParent = implicitAs(query.SELECT.from.ref);
118
+ return mergeElementsIntoMap(Object.create(null), elements, art.$location, parent, errorParent);
117
119
  }
118
120
  else if (query.SELECT.from.SET || query.SELECT.from.SELECT) {
119
121
  return getSources(query.SELECT.from, true);
@@ -131,7 +133,7 @@ function getUtils( model, universalReady ) {
131
133
  }
132
134
  else if (arg.ref) {
133
135
  const art = artifactRef(arg);
134
- elements = mergeElementsIntoMap(elements, art.elements, art.$location, arg.as || arg.ref[arg.ref.length - 1], arg.ref[arg.ref.length - 1] || arg.as);
136
+ elements = mergeElementsIntoMap(elements, art.elements, art.$location, arg.as || implicitAs(arg.ref), implicitAs(arg.ref) || arg.as);
135
137
  }
136
138
  else if (arg.SELECT || arg.SET) {
137
139
  elements = mergeElementMaps(elements, getSources(arg));
@@ -176,27 +178,13 @@ function getUtils( model, universalReady ) {
176
178
  existingMap[elementName] = [];
177
179
 
178
180
  existingMap[elementName].push({
179
- element, name: elementName, source: $location, parent: getBaseName(parent), errorParent,
181
+ element, name: elementName, source: $location, parent, errorParent,
180
182
  });
181
183
  }
182
184
 
183
185
  return existingMap;
184
186
  }
185
187
 
186
- /**
187
- * Return the name part of the artifact name - no namespace etc.
188
- * @param {string|object} name Absolute name of the artifact
189
- */
190
- function getBaseName( name ) {
191
- if (!name)
192
- return name;
193
-
194
- if (name.id)
195
- return name.id.substring( name.id.lastIndexOf('.') + 1 );
196
-
197
- return name.substring( name.lastIndexOf('.') + 1 );
198
- }
199
-
200
188
  /**
201
189
  * Return the left-most, primary source of the given query.
202
190
  * @param {*} query Definition's query object
@@ -341,57 +329,6 @@ function getUtils( model, universalReady ) {
341
329
  }
342
330
  }
343
331
 
344
- /**
345
- * Clone 'node', transforming nodes therein recursively. Object 'transformers' is expected
346
- * to contain a mapping of property 'key' names to transformer functions. The node's properties
347
- * are walked recursively, calling each transformer function on its corresponding property
348
- * 'key' of 'node', replacing 'value' in 'resultNode' with the function's return value
349
- * (returning 'undefined' will delete the property).
350
- * If no transformation function is found for 'key', the first letter of 'key' is tried
351
- * instead (this seems to be intended for handling annotations that start with '@' ?)
352
- *
353
- * Regardless of their names, transformers are never applied to dictionary elements.
354
- *
355
- * The transformer functions are called with the following signature:
356
- * transformer(value, node, resultNode, key)
357
- *
358
- * @param {any} rootNode Node to transform
359
- * @param {any} transformers Object defining transformer functions
360
- * @returns {object}
361
- */
362
- function cloneWithTransformations( rootNode, transformers ) {
363
- return transformNode(rootNode);
364
-
365
- // This general transformation function will be applied to each node recursively
366
- function transformNode( node ) {
367
- // Return primitive values and null unchanged, but let objects and dictionaries through
368
- // (Note that 'node instanceof Object' would be false for dictionaries).
369
- if (node === null || typeof node !== 'object')
370
- return node;
371
-
372
- // Simply return if node is to be ignored
373
- if (node === undefined || node._ignore)
374
- return undefined;
375
- // Transform arrays element-wise
376
- if (Array.isArray(node))
377
- return node.map(transformNode);
378
-
379
- // Things not having 'proto' are dictionaries
380
- const proto = Object.getPrototypeOf(node);
381
- // Iterate own properties of 'node' and transform them into 'resultNode'
382
- const resultNode = Object.create(proto);
383
- for (const key of Object.keys(node)) {
384
- // Dictionary always use transformNode(), other objects their transformer according to key
385
- const transformer = (proto === null || proto === undefined) ? transformNode : transformers[key] || transformers[key.charAt(0)];
386
- // Apply transformer, or use transformNode() if there is none
387
- const resultValue = (transformer || transformNode)(node[key], node, resultNode, key);
388
- if (resultValue !== undefined)
389
- resultNode[key] = resultValue;
390
- }
391
- return resultNode;
392
- }
393
- }
394
-
395
332
  /**
396
333
  * Resolve to the final type of a type, that means follow type chains, references, etc.
397
334
  * Input is a fully qualified type name, i.e. string, or type ref, i.e. `{ ref: [...] }`.
@@ -931,7 +868,7 @@ function getUnderscoredName( startIndex, parts, csn ) {
931
868
  for (let i = startIndex; i < parts.length; i++) {
932
869
  const namePart = parts.slice(0, i).join('.');
933
870
  const art = csn.definitions[namePart];
934
- if (art && !(art.kind === 'namespace' || art.kind === 'context' || art.kind === 'service')) {
871
+ if (art && !(art.kind === 'context' || art.kind === 'service')) {
935
872
  const prefix = parts.slice(0, i - 1).join('.');
936
873
  const suffix = parts.slice(i - 1).join('_');
937
874
  const result = [];
@@ -61,6 +61,7 @@ function tableAliasAsLink( art, parent, name ) {
61
61
  * @param {string} [nameOrPath]
62
62
  */
63
63
  function revealInternalProperties( model, nameOrPath ) {
64
+ // return model;
64
65
  const transformers = {
65
66
  messages: m => m,
66
67
  name: shortenName,
@@ -71,6 +72,7 @@ function revealInternalProperties( model, nameOrPath ) {
71
72
  artifacts: artifactDictionary,
72
73
  definitions: artifactDictionary,
73
74
  vocabularies: dictionary,
75
+ $lateExtensions: dictionary,
74
76
  elements,
75
77
  columns,
76
78
  expand: columns,
@@ -95,6 +97,7 @@ function revealInternalProperties( model, nameOrPath ) {
95
97
  $compositionTargets: d => d, // dictionary( boolean )
96
98
  _extend: reveal,
97
99
  _annotate: reveal,
100
+ _annotateS: artifactIdentifier,
98
101
  _deps: dependencyInfo,
99
102
  _status: primOrString, // is a string anyway
100
103
  $annotations: as => as.map( $annotation ),
@@ -226,6 +226,7 @@ optionProcessor.command('O, toOdata')
226
226
  .option(' --odata-x-service-refs')
227
227
  .option(' --odata-foreign-keys')
228
228
  .option(' --odata-v2-partial-constr')
229
+ .option(' --odata-voc-refs <list>')
229
230
  .option('-c, --csn')
230
231
  .option('-f, --odata-format <format>', ['flat', 'structured'])
231
232
  .option('-n, --sql-mapping <style>', ['plain', 'quoted', 'hdbcds'], { aliases: [ '--names' ] })
@@ -254,6 +255,8 @@ optionProcessor.command('O, toOdata')
254
255
  --odata-foreign-keys Render foreign keys in structured format (V4 only)
255
256
  --odata-v2-partial-constr Render referential constraints also for partial principal key tuple
256
257
  (Not spec compliant and V2 only)
258
+ --odata-voc-refs <list> JSON array of adhoc vocabulary definitions
259
+ [ { alias, ns, uri }, ... ]
257
260
  -n, --sql-mapping <style> Annotate artifacts and elements with "@cds.persistence.name", which is
258
261
  the corresponding database name (see "--sql-mapping" for "toHana or "toSql")
259
262
  plain : (default) Names in uppercase and flattened with underscores