@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.
- package/CHANGELOG.md +58 -0
- package/README.md +1 -0
- package/bin/cds_update_identifiers.js +5 -5
- package/bin/cdsc.js +12 -12
- package/doc/CHANGELOG_ARCHIVE.md +1 -1
- package/doc/CHANGELOG_BETA.md +9 -1
- package/doc/CHANGELOG_DEPRECATED.md +2 -0
- package/lib/api/main.js +58 -59
- package/lib/api/options.js +4 -2
- package/lib/api/validate.js +2 -2
- package/lib/base/cleanSymbols.js +2 -3
- package/lib/base/dictionaries.js +6 -6
- package/lib/base/error.js +2 -2
- package/lib/base/keywords.js +6 -6
- package/lib/base/location.js +11 -12
- package/lib/base/message-registry.js +124 -28
- package/lib/base/messages.js +247 -179
- package/lib/base/model.js +14 -11
- package/lib/base/node-helpers.js +9 -10
- package/lib/base/optionProcessorHelper.js +138 -129
- package/lib/checks/actionsFunctions.js +5 -5
- package/lib/checks/annotationsOData.js +4 -4
- package/lib/checks/arrayOfs.js +1 -1
- package/lib/checks/cdsPersistence.js +1 -1
- package/lib/checks/checkForTypes.js +3 -3
- package/lib/checks/defaultValues.js +3 -3
- package/lib/checks/elements.js +7 -7
- package/lib/checks/emptyOrOnlyVirtual.js +2 -2
- package/lib/checks/foreignKeys.js +1 -1
- package/lib/checks/invalidTarget.js +4 -4
- package/lib/checks/managedInType.js +1 -1
- package/lib/checks/managedWithoutKeys.js +1 -1
- package/lib/checks/nonexpandableStructured.js +5 -3
- package/lib/checks/nullableKeys.js +1 -1
- package/lib/checks/onConditions.js +5 -6
- package/lib/checks/parameters.js +1 -1
- package/lib/checks/queryNoDbArtifacts.js +2 -2
- package/lib/checks/selectItems.js +4 -4
- package/lib/checks/sql-snippets.js +4 -4
- package/lib/checks/types.js +7 -7
- package/lib/checks/utils.js +4 -4
- package/lib/checks/validator.js +16 -13
- package/lib/compiler/.eslintrc.json +1 -1
- package/lib/compiler/assert-consistency.js +0 -1
- package/lib/compiler/builtins.js +1 -1
- package/lib/compiler/checks.js +73 -15
- package/lib/compiler/define.js +3 -7
- package/lib/compiler/extend.js +212 -32
- package/lib/compiler/finalize-parse-cdl.js +7 -2
- package/lib/compiler/index.js +17 -14
- package/lib/compiler/populate.js +2 -5
- package/lib/compiler/propagator.js +2 -0
- package/lib/compiler/shared.js +23 -12
- package/lib/compiler/tweak-assocs.js +5 -6
- package/lib/compiler/utils.js +6 -0
- package/lib/edm/annotations/genericTranslation.js +553 -319
- package/lib/edm/annotations/preprocessAnnotations.js +39 -35
- package/lib/edm/csn2edm.js +88 -75
- package/lib/edm/edm.js +17 -3
- package/lib/edm/edmAnnoPreprocessor.js +5 -5
- package/lib/edm/edmPreprocessor.js +106 -76
- package/lib/edm/edmUtils.js +41 -2
- package/lib/gen/Dictionary.json +34 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +66 -63
- package/lib/gen/language.tokens +81 -81
- package/lib/gen/languageLexer.interp +4 -10
- package/lib/gen/languageLexer.js +854 -869
- package/lib/gen/languageLexer.tokens +79 -81
- package/lib/gen/languageParser.js +14360 -14146
- package/lib/inspect/inspectModelStatistics.js +2 -2
- package/lib/inspect/inspectPropagation.js +6 -6
- package/lib/inspect/inspectUtils.js +2 -2
- package/lib/json/from-csn.js +82 -40
- package/lib/json/to-csn.js +82 -157
- package/lib/language/.eslintrc.json +1 -4
- package/lib/language/genericAntlrParser.js +59 -38
- package/lib/language/language.g4 +1508 -1490
- package/lib/language/multiLineStringParser.js +1 -1
- package/lib/main.js +3 -3
- package/lib/model/csnUtils.js +130 -122
- package/lib/model/revealInternalProperties.js +1 -1
- package/lib/model/sortViews.js +4 -6
- package/lib/modelCompare/utils/filter.js +4 -3
- package/lib/optionProcessor.js +5 -0
- package/lib/render/DuplicateChecker.js +1 -1
- package/lib/render/manageConstraints.js +12 -12
- package/lib/render/toCdl.js +225 -159
- package/lib/render/toHdbcds.js +63 -63
- package/lib/render/toRename.js +5 -5
- package/lib/render/toSql.js +55 -65
- package/lib/render/utils/common.js +20 -37
- package/lib/render/utils/delta.js +3 -3
- package/lib/render/utils/sql.js +22 -6
- package/lib/render/utils/stringEscapes.js +3 -3
- package/lib/transform/db/applyTransformations.js +3 -3
- package/lib/transform/db/assertUnique.js +13 -12
- package/lib/transform/db/associations.js +5 -5
- package/lib/transform/db/cdsPersistence.js +10 -8
- package/lib/transform/db/constraints.js +14 -14
- package/lib/transform/db/expansion.js +20 -22
- package/lib/transform/db/flattening.js +24 -42
- package/lib/transform/db/groupByOrderBy.js +3 -3
- package/lib/transform/db/temporal.js +6 -6
- package/lib/transform/db/transformExists.js +23 -23
- package/lib/transform/db/views.js +16 -16
- package/lib/transform/draft/db.js +10 -10
- package/lib/transform/draft/odata.js +2 -2
- package/lib/transform/forOdataNew.js +12 -40
- package/lib/transform/forRelationalDB.js +17 -7
- package/lib/transform/localized.js +2 -2
- package/lib/transform/odata/toFinalBaseType.js +41 -27
- package/lib/transform/odata/typesExposure.js +106 -62
- package/lib/transform/parseExpr.js +209 -106
- package/lib/transform/transformUtilsNew.js +2 -2
- package/lib/transform/translateAssocsToJoins.js +24 -19
- package/lib/transform/universalCsn/coreComputed.js +10 -10
- package/lib/transform/universalCsn/universalCsnEnricher.js +26 -26
- package/lib/transform/universalCsn/utils.js +3 -3
- package/lib/utils/file.js +5 -5
- package/lib/utils/moduleResolve.js +13 -13
- package/lib/utils/objectUtils.js +6 -6
- package/lib/utils/term.js +5 -2
- package/lib/utils/timetrace.js +51 -24
- package/package.json +5 -7
- package/share/messages/check-proper-type-of.md +1 -1
- package/share/messages/message-explanations.json +1 -1
- package/share/messages/redirected-to-complex.md +4 -4
- package/share/messages/{syntax-expecting-integer.md → syntax-expecting-unsigned-int.md} +7 -4
package/lib/render/toCdl.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
138
|
-
|
|
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 =>
|
|
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)
|
|
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 {
|
|
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)
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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
|
|
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 +=
|
|
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 =
|
|
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
|
-
|
|
818
|
-
|
|
819
|
-
|
|
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 ${
|
|
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
|
|
1272
|
-
// we render the full name, including the leading "cds."
|
|
1273
|
-
|
|
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 +=
|
|
1330
|
+
result += shortHand;
|
|
1277
1331
|
}
|
|
1278
1332
|
else {
|
|
1279
|
-
result +=
|
|
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 +=
|
|
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
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
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 {
|
|
1771
|
-
* @returns {
|
|
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 {
|
|
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 };
|