@sap/cds-compiler 3.4.4 → 3.5.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 (129) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +1 -0
  3. package/bin/cds_update_identifiers.js +5 -5
  4. package/bin/cdsc.js +12 -12
  5. package/doc/CHANGELOG_ARCHIVE.md +1 -1
  6. package/doc/CHANGELOG_BETA.md +9 -1
  7. package/doc/CHANGELOG_DEPRECATED.md +2 -0
  8. package/lib/api/main.js +58 -59
  9. package/lib/api/options.js +4 -2
  10. package/lib/api/validate.js +2 -2
  11. package/lib/base/cleanSymbols.js +2 -3
  12. package/lib/base/dictionaries.js +6 -6
  13. package/lib/base/error.js +2 -2
  14. package/lib/base/keywords.js +6 -6
  15. package/lib/base/location.js +11 -12
  16. package/lib/base/message-registry.js +124 -28
  17. package/lib/base/messages.js +247 -179
  18. package/lib/base/model.js +14 -11
  19. package/lib/base/node-helpers.js +9 -10
  20. package/lib/base/optionProcessorHelper.js +138 -129
  21. package/lib/checks/actionsFunctions.js +5 -5
  22. package/lib/checks/annotationsOData.js +4 -4
  23. package/lib/checks/arrayOfs.js +1 -1
  24. package/lib/checks/cdsPersistence.js +1 -1
  25. package/lib/checks/checkForTypes.js +3 -3
  26. package/lib/checks/defaultValues.js +3 -3
  27. package/lib/checks/elements.js +7 -7
  28. package/lib/checks/emptyOrOnlyVirtual.js +2 -2
  29. package/lib/checks/foreignKeys.js +1 -1
  30. package/lib/checks/invalidTarget.js +4 -4
  31. package/lib/checks/managedInType.js +1 -1
  32. package/lib/checks/managedWithoutKeys.js +1 -1
  33. package/lib/checks/nonexpandableStructured.js +5 -3
  34. package/lib/checks/nullableKeys.js +1 -1
  35. package/lib/checks/onConditions.js +5 -6
  36. package/lib/checks/parameters.js +1 -1
  37. package/lib/checks/queryNoDbArtifacts.js +2 -2
  38. package/lib/checks/selectItems.js +4 -4
  39. package/lib/checks/sql-snippets.js +4 -4
  40. package/lib/checks/types.js +7 -7
  41. package/lib/checks/utils.js +4 -4
  42. package/lib/checks/validator.js +16 -13
  43. package/lib/compiler/.eslintrc.json +1 -1
  44. package/lib/compiler/assert-consistency.js +0 -1
  45. package/lib/compiler/builtins.js +1 -1
  46. package/lib/compiler/checks.js +73 -15
  47. package/lib/compiler/define.js +3 -7
  48. package/lib/compiler/extend.js +212 -32
  49. package/lib/compiler/finalize-parse-cdl.js +7 -2
  50. package/lib/compiler/index.js +17 -14
  51. package/lib/compiler/populate.js +2 -5
  52. package/lib/compiler/propagator.js +2 -0
  53. package/lib/compiler/shared.js +23 -12
  54. package/lib/compiler/tweak-assocs.js +5 -6
  55. package/lib/compiler/utils.js +6 -0
  56. package/lib/edm/annotations/genericTranslation.js +553 -319
  57. package/lib/edm/annotations/preprocessAnnotations.js +39 -35
  58. package/lib/edm/csn2edm.js +88 -75
  59. package/lib/edm/edm.js +17 -3
  60. package/lib/edm/edmAnnoPreprocessor.js +5 -5
  61. package/lib/edm/edmPreprocessor.js +106 -76
  62. package/lib/edm/edmUtils.js +41 -2
  63. package/lib/gen/Dictionary.json +34 -0
  64. package/lib/gen/language.checksum +1 -1
  65. package/lib/gen/language.interp +66 -63
  66. package/lib/gen/language.tokens +81 -81
  67. package/lib/gen/languageLexer.interp +4 -10
  68. package/lib/gen/languageLexer.js +854 -869
  69. package/lib/gen/languageLexer.tokens +79 -81
  70. package/lib/gen/languageParser.js +14360 -14146
  71. package/lib/inspect/inspectModelStatistics.js +2 -2
  72. package/lib/inspect/inspectPropagation.js +6 -6
  73. package/lib/inspect/inspectUtils.js +2 -2
  74. package/lib/json/from-csn.js +82 -40
  75. package/lib/json/to-csn.js +82 -157
  76. package/lib/language/.eslintrc.json +1 -4
  77. package/lib/language/genericAntlrParser.js +59 -38
  78. package/lib/language/language.g4 +1508 -1490
  79. package/lib/language/multiLineStringParser.js +1 -1
  80. package/lib/main.js +3 -3
  81. package/lib/model/csnUtils.js +130 -122
  82. package/lib/model/revealInternalProperties.js +1 -1
  83. package/lib/model/sortViews.js +4 -6
  84. package/lib/modelCompare/utils/filter.js +4 -3
  85. package/lib/optionProcessor.js +5 -0
  86. package/lib/render/DuplicateChecker.js +1 -1
  87. package/lib/render/manageConstraints.js +12 -12
  88. package/lib/render/toCdl.js +225 -159
  89. package/lib/render/toHdbcds.js +63 -63
  90. package/lib/render/toRename.js +5 -5
  91. package/lib/render/toSql.js +55 -65
  92. package/lib/render/utils/common.js +20 -37
  93. package/lib/render/utils/delta.js +3 -3
  94. package/lib/render/utils/sql.js +22 -6
  95. package/lib/render/utils/stringEscapes.js +3 -3
  96. package/lib/transform/db/applyTransformations.js +3 -3
  97. package/lib/transform/db/assertUnique.js +13 -12
  98. package/lib/transform/db/associations.js +5 -5
  99. package/lib/transform/db/cdsPersistence.js +10 -8
  100. package/lib/transform/db/constraints.js +14 -14
  101. package/lib/transform/db/expansion.js +20 -22
  102. package/lib/transform/db/flattening.js +24 -42
  103. package/lib/transform/db/groupByOrderBy.js +3 -3
  104. package/lib/transform/db/temporal.js +6 -6
  105. package/lib/transform/db/transformExists.js +23 -23
  106. package/lib/transform/db/views.js +16 -16
  107. package/lib/transform/draft/db.js +10 -10
  108. package/lib/transform/draft/odata.js +2 -2
  109. package/lib/transform/forOdataNew.js +12 -40
  110. package/lib/transform/forRelationalDB.js +17 -7
  111. package/lib/transform/localized.js +2 -2
  112. package/lib/transform/odata/toFinalBaseType.js +41 -27
  113. package/lib/transform/odata/typesExposure.js +106 -62
  114. package/lib/transform/parseExpr.js +209 -106
  115. package/lib/transform/transformUtilsNew.js +2 -2
  116. package/lib/transform/translateAssocsToJoins.js +24 -19
  117. package/lib/transform/universalCsn/coreComputed.js +10 -10
  118. package/lib/transform/universalCsn/universalCsnEnricher.js +26 -26
  119. package/lib/transform/universalCsn/utils.js +3 -3
  120. package/lib/utils/file.js +5 -5
  121. package/lib/utils/moduleResolve.js +13 -13
  122. package/lib/utils/objectUtils.js +6 -6
  123. package/lib/utils/term.js +5 -2
  124. package/lib/utils/timetrace.js +51 -24
  125. package/package.json +5 -7
  126. package/share/messages/check-proper-type-of.md +1 -1
  127. package/share/messages/message-explanations.json +1 -1
  128. package/share/messages/redirected-to-complex.md +4 -4
  129. package/share/messages/{syntax-expecting-integer.md → syntax-expecting-unsigned-int.md} +7 -4
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  const keywords = require('../base/keywords');
4
- const { isBuiltinType, generatedByCompilerVersion, getNormalizedQuery } = require('../model/csnUtils');
5
4
  const { findElement, createExpressionRenderer, withoutCast } = require('./utils/common');
6
5
  const { escapeString, hasUnpairedUnicodeSurrogate } = require('./utils/stringEscapes');
7
6
  const { checkCSNVersion } = require('../json/csnVersion');
@@ -12,6 +11,12 @@ const { isBetaEnabled } = require('../base/model');
12
11
  const { ModelError } = require('../base/error');
13
12
  const { typeParameters, specialFunctions } = require('../compiler/builtins');
14
13
  const { forEach } = require('../utils/objectUtils');
14
+ const {
15
+ isBuiltinType,
16
+ generatedByCompilerVersion,
17
+ getNormalizedQuery,
18
+ cloneCsnNonDict,
19
+ } = require('../model/csnUtils');
15
20
 
16
21
  const identifierRegex = /^[$_a-zA-Z][$_a-zA-Z0-9]*$/;
17
22
 
@@ -24,15 +29,36 @@ const identifierRegex = /^[$_a-zA-Z][$_a-zA-Z0-9]*$/;
24
29
  * @param {CSN.Model} csn
25
30
  * @param {CSN.Options} [options]
26
31
  */
27
- function csnToCdl(csn, options) {
32
+ function csnToCdl( csn, options ) {
28
33
  timetrace.start('CDL rendering');
29
- const exprRenderer = createCdlExpressionRenderer();
30
34
 
31
- if (options.csnFlavor === 'universal' && isBetaEnabled(options, 'enableUniversalCsn'))
35
+ if (options.csnFlavor === 'universal' && isBetaEnabled(options, 'enableUniversalCsn')) {
36
+ // Since the expander modifies the CSN, we need to clone it first or
37
+ // toCdl can't guarantee that the input CSN is not modified.
38
+ csn = cloneCsnNonDict(csn, options);
32
39
  enrichUniversalCsn(csn, options);
40
+ }
33
41
 
34
42
  checkCSNVersion(csn, options);
35
43
 
44
+ const exprRenderer = createCdlExpressionRenderer();
45
+ const usings = {
46
+ list: [],
47
+ available: availableFirstPathSteps(csn),
48
+ addIfRequired(name) {
49
+ // RegEx is at least twice as fast as .split()[0]
50
+ const first = name.match(/^[^.]+/)[0];
51
+ if (!this.available.includes(first) && !this.list.includes(first))
52
+ this.list.push(first);
53
+ },
54
+ renderUsings() {
55
+ if (this.list.length === 0)
56
+ return '';
57
+ return `using { ${this.list.join(', ')} };\n\n`;
58
+ },
59
+ };
60
+ const hanaRequiresAbsolutePath = usings.available.includes('hana');
61
+
36
62
  const cdlResult = Object.create(null);
37
63
  cdlResult.model = options.testMode ? '' : `// ${generatedByCompilerVersion()} \n`;
38
64
 
@@ -52,7 +78,14 @@ function csnToCdl(csn, options) {
52
78
  cdlResult.namespace += 'using from \'./model.cds\';';
53
79
  }
54
80
 
55
- timetrace.stop();
81
+ cdlResult.model = usings.renderUsings() + cdlResult.model;
82
+ if (csn.requires) {
83
+ let usingsStr = csn.requires.map(req => `using from '${req}';`).join('\n');
84
+ usingsStr += '\n\n';
85
+ cdlResult.model = usingsStr + cdlResult.model;
86
+ }
87
+
88
+ timetrace.stop('CDL rendering');
56
89
  return cdlResult;
57
90
 
58
91
  /**
@@ -79,12 +112,12 @@ function csnToCdl(csn, options) {
79
112
  * @param {object} vocabularies
80
113
  * @return {string}
81
114
  */
82
- function renderVocabularies(vocabularies) {
115
+ function renderVocabularies( vocabularies ) {
83
116
  let result = '';
84
117
  forEach(vocabularies, renderVocabulariesEntry);
85
118
  return result;
86
119
 
87
- function renderVocabulariesEntry(name, anno) {
120
+ function renderVocabulariesEntry( name, anno ) {
88
121
  if (!anno._ignore) {
89
122
  // This environment is passed down the call hierarchy, for dealing with
90
123
  // indentation and name resolution issues
@@ -104,7 +137,7 @@ function csnToCdl(csn, options) {
104
137
  * @param {CdlRenderEnvironment} env
105
138
  * @return {string}
106
139
  */
107
- function renderExtensions(extensions, env) {
140
+ function renderExtensions( extensions, env ) {
108
141
  if (!env.path)
109
142
  env = envNewPath(env, [ 'extensions' ]);
110
143
  return extensions.map((ext, index) => renderExtension(ext, envAddPath(env, [ index ]))).join('\n');
@@ -117,7 +150,7 @@ function csnToCdl(csn, options) {
117
150
  * @param {CdlRenderEnvironment} env
118
151
  * @return {string}
119
152
  */
120
- function renderExtension(ext, env) {
153
+ function renderExtension( ext, env ) {
121
154
  if (ext.extend)
122
155
  return renderExtendStatement(ext.extend, ext, env);
123
156
  return renderAnnotateStatement(ext, env);
@@ -133,20 +166,33 @@ function csnToCdl(csn, options) {
133
166
  * @param {CdlRenderEnvironment} env
134
167
  * @return {string}
135
168
  */
136
- function renderExtendStatement(extName, ext, env) {
137
- extName = renderArtifactName(extName);
138
- // Element extensions have `kind` set.
139
- const isElementExtend = (ext.kind === 'extend');
169
+ function renderExtendStatement( extName, ext, env ) {
170
+ // Element extensions have `kind` set. Don't use for enum extension.
171
+ const isElementExtend = (ext.kind === 'extend' && !ext.enum);
140
172
  let result = renderAnnotationAssignmentsAndDocComment(ext, env);
173
+ extName = isElementExtend ? renderArtifactName(extName) : renderDefinitionReference(extName);
141
174
 
142
175
  if (ext.includes && ext.includes.length > 0) {
143
176
  // Includes can't be combined with anything in braces {}.
144
177
  const affix = isElementExtend ? 'element ' : '';
145
- const includes = ext.includes.map(inc => quotePathIfRequired(inc)).join(', ');
178
+ const includes = ext.includes.map(inc => renderDefinitionReference(inc)).join(', ');
146
179
  result += `${env.indent}extend ${affix}${extName} with ${includes};\n`;
147
180
  return result;
148
181
  }
149
182
 
183
+ const typeParams = renderTypeParameters(ext, true);
184
+ if (typeParams) {
185
+ result += `${env.indent}extend ${extName} with ${typeParams};\n`;
186
+ return result;
187
+ }
188
+
189
+ // If there is nothing to extend, e.g. only annotations, don't render an
190
+ // empty element list. This would end up in diffs with parseCdl CSN.
191
+ if (!ext.elements && !ext.columns && !ext.actions && !ext.enum) {
192
+ result += `${env.indent}extend ${extName};\n`;
193
+ return result;
194
+ }
195
+
150
196
  // We have the "old-style" prefix syntax and the "new-style" postfix "with <type>" syntax.
151
197
  // The former one can not only extend (sub-)elements but also actions in the same statement whereas
152
198
  // the latter cannot.
@@ -157,18 +203,12 @@ function csnToCdl(csn, options) {
157
203
  else
158
204
  result += `${env.indent}extend ${extName} with ${getExtendPostfixVariant(ext)} {\n`;
159
205
 
160
- if (ext.columns) {
206
+ if (ext.columns)
161
207
  result += renderViewColumns(ext.columns, increaseIndent(env));
162
- }
163
- else if (ext.elements) {
208
+
209
+ else if (ext.elements || ext.enum)
164
210
  result += renderExtendStatementElements(ext, env);
165
- }
166
- else if (ext.enum) {
167
- const childEnv = increaseIndent(env);
168
- forEach(ext.enum, (name, value) => {
169
- result += renderEnumElement(name, value, childEnv);
170
- });
171
- }
211
+
172
212
 
173
213
  // Not part of if/else cascade, because it may be in postfix notation.
174
214
  if (ext.actions) {
@@ -194,7 +234,7 @@ function csnToCdl(csn, options) {
194
234
  * @param {object} ext
195
235
  * @return {string}
196
236
  */
197
- function getExtendPrefixVariant(ext) {
237
+ function getExtendPrefixVariant( ext ) {
198
238
  if (ext.kind === 'extend')
199
239
  return 'element'; // element extensions inside an `extend`
200
240
  if (ext.columns)
@@ -210,7 +250,7 @@ function csnToCdl(csn, options) {
210
250
  * @param {CSN.Extension} ext
211
251
  * @return {string}
212
252
  */
213
- function getExtendPostfixVariant(ext) {
253
+ function getExtendPostfixVariant( ext ) {
214
254
  if (ext.columns)
215
255
  return 'columns';
216
256
  if (ext.actions)
@@ -229,15 +269,15 @@ function csnToCdl(csn, options) {
229
269
  * @param {CdlRenderEnvironment} env
230
270
  * @return {string}
231
271
  */
232
- function renderExtendStatementElements(ext, env) {
272
+ function renderExtendStatementElements( ext, env ) {
233
273
  let result = '';
234
- forEach(ext.elements || {}, (elemName, element) => {
274
+ forEach(ext.elements || ext.enum || {}, (elemName, element) => {
235
275
  if (element.kind === 'extend')
236
276
  result += renderExtendStatement(elemName, element, increaseIndent(env));
237
277
  else
238
278
  // As soon as we are inside an element, nested `extend` are not possible,
239
279
  // since we can't extend an existing element of a new one.
240
- result += renderElement(elemName, element, increaseIndent(env), true);
280
+ result += renderElement(elemName, element, increaseIndent(env));
241
281
  });
242
282
  return result;
243
283
  }
@@ -249,9 +289,11 @@ function csnToCdl(csn, options) {
249
289
  * @param {CdlRenderEnvironment} env
250
290
  * @return {string}
251
291
  */
252
- function renderAnnotateStatement(ext, env) {
292
+ function renderAnnotateStatement( ext, env ) {
253
293
  // Top-level annotations of the artifact
254
294
  let result = renderAnnotationAssignmentsAndDocComment(ext, env);
295
+ // Note: Not renderDefinitionReference, because we don't care if there
296
+ // are annotations to unknown things. That's allowed!
255
297
  result += `${env.indent}annotate ${renderArtifactName(ext.annotate)}`;
256
298
 
257
299
  if (ext.params)
@@ -260,6 +302,8 @@ function csnToCdl(csn, options) {
260
302
  // Element extensions and annotations (possibly nested)
261
303
  if (ext.elements)
262
304
  result += renderAnnotateStatementElements(ext.elements, env);
305
+ if (ext.enum)
306
+ result += renderAnnotateStatementElements(ext.enum, env);
263
307
 
264
308
  // Returns annotations
265
309
  if (ext.returns) {
@@ -298,18 +342,21 @@ function csnToCdl(csn, options) {
298
342
  * 'elements' (assuming that the surrounding parent has just been rendered, without trailing newline).
299
343
  * Returns the resulting source string, ending without a trailing newline.
300
344
  *
301
- * @param {CSN.Elements} elements
345
+ * @param {object} elements
302
346
  * @param {CdlRenderEnvironment} env
303
347
  * @return {string}
304
348
  */
305
- function renderAnnotateStatementElements(elements, env) {
349
+ function renderAnnotateStatementElements( elements, env ) {
306
350
  let result = ' {\n';
307
351
  const childEnv = increaseIndent(env);
308
352
  for (const name in elements) {
309
353
  const elem = elements[name];
310
- result += renderAnnotationAssignmentsAndDocComment(elem, childEnv) + childEnv.indent + quoteIdIfRequired(name);
354
+ result += renderAnnotationAssignmentsAndDocComment(elem, childEnv);
355
+ result += childEnv.indent + quoteIdIfRequired(name);
311
356
  if (elem.elements)
312
357
  result += renderAnnotateStatementElements(elem.elements, childEnv);
358
+ if (elem.enum)
359
+ result += renderAnnotateStatementElements(elem.enum, childEnv);
313
360
 
314
361
  result += ';\n';
315
362
  }
@@ -324,7 +371,7 @@ function csnToCdl(csn, options) {
324
371
  * @param {CdlRenderEnvironment} env
325
372
  * @return {string}
326
373
  */
327
- function renderAnnotateParamsInParentheses(params, env) {
374
+ function renderAnnotateParamsInParentheses( params, env ) {
328
375
  const childEnv = increaseIndent(env);
329
376
  let result = '(\n';
330
377
  const paramAnnotations = [];
@@ -342,7 +389,7 @@ function csnToCdl(csn, options) {
342
389
  * @param {CSN.Artifact} art
343
390
  * @param {CdlRenderEnvironment} env
344
391
  */
345
- function renderArtifact(artifactName, art, env) {
392
+ function renderArtifact( artifactName, art, env ) {
346
393
  env = envNewPath(env, [ 'definitions', artifactName ]);
347
394
  env.artifactName = artifactName;
348
395
 
@@ -379,7 +426,7 @@ function csnToCdl(csn, options) {
379
426
  * @param {CSN.Artifact} art
380
427
  * @param {CdlRenderEnvironment} env
381
428
  */
382
- function renderEvent(artifactName, art, env) {
429
+ function renderEvent( artifactName, art, env ) {
383
430
  let result = renderAnnotationAssignmentsAndDocComment(art, env);
384
431
  const normalizedArtifactName = renderArtifactName(artifactName);
385
432
  result += `${env.indent}event ${normalizedArtifactName}`;
@@ -407,7 +454,7 @@ function csnToCdl(csn, options) {
407
454
  * @param {CdlRenderEnvironment} env
408
455
  * @returns {string}
409
456
  */
410
- function renderContextOrService(artifactName, art, env) {
457
+ function renderContextOrService( artifactName, art, env ) {
411
458
  let result = renderAnnotationAssignmentsAndDocComment(art, env);
412
459
  result += `${env.indent}${art.kind} ${renderArtifactName(artifactName)}`;
413
460
  return `${result} {};\n`;
@@ -421,7 +468,7 @@ function csnToCdl(csn, options) {
421
468
  * @param {CdlRenderEnvironment} env
422
469
  * @return {string}
423
470
  */
424
- function renderEntity(artifactName, art, env) {
471
+ function renderEntity( artifactName, art, env ) {
425
472
  let result = renderAnnotationAssignmentsAndDocComment(art, env);
426
473
  result += env.indent + (art.abstract ? 'abstract ' : '');
427
474
  result += `entity ${renderArtifactName(artifactName)}`;
@@ -445,7 +492,7 @@ function csnToCdl(csn, options) {
445
492
  * @param {CdlRenderEnvironment} env
446
493
  * @return {string}
447
494
  */
448
- function renderAspect(artifactName, art, env) {
495
+ function renderAspect( artifactName, art, env ) {
449
496
  let result = renderAnnotationAssignmentsAndDocComment(art, env);
450
497
  result += `${env.indent}aspect ${renderArtifactName(artifactName)}`;
451
498
  if (art.includes)
@@ -468,11 +515,11 @@ function csnToCdl(csn, options) {
468
515
  * @param {CdlRenderEnvironment} env
469
516
  * @return {string}
470
517
  */
471
- function renderElements(artifact, env) {
518
+ function renderElements( artifact, env ) {
472
519
  let elements = '';
473
520
  const childEnv = increaseIndent(env);
474
521
  for (const name in artifact.elements)
475
- elements += renderElement(name, artifact.elements[name], childEnv, null);
522
+ elements += renderElement(name, artifact.elements[name], childEnv);
476
523
 
477
524
  if (elements === '')
478
525
  return '{ }';
@@ -480,23 +527,34 @@ function csnToCdl(csn, options) {
480
527
  }
481
528
 
482
529
  /**
483
- * Render an element (of an entity, type or annotation, not a projection or view).
484
- * Return the resulting source string.
530
+ * Render an element (of an entity, type or annotation, not a projection or view)
531
+ * or an enum symbol.
532
+ * Returns the resulting source string.
485
533
  *
486
534
  * @param {string} elementName
487
- * @param {CSN.Element} elm
535
+ * @param {CSN.Element|CSN.Enum} elm
488
536
  * @param {CdlRenderEnvironment} env
489
- * @param {Boolean} [isSubElement]
490
537
  */
491
- function renderElement(elementName, elm, env, isSubElement) {
538
+ function renderElement( elementName, elm, env ) {
492
539
  env = envAddPath(env, [ 'elements', elementName ]);
493
540
  let result = renderAnnotationAssignmentsAndDocComment(elm, env);
494
541
  result += env.indent;
495
542
  result += elm.virtual ? 'virtual ' : '';
496
- result += elm.key && !isSubElement ? 'key ' : '';
543
+ result += elm.key ? 'key ' : '';
497
544
  // TODO(v4): Remove once deprecated flag for `masked` is removed.
498
545
  result += elm.masked ? 'masked ' : '';
499
- result += `${quoteIdIfRequired(elementName)} : ${renderTypeReferenceAndProps(elm, env)}`;
546
+ result += quoteIdIfRequired(elementName);
547
+ if (elm.val !== undefined) {
548
+ result += ` = ${exprRenderer.renderExpr(elm, env)}`;
549
+ }
550
+ else if (elm['#'] !== undefined) {
551
+ result += ` = #${elm['#']}`;
552
+ }
553
+ else {
554
+ const props = renderTypeReferenceAndProps(elm, env);
555
+ if (props !== '')
556
+ result += ` : ${props}`;
557
+ }
500
558
 
501
559
  return `${result};\n`;
502
560
  }
@@ -516,8 +574,8 @@ function csnToCdl(csn, options) {
516
574
  * @param {CdlRenderEnvironment} env
517
575
  * @return {string}
518
576
  */
519
- function renderQueryElementAndEnumAnnotations(artifactName, art, env) {
520
- const annotate = collectAnnotationsOfElementsAndEnum(art, { artifactName, path: env.path });
577
+ function renderQueryElementAndEnumAnnotations( artifactName, art, env ) {
578
+ const annotate = collectAnnotationsOfElementsAndEnum(art, createEnv({ artifactName, path: env.path }));
521
579
  if (annotate)
522
580
  return renderExtensions([ annotate ], env);
523
581
  return '';
@@ -531,7 +589,7 @@ function csnToCdl(csn, options) {
531
589
  * @param {CdlRenderEnvironment} env
532
590
  * @return {CSN.Extension|null}
533
591
  */
534
- function collectAnnotationsOfElementsAndEnum(artifact, env) {
592
+ function collectAnnotationsOfElementsAndEnum( artifact, env ) {
535
593
  // Array, which may be annotated as well.
536
594
  if (artifact.items) {
537
595
  env = envAddPath(env, [ 'items' ]);
@@ -573,7 +631,7 @@ function csnToCdl(csn, options) {
573
631
  *
574
632
  * @return {boolean} True, if there were annotations, false otherwise.
575
633
  */
576
- function collectAnnos(annotateObj, art) {
634
+ function collectAnnos( annotateObj, art ) {
577
635
  if (!art.elements && !art.enum)
578
636
  return false;
579
637
 
@@ -617,7 +675,7 @@ function csnToCdl(csn, options) {
617
675
  * @param {CdlRenderEnvironment} env
618
676
  * @return {string}
619
677
  */
620
- function renderViewSource(source, env) {
678
+ function renderViewSource( source, env ) {
621
679
  // Sub-SELECT
622
680
  if (source.SELECT || source.SET) {
623
681
  let result = `(${renderQuery(source, false, 'view', increaseIndent(env))})`;
@@ -645,7 +703,7 @@ function csnToCdl(csn, options) {
645
703
  return renderAbsolutePathWithAlias(source, env);
646
704
  }
647
705
 
648
- function renderJoinCardinality(card) {
706
+ function renderJoinCardinality( card ) {
649
707
  let result = '';
650
708
  if (card) {
651
709
  if (card.srcmin && card.srcmin === 1)
@@ -669,17 +727,16 @@ function csnToCdl(csn, options) {
669
727
  * @param {CdlRenderEnvironment} env
670
728
  * @return {string}
671
729
  */
672
- function renderAbsolutePath(path, env) {
730
+ function renderAbsolutePath( path, env ) {
673
731
  // Sanity checks
674
732
  if (!path.ref)
675
733
  throw new ModelError(`Expecting ref in path: ${JSON.stringify(path)}`);
676
734
 
677
-
678
735
  // Determine the absolute name of the first artifact on the path (before any associations or element traversals)
679
736
  const firstArtifactName = path.ref[0].id || path.ref[0];
680
737
 
681
738
  // Render the first path step (absolute name, with different quoting/naming ..)
682
- let result = renderArtifactName(firstArtifactName);
739
+ let result = renderDefinitionReference(firstArtifactName);
683
740
 
684
741
  // Even the first step might have parameters and/or a filter
685
742
  if (path.ref[0].args)
@@ -709,7 +766,7 @@ function csnToCdl(csn, options) {
709
766
  * @param {CdlRenderEnvironment} env
710
767
  * @return {string}
711
768
  */
712
- function renderAbsolutePathWithAlias(path, env) {
769
+ function renderAbsolutePathWithAlias( path, env ) {
713
770
  let result = renderAbsolutePath(path, env);
714
771
  if (path.as) {
715
772
  // Source had an alias - render it
@@ -726,7 +783,7 @@ function csnToCdl(csn, options) {
726
783
  * @param {CdlRenderEnvironment} env
727
784
  * @return {string}
728
785
  */
729
- function renderViewColumns(columns, env, elements = Object.create(null)) {
786
+ function renderViewColumns( columns, env, elements = Object.create(null) ) {
730
787
  const result = columns.map(col => renderViewColumn(col, env, findElement(elements, col)))
731
788
  .filter(s => s !== '')
732
789
  .join(',\n');
@@ -742,7 +799,7 @@ function csnToCdl(csn, options) {
742
799
  * @param {CdlRenderEnvironment} env
743
800
  * @param {CSN.Element} element Element corresponding to the column. Generated by the compiler.
744
801
  */
745
- function renderViewColumn(col, env, element) {
802
+ function renderViewColumn( col, env, element ) {
746
803
  // Annotations and column
747
804
  let result = '';
748
805
  if (!col.doc) {
@@ -789,7 +846,7 @@ function csnToCdl(csn, options) {
789
846
  * @param {CdlRenderEnvironment} env
790
847
  * @returns {string}
791
848
  */
792
- function renderInlineExpand(obj, env) {
849
+ function renderInlineExpand( obj, env ) {
793
850
  // No expression to render for { * } as alias
794
851
  let result = (obj.as && obj.expand && !obj.ref) ? '' : exprRenderer.renderExpr(withoutCast(obj), env);
795
852
 
@@ -814,11 +871,9 @@ function csnToCdl(csn, options) {
814
871
  // Drill down and render children of the expand/inline
815
872
  const childEnv = increaseIndent(env);
816
873
  const expandInline = obj.expand || obj.inline;
817
- expandInline.forEach((elm, i) => {
818
- result += `${childEnv.indent}${renderInlineExpand(elm, childEnv)}`;
819
- if (i < expandInline.length - 1)
820
- result += ',\n';
821
- });
874
+ result += expandInline //
875
+ .map(elm => renderAnnotationAssignmentsAndDocComment(elm, childEnv) + childEnv.indent + renderInlineExpand(elm, childEnv))
876
+ .join(',\n');
822
877
  result += `\n${env.indent}}`;
823
878
 
824
879
  // Don't forget about the .excluding
@@ -839,7 +894,7 @@ function csnToCdl(csn, options) {
839
894
  * @param {CdlRenderEnvironment} env
840
895
  * @returns {String}
841
896
  */
842
- function renderDocComment(obj, env) {
897
+ function renderDocComment( obj, env ) {
843
898
  if (!obj || obj && obj.doc === undefined)
844
899
  return '';
845
900
  else if (obj && obj.doc === null) // empty doc comment needs to be rendered
@@ -855,15 +910,11 @@ function csnToCdl(csn, options) {
855
910
  }
856
911
 
857
912
  /**
858
- * Render a view. If '$syntax' is set (to 'projection', 'view', 'entity'),
859
- * the view query is rendered in the requested syntax style, otherwise it
860
- * is rendered as a view.
861
- *
862
913
  * @param {string} artifactName
863
914
  * @param {CSN.Artifact} art
864
915
  * @param {CdlRenderEnvironment} env
865
916
  */
866
- function renderView(artifactName, art, env) {
917
+ function renderView( artifactName, art, env ) {
867
918
  const syntax = (art.projection) ? 'projection' : 'entity';
868
919
  let result = renderAnnotationAssignmentsAndDocComment(art, env);
869
920
  result += `${env.indent}entity ${renderArtifactName(artifactName)}`;
@@ -893,7 +944,7 @@ function csnToCdl(csn, options) {
893
944
  * @param {CSN.Path} [path=[]]
894
945
  * @param {object} [elements]
895
946
  */
896
- function renderQuery(query, isLeadingQuery, syntax, env, path = [], elements = query.elements || Object.create(null)) {
947
+ function renderQuery( query, isLeadingQuery, syntax, env, path = [], elements = query.elements || Object.create(null) ) {
897
948
  if (query.SET) {
898
949
  // Set operator, such as UNION, INTERSECT, or EXCEPT...
899
950
  return renderQuerySet();
@@ -962,7 +1013,7 @@ function csnToCdl(csn, options) {
962
1013
  * @param {CdlRenderEnvironment} indentEnv
963
1014
  * @return {string}
964
1015
  */
965
- function continueIndent(str, indentEnv) {
1016
+ function continueIndent( str, indentEnv ) {
966
1017
  if (str.endsWith('}') || str.endsWith('})')) {
967
1018
  // The preceding clause ended with '}', just append after that
968
1019
  return ' ';
@@ -978,7 +1029,7 @@ function csnToCdl(csn, options) {
978
1029
  * @param {CdlRenderEnvironment} limitEnv
979
1030
  * @return {string}
980
1031
  */
981
- function renderLimit(limit, limitEnv) {
1032
+ function renderLimit( limit, limitEnv ) {
982
1033
  let limitStr = '';
983
1034
  if (limit.rows !== undefined)
984
1035
  limitStr += `limit ${exprRenderer.renderExpr(limit.rows, limitEnv)}`;
@@ -1022,7 +1073,7 @@ function csnToCdl(csn, options) {
1022
1073
  * @param {CdlRenderEnvironment} env
1023
1074
  * @return {string}
1024
1075
  */
1025
- function renderOrderByEntry(entry, env) {
1076
+ function renderOrderByEntry( entry, env ) {
1026
1077
  let result = renderAnnotationAssignmentsAndDocComment(entry, env) + exprRenderer.renderExpr(entry, env);
1027
1078
  if (entry.sort)
1028
1079
  result += ` ${entry.sort}`;
@@ -1043,7 +1094,7 @@ function csnToCdl(csn, options) {
1043
1094
  * @param {CdlRenderEnvironment} env
1044
1095
  * @return {string}
1045
1096
  */
1046
- function renderActionsAndFunctions(art, env) {
1097
+ function renderActionsAndFunctions( art, env ) {
1047
1098
  let result = '';
1048
1099
  const childEnv = increaseIndent(env);
1049
1100
  for (const name in art.actions)
@@ -1064,7 +1115,7 @@ function csnToCdl(csn, options) {
1064
1115
  * @param {CdlRenderEnvironment} env
1065
1116
  * @return {string}
1066
1117
  */
1067
- function renderActionOrFunction(actionName, act, env) {
1118
+ function renderActionOrFunction( actionName, act, env ) {
1068
1119
  let result = renderAnnotationAssignmentsAndDocComment(act, env) + env.indent + act.kind;
1069
1120
  result += ` ${renderArtifactName(actionName)}`;
1070
1121
  result += renderParameters(act, env);
@@ -1086,7 +1137,7 @@ function csnToCdl(csn, options) {
1086
1137
  * @param {CdlRenderEnvironment} env
1087
1138
  * @returns {string}
1088
1139
  */
1089
- function renderParameters(art, env) {
1140
+ function renderParameters( art, env ) {
1090
1141
  const childEnv = increaseIndent(env);
1091
1142
  const parameters = Object.keys(art.params || {}).map(name => renderParameter(name, art.params[name], childEnv));
1092
1143
  if (parameters.length === 0)
@@ -1102,7 +1153,7 @@ function csnToCdl(csn, options) {
1102
1153
  * @param {CdlRenderEnvironment} env
1103
1154
  * @return {string}
1104
1155
  */
1105
- function renderParameter(parName, par, env) {
1156
+ function renderParameter( parName, par, env ) {
1106
1157
  env = envAddPath(env, [ 'params', parName ]);
1107
1158
  let result = `${renderAnnotationAssignmentsAndDocComment(par, env)}${env.indent}`;
1108
1159
  result += `${quoteIdIfRequired(parName)} : ${renderTypeReferenceAndProps(par, env)}`;
@@ -1119,7 +1170,7 @@ function csnToCdl(csn, options) {
1119
1170
  * @param {String} [artType] - used for rendering csn.vocabularies, as the annotations there do not have a kind.
1120
1171
  * @return {string}
1121
1172
  */
1122
- function renderTypeOrAnnotation(artifactName, art, env, artType) {
1173
+ function renderTypeOrAnnotation( artifactName, art, env, artType ) {
1123
1174
  let result = renderAnnotationAssignmentsAndDocComment(art, env);
1124
1175
  result += `${env.indent + (artType || art.$syntax || art.kind )} ${renderArtifactName(artifactName)}`;
1125
1176
  if (art.includes)
@@ -1144,7 +1195,7 @@ function csnToCdl(csn, options) {
1144
1195
  * - `noAnnoCollect` Do not collect annotations of sub-elements.
1145
1196
  * @return {string}
1146
1197
  */
1147
- function renderTypeReferenceAndProps(artifact, env, config = {}) {
1198
+ function renderTypeReferenceAndProps( artifact, env, config = {} ) {
1148
1199
  let result = '';
1149
1200
  const { typeRefOnly, noAnnoCollect } = config;
1150
1201
  let isTypeDef = env.path?.length === 2; // e.g [ 'definitions', typeDef ];
@@ -1250,8 +1301,8 @@ function csnToCdl(csn, options) {
1250
1301
  * @param {CdlRenderEnvironment} env
1251
1302
  * @return {string}
1252
1303
  */
1253
- function renderRedirectedTo(art, env) {
1254
- let result = `redirected to ${quotePathIfRequired(art.target)}`;
1304
+ function renderRedirectedTo( art, env ) {
1305
+ let result = `redirected to ${renderDefinitionReference(art.target)}`;
1255
1306
  if (art.on)
1256
1307
  result += ` on ${exprRenderer.renderExpr(art.on, env)}`;
1257
1308
  else if (art.keys)
@@ -1264,19 +1315,22 @@ function csnToCdl(csn, options) {
1264
1315
  * @param {CSN.Artifact} artWithType
1265
1316
  * @return {string}
1266
1317
  */
1267
- function renderNamedTypeWithParameters(artWithType) {
1318
+ function renderNamedTypeWithParameters( artWithType ) {
1268
1319
  let result = '';
1269
1320
 
1270
1321
  if (isBuiltinType(artWithType.type)) {
1271
- // If there is a user-defined type with the same short name (cds.Integer -> Integer),
1272
- // we render the full name, including the leading "cds."
1273
- if (csn.definitions[artWithType.type.slice(4)])
1322
+ // If there is a user-defined type that starts with the same short name
1323
+ // (cds.Integer -> Integer), we render the full name, including the leading "cds."
1324
+ const shortHand = artWithType.type.slice(4);
1325
+ if (shortHand.startsWith('hana.') && hanaRequiresAbsolutePath)
1326
+ result += artWithType.type;
1327
+ else if (usings.available.includes(shortHand))
1274
1328
  result += artWithType.type;
1275
1329
  else
1276
- result += artWithType.type.slice(4);
1330
+ result += shortHand;
1277
1331
  }
1278
1332
  else {
1279
- result += renderArtifactName(artWithType.type);
1333
+ result += renderDefinitionReference(artWithType.type);
1280
1334
  }
1281
1335
 
1282
1336
  result += renderTypeParameters(artWithType);
@@ -1291,35 +1345,15 @@ function csnToCdl(csn, options) {
1291
1345
  * @param {CdlRenderEnvironment} env
1292
1346
  * @return {string}
1293
1347
  */
1294
- function renderEnum(enumPart, env) {
1348
+ function renderEnum( enumPart, env ) {
1295
1349
  let result = ' enum {\n';
1296
1350
  const childEnv = increaseIndent(env);
1297
1351
  for (const name in enumPart)
1298
- result += renderEnumElement(name, enumPart[name], childEnv);
1352
+ result += renderElement(name, enumPart[name], childEnv);
1299
1353
  result += `${env.indent}}`;
1300
1354
  return result;
1301
1355
  }
1302
1356
 
1303
- /**
1304
- * Render the element of a `<type> enum {}` structure.
1305
- *
1306
- * @param {string} name
1307
- * @param {CSN.EnumValue} enumValue
1308
- * @param {CdlRenderEnvironment} env
1309
- * @return {string}
1310
- */
1311
- function renderEnumElement(name, enumValue, env) {
1312
- let result = '';
1313
- result += renderAnnotationAssignmentsAndDocComment(enumValue, env);
1314
- result += env.indent + quoteIdIfRequired(name);
1315
- if (enumValue.val !== undefined)
1316
- result += ` = ${exprRenderer.renderExpr(enumValue, env)}`;
1317
- else if (enumValue['#'] !== undefined)
1318
- result += ` = #${enumValue['#']}`;
1319
- result += ';\n';
1320
- return result;
1321
- }
1322
-
1323
1357
  /**
1324
1358
  * Render an annotation value (somewhat like a simplified expression, with slightly different
1325
1359
  * representation)
@@ -1327,7 +1361,7 @@ function csnToCdl(csn, options) {
1327
1361
  * @param {any} x
1328
1362
  * @param {CdlRenderEnvironment} env
1329
1363
  */
1330
- function renderAnnotationValue(x, env) {
1364
+ function renderAnnotationValue( x, env ) {
1331
1365
  if (Array.isArray(x)) {
1332
1366
  // Render array parts as values. Spaces required if last array value is
1333
1367
  // a delimited identifier.
@@ -1377,7 +1411,7 @@ function csnToCdl(csn, options) {
1377
1411
  * @param {object} env
1378
1412
  * @returns {string}
1379
1413
  */
1380
- function renderPathStep(s, idx, env) {
1414
+ function renderPathStep( s, idx, env ) {
1381
1415
  // Simple id or absolute name
1382
1416
  if (typeof s === 'string') {
1383
1417
  // In first path position, do not quote $projection and magic $-variables like CURRENT_DATE, $now etc.
@@ -1424,7 +1458,7 @@ function csnToCdl(csn, options) {
1424
1458
  * @param {CdlRenderEnvironment} env
1425
1459
  * @returns {string}
1426
1460
  */
1427
- function renderArguments(node, sep, env) {
1461
+ function renderArguments( node, sep, env ) {
1428
1462
  if (!node.args)
1429
1463
  return '';
1430
1464
  else if (Array.isArray(node.args))
@@ -1443,7 +1477,7 @@ function csnToCdl(csn, options) {
1443
1477
  * @param {CdlRenderEnvironment} env
1444
1478
  * @returns {string}
1445
1479
  */
1446
- function renderNamedArguments(node, separator, env) {
1480
+ function renderNamedArguments( node, separator, env ) {
1447
1481
  return Object.keys(node.args).map(function renderNamedArgument(key) {
1448
1482
  return `${quoteIdIfRequired(key, env.additionalKeywords)} ${separator} ${renderArgument(node.args[key], env)}`;
1449
1483
  }).join(', ');
@@ -1456,7 +1490,7 @@ function csnToCdl(csn, options) {
1456
1490
  * @param {CdlRenderEnvironment} env
1457
1491
  * @returns {string}
1458
1492
  */
1459
- function renderPositionalArguments(node, env) {
1493
+ function renderPositionalArguments( node, env ) {
1460
1494
  if (!node.args)
1461
1495
  return '';
1462
1496
  const func = node.func?.toUpperCase();
@@ -1477,7 +1511,7 @@ function csnToCdl(csn, options) {
1477
1511
  * @param {string[]} additionalKeywords
1478
1512
  * @return {string}
1479
1513
  */
1480
- function renderArgument(arg, env, additionalKeywords = []) {
1514
+ function renderArgument( arg, env, additionalKeywords = [] ) {
1481
1515
  // If the argument is a xpr with e.g. `=`, it may require parentheses.
1482
1516
  // For nested xpr, `exprRenderer.renderExpr()` will already add parentheses.
1483
1517
  env = { ...env, additionalKeywords };
@@ -1492,7 +1526,7 @@ function csnToCdl(csn, options) {
1492
1526
  * @param artifact
1493
1527
  * @returns {string}
1494
1528
  */
1495
- function renderCardinality(artifact) {
1529
+ function renderCardinality( artifact ) {
1496
1530
  if (isSimpleCardinality(artifact.cardinality))
1497
1531
  return renderSimpleCardinality(artifact);
1498
1532
  return renderBracketCardinality(artifact);
@@ -1504,7 +1538,7 @@ function csnToCdl(csn, options) {
1504
1538
  * @param {CSN.Artifact} art
1505
1539
  * @return {string}
1506
1540
  */
1507
- function renderBracketCardinality(art) {
1541
+ function renderBracketCardinality( art ) {
1508
1542
  const isComp = art.type === 'cds.Composition';
1509
1543
  const suffix = (isComp ? ' of ' : ' to ');
1510
1544
  const card = art.cardinality;
@@ -1532,7 +1566,7 @@ function csnToCdl(csn, options) {
1532
1566
  * @param {CSN.Cardinality} cardinality
1533
1567
  * @return {boolean}
1534
1568
  */
1535
- function isSimpleCardinality(cardinality) {
1569
+ function isSimpleCardinality( cardinality ) {
1536
1570
  return !cardinality || (
1537
1571
  cardinality.min === undefined &&
1538
1572
  cardinality.src === undefined &&
@@ -1548,7 +1582,7 @@ function csnToCdl(csn, options) {
1548
1582
  * @param {CSN.Element} elem
1549
1583
  * @return {string}
1550
1584
  */
1551
- function renderSimpleCardinality(elem) {
1585
+ function renderSimpleCardinality( elem ) {
1552
1586
  let result = (elem.type === 'cds.Association' ? ' to ' : ' of ');
1553
1587
  if (!elem.cardinality)
1554
1588
  return result;
@@ -1560,7 +1594,7 @@ function csnToCdl(csn, options) {
1560
1594
  }
1561
1595
 
1562
1596
  // Render the nullability of an element or parameter (can be unset, true, or false)
1563
- function renderNullability(obj /* , env */) {
1597
+ function renderNullability( obj /* , env */) {
1564
1598
  if (obj.notNull === undefined) {
1565
1599
  // Attribute not set at all
1566
1600
  return '';
@@ -1575,7 +1609,7 @@ function csnToCdl(csn, options) {
1575
1609
  * @param {CdlRenderEnvironment} env
1576
1610
  * @return {string}
1577
1611
  */
1578
- function renderForeignKey(fKey, env) {
1612
+ function renderForeignKey( fKey, env ) {
1579
1613
  const alias = fKey.as ? (` as ${fKey.as}`) : '';
1580
1614
  return exprRenderer.renderExpr(fKey, env) + alias;
1581
1615
  }
@@ -1585,18 +1619,22 @@ function csnToCdl(csn, options) {
1585
1619
  * length, precision and scale (even if incomplete), plus any other unknown ones.
1586
1620
  *
1587
1621
  * @param {CSN.Artifact} artWithType
1622
+ * @param {boolean} noShortVersion If true, parameters will not be shortened, e.g. `(10)`
1623
+ * for length instead of `(length: 10)`.
1588
1624
  * @returns {string}
1589
1625
  */
1590
- function renderTypeParameters(artWithType) {
1626
+ function renderTypeParameters( artWithType, noShortVersion = false ) {
1591
1627
  const params = typeParameters.list.filter(param => artWithType[param] !== undefined);
1592
1628
  if (params.length === 0)
1593
1629
  return '';
1594
1630
 
1631
+ if (!noShortVersion) {
1595
1632
  // Special cases for 1 or 2 arguments.
1596
- if (params.length === 1 && artWithType.length !== undefined)
1597
- return `(${artWithType.length})`;
1598
- if (params.length === 2 && artWithType.precision !== undefined && artWithType.scale !== undefined)
1599
- return `(${artWithType.precision}, ${artWithType.scale})`;
1633
+ if (params.length === 1 && artWithType.length !== undefined)
1634
+ return `(${artWithType.length})`;
1635
+ if (params.length === 2 && artWithType.precision !== undefined && artWithType.scale !== undefined)
1636
+ return `(${artWithType.precision}, ${artWithType.scale})`;
1637
+ }
1600
1638
 
1601
1639
  // Render named params
1602
1640
  const renderedParams = [];
@@ -1614,7 +1652,7 @@ function csnToCdl(csn, options) {
1614
1652
  * @param {{parens: boolean}} [config] Config for renderAnnotationAssignment()
1615
1653
  * @return {string}
1616
1654
  */
1617
- function renderAnnotationAssignmentsAndDocComment(obj, env, config) {
1655
+ function renderAnnotationAssignmentsAndDocComment( obj, env, config ) {
1618
1656
  let result = renderDocComment(obj, env);
1619
1657
  for (const name in obj) {
1620
1658
  if (name.startsWith('@'))
@@ -1634,7 +1672,7 @@ function csnToCdl(csn, options) {
1634
1672
  * @param {object} [config] parens: Whether the annotation assignment must be surrounded by parentheses.
1635
1673
  * @return {string} Rendered annotation, possibly quoted: `@![A.B.C#foo.C]: value`
1636
1674
  */
1637
- function renderAnnotationAssignment(anno, name, env, config = { parens: false }) {
1675
+ function renderAnnotationAssignment( anno, name, env, config = { parens: false } ) {
1638
1676
  name = name.substring(1);
1639
1677
  // Take the annotation assignment apart into <nameBeforeVariant>#<variantAndRest>
1640
1678
  const parts = name.split('#');
@@ -1673,10 +1711,30 @@ function csnToCdl(csn, options) {
1673
1711
  * @param {string} artifactName Artifact name to render
1674
1712
  * @return {string} Artifact name ready for rendering
1675
1713
  */
1676
- function renderArtifactName(artifactName) {
1714
+ function renderArtifactName( artifactName ) {
1677
1715
  return quotePathIfRequired(artifactName);
1678
1716
  }
1679
1717
 
1718
+ /**
1719
+ * Render the name of a definition. Ensures the first segment of the name
1720
+ * is available in the rendered CDL. Otherwise a USING is added.
1721
+ *
1722
+ * @param {string} name
1723
+ * @return {string}
1724
+ */
1725
+ function renderDefinitionReference( name ) {
1726
+ usings.addIfRequired(name);
1727
+ return quotePathIfRequired(name);
1728
+ }
1729
+
1730
+ /**
1731
+ * @param {string[]} includes
1732
+ * @return {string}
1733
+ */
1734
+ function renderIncludes( includes ) {
1735
+ return ` : ${includes.map(name => renderDefinitionReference(name)).join(', ')}`;
1736
+ }
1737
+
1680
1738
  function createCdlExpressionRenderer() {
1681
1739
  return createExpressionRenderer({
1682
1740
  finalize: x => x,
@@ -1745,32 +1803,33 @@ function csnToCdl(csn, options) {
1745
1803
  * Returns a newly created default environment (which keeps track of indentation, required USING
1746
1804
  * declarations and name prefixes.
1747
1805
  *
1806
+ * @param {object} [values]
1748
1807
  * @return {CdlRenderEnvironment}
1749
1808
  */
1750
- function createEnv() {
1751
- return {
1809
+ function createEnv( values = {} ) {
1810
+ return Object.assign({
1752
1811
  // Current indentation string
1753
1812
  indent: '',
1754
1813
  path: null,
1755
1814
  artifactName: '',
1756
1815
  elementName: '',
1757
- };
1816
+ }, values);
1758
1817
  }
1759
1818
 
1760
- function envAddPath(env, path) {
1819
+ function envAddPath( env, path ) {
1761
1820
  return Object.assign({}, env, { path: [ ...env.path, ...path ] } );
1762
1821
  }
1763
- function envNewPath(env, path) {
1822
+ function envNewPath( env, path ) {
1764
1823
  return Object.assign({}, env, { path: [ ...path ] } );
1765
1824
  }
1766
1825
 
1767
1826
  /**
1768
1827
  * Returns a copy of 'env' with increased indentation (and reset name prefix)
1769
1828
  *
1770
- * @param {CdlRenderEnvironment} env
1771
- * @returns {CdlRenderEnvironment}
1829
+ * @param {object} env
1830
+ * @returns {object}
1772
1831
  */
1773
- function increaseIndent(env) {
1832
+ function increaseIndent( env ) {
1774
1833
  return Object.assign({}, env, { indent: `${env.indent} ` });
1775
1834
  }
1776
1835
 
@@ -1786,7 +1845,7 @@ function increaseIndent(env) {
1786
1845
  *
1787
1846
  * @todo For paths such as `E.key`, `key` does not have to be in quotes.
1788
1847
  */
1789
- function quotePathIfRequired(path) {
1848
+ function quotePathIfRequired( path ) {
1790
1849
  return path.split('.').map(step => quoteIdIfRequired(step)).join('.');
1791
1850
  }
1792
1851
 
@@ -1801,7 +1860,7 @@ function quotePathIfRequired(path) {
1801
1860
  * @param {string[]} [additionalKeywords]
1802
1861
  * @return {string}
1803
1862
  */
1804
- function quoteIdIfRequired(id, additionalKeywords) {
1863
+ function quoteIdIfRequired( id, additionalKeywords ) {
1805
1864
  // Quote if required for CDL
1806
1865
  if (requiresQuotingForCdl(id, additionalKeywords || []))
1807
1866
  return quote(id);
@@ -1817,7 +1876,7 @@ function quoteIdIfRequired(id, additionalKeywords) {
1817
1876
  * @param {string} anno
1818
1877
  * @returns {string}
1819
1878
  */
1820
- function quoteAnnotationPathIfRequired(anno) {
1879
+ function quoteAnnotationPathIfRequired( anno ) {
1821
1880
  return anno.split('.').map((segment) => {
1822
1881
  if (segment.startsWith('@'))
1823
1882
  return `@${quoteIdIfRequired(segment.slice(1))}`;
@@ -1831,7 +1890,7 @@ function quoteAnnotationPathIfRequired(anno) {
1831
1890
  * @param id
1832
1891
  * @returns {string}
1833
1892
  */
1834
- function quote(id) {
1893
+ function quote( id ) {
1835
1894
  return `![${id.replace(/]/g, ']]')}]`;
1836
1895
  }
1837
1896
 
@@ -1847,7 +1906,7 @@ function quote(id) {
1847
1906
  * @param {string[]} [additionalKeywords]
1848
1907
  * @return {boolean}
1849
1908
  */
1850
- function requiresQuotingForCdl(id, additionalKeywords) {
1909
+ function requiresQuotingForCdl( id, additionalKeywords ) {
1851
1910
  return !identifierRegex.test(id) ||
1852
1911
  keywords.cdl.includes(id.toUpperCase()) ||
1853
1912
  keywords.cdl_functions.includes(id.toUpperCase()) ||
@@ -1890,7 +1949,7 @@ const functionExpressionOperatorsRequireParentheses = [
1890
1949
  * @param {string[]} additionalAllowedKeywords
1891
1950
  * @return {boolean}
1892
1951
  */
1893
- function isSimpleFunctionExpression(xpr, additionalAllowedKeywords = []) {
1952
+ function isSimpleFunctionExpression( xpr, additionalAllowedKeywords = [] ) {
1894
1953
  return !xpr || xpr.every(val => typeof val !== 'string' ||
1895
1954
  (additionalAllowedKeywords.includes(val.toUpperCase()) ||
1896
1955
  !functionExpressionOperatorsRequireParentheses.includes(val.toUpperCase())));
@@ -1907,7 +1966,7 @@ function isSimpleFunctionExpression(xpr, additionalAllowedKeywords = []) {
1907
1966
  * @param {number} argumentIndex
1908
1967
  * @returns {string[]}
1909
1968
  */
1910
- function getKeywordsForSpecialFunctionArgument(funcName, argumentIndex) {
1969
+ function getKeywordsForSpecialFunctionArgument( funcName, argumentIndex ) {
1911
1970
  const f = specialFunctions[funcName] && specialFunctions[funcName][argumentIndex];
1912
1971
  if (!f)
1913
1972
  return [];
@@ -1921,14 +1980,6 @@ function getKeywordsForSpecialFunctionArgument(funcName, argumentIndex) {
1921
1980
  return additionalKeywords;
1922
1981
  }
1923
1982
 
1924
- /**
1925
- * @param {string[]} includes
1926
- * @return {string}
1927
- */
1928
- function renderIncludes(includes) {
1929
- return ` : ${includes.map(name => quotePathIfRequired(name)).join(', ')}`;
1930
- }
1931
-
1932
1983
  /**
1933
1984
  * Render the given string. Uses back-tick strings.
1934
1985
  * env is used for indentation of three-back-tick strings.
@@ -1937,7 +1988,7 @@ function renderIncludes(includes) {
1937
1988
  * @param env
1938
1989
  * @returns {string}
1939
1990
  */
1940
- function renderString(str, env) {
1991
+ function renderString( str, env ) {
1941
1992
  if (isSimpleString(str))
1942
1993
  return `'${str.replace(/'/g, '\'\'')}'`;
1943
1994
 
@@ -1982,7 +2033,7 @@ function renderString(str, env) {
1982
2033
  }
1983
2034
 
1984
2035
  /** @param {number} codePoint */
1985
- function hexEscape(codePoint) {
2036
+ function hexEscape( codePoint ) {
1986
2037
  const hex = codePoint.toString(16);
1987
2038
  return `\\u{${hex}}`;
1988
2039
  }
@@ -1991,7 +2042,7 @@ function hexEscape(codePoint) {
1991
2042
  * Returns true if the given string can be represented by using single quotes.
1992
2043
  * @param {string} str
1993
2044
  */
1994
- function isSimpleString(str) {
2045
+ function isSimpleString( str ) {
1995
2046
  // A single-line string allows everything except certain line separators/breaks.
1996
2047
  // See ANTLR grammar for specifics.
1997
2048
  // Furthermore, if control characters are used, we escape them,
@@ -2003,13 +2054,28 @@ function isSimpleString(str) {
2003
2054
  !hasUnpairedUnicodeSurrogate(str));
2004
2055
  }
2005
2056
 
2057
+ /**
2058
+ * Get a list of top-level artifact names, which are not in contexts/usings/, i.e. those
2059
+ * before the first dot ('.'). For example for `S.E.F`, `S` is used.
2060
+ *
2061
+ * @param {CSN.Model} csn
2062
+ * @return {string[]}
2063
+ */
2064
+ function availableFirstPathSteps( csn ) {
2065
+ if (!csn.definitions)
2066
+ return [];
2067
+ const unique = new Set(Object.keys(csn.definitions).map(name => name.split('.')[0]));
2068
+ return Array.from(unique);
2069
+ }
2070
+
2006
2071
  /**
2007
2072
  * @typedef CdlRenderEnvironment Rendering environment used throughout the render process.
2008
2073
  *
2009
2074
  * @property {string} indent Current indentation as a string, e.g. ' ' for two spaces.
2010
- * @property {string[]} [path] CSN path to the current artifact
2075
+ * @property {CSN.Path} [path] CSN path to the current artifact
2011
2076
  * @property {string} [artifactName] Name of the artifact - set in renderArtifact
2012
2077
  * @property {string} [elementName] Name of the element being rendered - set in renderElement
2078
+ * @property {string[]} [additionalKeywords] For function rendering: Words that are also keywords.
2013
2079
  */
2014
2080
 
2015
2081
  module.exports = { csnToCdl };