@sap/cds-compiler 3.4.2 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +80 -0
- package/README.md +1 -0
- package/bin/cds_update_identifiers.js +5 -5
- package/bin/cdsc.js +15 -16
- package/bin/cdshi.js +19 -6
- package/doc/CHANGELOG_ARCHIVE.md +2 -2
- package/doc/CHANGELOG_BETA.md +9 -1
- package/doc/CHANGELOG_DEPRECATED.md +2 -0
- package/lib/api/main.js +61 -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 +177 -58
- package/lib/base/messages.js +252 -180
- 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/.eslintrc.json +2 -0
- 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 +4 -1
- package/lib/compiler/assert-consistency.js +8 -7
- package/lib/compiler/builtins.js +14 -14
- package/lib/compiler/checks.js +123 -48
- package/lib/compiler/define.js +12 -13
- package/lib/compiler/extend.js +266 -60
- package/lib/compiler/finalize-parse-cdl.js +10 -5
- package/lib/compiler/index.js +17 -14
- package/lib/compiler/populate.js +14 -6
- package/lib/compiler/propagator.js +2 -0
- package/lib/compiler/resolve.js +2 -15
- package/lib/compiler/shared.js +27 -16
- package/lib/compiler/tweak-assocs.js +5 -6
- package/lib/compiler/utils.js +20 -0
- package/lib/edm/annotations/genericTranslation.js +604 -358
- package/lib/edm/annotations/preprocessAnnotations.js +39 -35
- package/lib/edm/csn2edm.js +275 -222
- package/lib/edm/edm.js +17 -3
- package/lib/edm/edmAnnoPreprocessor.js +6 -6
- package/lib/edm/edmInboundChecks.js +2 -2
- package/lib/edm/edmPreprocessor.js +107 -77
- package/lib/edm/edmUtils.js +44 -5
- package/lib/gen/Dictionary.json +210 -8
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +67 -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 +14309 -13832
- 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 +102 -55
- package/lib/json/to-csn.js +119 -198
- package/lib/language/antlrParser.js +5 -2
- package/lib/language/docCommentParser.js +6 -6
- package/lib/language/errorStrategy.js +43 -23
- package/lib/language/genericAntlrParser.js +113 -133
- package/lib/language/language.g4 +1550 -1506
- package/lib/language/multiLineStringParser.js +3 -3
- package/lib/language/textUtils.js +2 -2
- package/lib/main.js +3 -3
- package/lib/model/csnRefs.js +5 -0
- package/lib/model/csnUtils.js +130 -122
- package/lib/model/revealInternalProperties.js +1 -1
- package/lib/model/sortViews.js +4 -6
- package/lib/modelCompare/compare.js +2 -2
- package/lib/modelCompare/utils/.eslintrc.json +22 -0
- package/lib/modelCompare/utils/filter.js +100 -0
- package/lib/optionProcessor.js +5 -0
- package/lib/render/.eslintrc.json +1 -0
- package/lib/render/DuplicateChecker.js +1 -1
- package/lib/render/manageConstraints.js +12 -12
- package/lib/render/toCdl.js +311 -276
- package/lib/render/toHdbcds.js +97 -94
- package/lib/render/toRename.js +5 -5
- package/lib/render/toSql.js +127 -223
- package/lib/render/utils/common.js +141 -108
- package/lib/render/utils/delta.js +227 -0
- package/lib/render/utils/sql.js +22 -6
- package/lib/render/utils/stringEscapes.js +3 -3
- package/lib/transform/db/.eslintrc.json +2 -0
- 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/.eslintrc.json +1 -35
- package/lib/transform/draft/db.js +10 -10
- package/lib/transform/draft/odata.js +2 -2
- package/lib/transform/forOdataNew.js +8 -29
- package/lib/transform/forRelationalDB.js +16 -6
- package/lib/transform/localized.js +11 -10
- package/lib/transform/odata/toFinalBaseType.js +41 -27
- package/lib/transform/odata/typesExposure.js +113 -47
- package/lib/transform/parseExpr.js +209 -106
- package/lib/transform/transformUtilsNew.js +17 -10
- 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 -8
- 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/modelCompare/filter.js +0 -83
package/lib/render/toCdl.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const keywords = require('../base/keywords');
|
|
4
|
-
const {
|
|
5
|
-
const { findElement, getExpressionRenderer } = require('./utils/common');
|
|
4
|
+
const { findElement, createExpressionRenderer, withoutCast } = require('./utils/common');
|
|
6
5
|
const { escapeString, hasUnpairedUnicodeSurrogate } = require('./utils/stringEscapes');
|
|
7
6
|
const { checkCSNVersion } = require('../json/csnVersion');
|
|
8
7
|
const { timetrace } = require('../utils/timetrace');
|
|
@@ -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
|
-
let _renderExpr = null;
|
|
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))})`;
|
|
@@ -635,7 +693,7 @@ function csnToCdl(csn, options) {
|
|
|
635
693
|
result += renderJoinCardinality(source.cardinality);
|
|
636
694
|
result += `join ${renderViewSource(source.args[i], env)}`;
|
|
637
695
|
if (source.on)
|
|
638
|
-
result += ` on ${renderExpr(source.on, env
|
|
696
|
+
result += ` on ${exprRenderer.renderExpr(source.on, env)}`;
|
|
639
697
|
}
|
|
640
698
|
result += ')';
|
|
641
699
|
return result;
|
|
@@ -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)
|
|
@@ -687,13 +744,13 @@ function csnToCdl(csn, options) {
|
|
|
687
744
|
|
|
688
745
|
if (path.ref[0].where) {
|
|
689
746
|
const cardinality = path.ref[0].cardinality ? (`${path.ref[0].cardinality.max}: `) : '';
|
|
690
|
-
const expr = renderExpr(path.ref[0].where, env
|
|
747
|
+
const expr = exprRenderer.renderExpr(path.ref[0].where, env);
|
|
691
748
|
result += `[${cardinality}${expr}]`;
|
|
692
749
|
}
|
|
693
750
|
|
|
694
751
|
// Add any path steps (possibly with parameters and filters) that may follow after that
|
|
695
752
|
if (path.ref.length > 1)
|
|
696
|
-
result += `:${renderExpr({ ref: path.ref.slice(1) }, env)}`;
|
|
753
|
+
result += `:${exprRenderer.renderExpr({ ref: path.ref.slice(1) }, env)}`;
|
|
697
754
|
|
|
698
755
|
return result;
|
|
699
756
|
}
|
|
@@ -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) {
|
|
@@ -755,17 +812,19 @@ function csnToCdl(csn, options) {
|
|
|
755
812
|
result += env.indent;
|
|
756
813
|
|
|
757
814
|
// only if column is virtual, keyword virtual was present in the source text
|
|
758
|
-
|
|
759
|
-
|
|
815
|
+
result += col.virtual ? 'virtual ' : '';
|
|
816
|
+
result += col.key ? 'key ' : '';
|
|
760
817
|
|
|
761
|
-
const key = col.key ? 'key ' : '';
|
|
762
818
|
// Use special rendering for .expand/.inline - renderExpr cannot easily handle some cases
|
|
763
|
-
|
|
819
|
+
if (col.expand || col.inline)
|
|
820
|
+
result += renderInlineExpand(col, env);
|
|
821
|
+
else
|
|
822
|
+
result += exprRenderer.renderExpr(withoutCast(col), env);
|
|
764
823
|
|
|
765
824
|
// Alias for inline/expand is already handled by renderInlineExpand
|
|
766
825
|
// A new association (cast with `type` and `target`) uses `as` as its primary name, not alias.
|
|
767
|
-
const isNewAssociation = col.cast
|
|
768
|
-
if (col.as && !col.inline && !col.expand
|
|
826
|
+
const isNewAssociation = col.cast?.type && col.cast.target;
|
|
827
|
+
if (!isNewAssociation && col.as && !col.inline && !col.expand)
|
|
769
828
|
result += ` as ${quoteIdIfRequired(col.as)}`;
|
|
770
829
|
|
|
771
830
|
// Explicit type provided for the view element?
|
|
@@ -787,9 +846,9 @@ function csnToCdl(csn, options) {
|
|
|
787
846
|
* @param {CdlRenderEnvironment} env
|
|
788
847
|
* @returns {string}
|
|
789
848
|
*/
|
|
790
|
-
function renderInlineExpand(obj, env) {
|
|
849
|
+
function renderInlineExpand( obj, env ) {
|
|
791
850
|
// No expression to render for { * } as alias
|
|
792
|
-
let result = (obj.as && obj.expand && !obj.ref) ? '' : renderExpr(obj, env);
|
|
851
|
+
let result = (obj.as && obj.expand && !obj.ref) ? '' : exprRenderer.renderExpr(withoutCast(obj), env);
|
|
793
852
|
|
|
794
853
|
// s as alias { * }
|
|
795
854
|
if (obj.as && (obj.ref || obj.xpr || obj.val !== undefined || obj.func !== undefined))
|
|
@@ -812,11 +871,9 @@ function csnToCdl(csn, options) {
|
|
|
812
871
|
// Drill down and render children of the expand/inline
|
|
813
872
|
const childEnv = increaseIndent(env);
|
|
814
873
|
const expandInline = obj.expand || obj.inline;
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
result += ',\n';
|
|
819
|
-
});
|
|
874
|
+
result += expandInline //
|
|
875
|
+
.map(elm => renderAnnotationAssignmentsAndDocComment(elm, childEnv) + childEnv.indent + renderInlineExpand(elm, childEnv))
|
|
876
|
+
.join(',\n');
|
|
820
877
|
result += `\n${env.indent}}`;
|
|
821
878
|
|
|
822
879
|
// Don't forget about the .excluding
|
|
@@ -837,7 +894,7 @@ function csnToCdl(csn, options) {
|
|
|
837
894
|
* @param {CdlRenderEnvironment} env
|
|
838
895
|
* @returns {String}
|
|
839
896
|
*/
|
|
840
|
-
function renderDocComment(obj, env) {
|
|
897
|
+
function renderDocComment( obj, env ) {
|
|
841
898
|
if (!obj || obj && obj.doc === undefined)
|
|
842
899
|
return '';
|
|
843
900
|
else if (obj && obj.doc === null) // empty doc comment needs to be rendered
|
|
@@ -853,15 +910,11 @@ function csnToCdl(csn, options) {
|
|
|
853
910
|
}
|
|
854
911
|
|
|
855
912
|
/**
|
|
856
|
-
* Render a view. If '$syntax' is set (to 'projection', 'view', 'entity'),
|
|
857
|
-
* the view query is rendered in the requested syntax style, otherwise it
|
|
858
|
-
* is rendered as a view.
|
|
859
|
-
*
|
|
860
913
|
* @param {string} artifactName
|
|
861
914
|
* @param {CSN.Artifact} art
|
|
862
915
|
* @param {CdlRenderEnvironment} env
|
|
863
916
|
*/
|
|
864
|
-
function renderView(artifactName, art, env) {
|
|
917
|
+
function renderView( artifactName, art, env ) {
|
|
865
918
|
const syntax = (art.projection) ? 'projection' : 'entity';
|
|
866
919
|
let result = renderAnnotationAssignmentsAndDocComment(art, env);
|
|
867
920
|
result += `${env.indent}entity ${renderArtifactName(artifactName)}`;
|
|
@@ -891,7 +944,7 @@ function csnToCdl(csn, options) {
|
|
|
891
944
|
* @param {CSN.Path} [path=[]]
|
|
892
945
|
* @param {object} [elements]
|
|
893
946
|
*/
|
|
894
|
-
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) ) {
|
|
895
948
|
if (query.SET) {
|
|
896
949
|
// Set operator, such as UNION, INTERSECT, or EXCEPT...
|
|
897
950
|
return renderQuerySet();
|
|
@@ -937,13 +990,13 @@ function csnToCdl(csn, options) {
|
|
|
937
990
|
result += renderActionsAndFunctions(query, env);
|
|
938
991
|
|
|
939
992
|
if (select.where)
|
|
940
|
-
result += `${continueIndent(result, env)}where ${renderExpr(select.where, env
|
|
993
|
+
result += `${continueIndent(result, env)}where ${exprRenderer.renderExpr(select.where, env)}`;
|
|
941
994
|
|
|
942
995
|
if (select.groupBy)
|
|
943
|
-
result += `${continueIndent(result, env)}group by ${select.groupBy.map(expr => renderExpr(expr, env
|
|
996
|
+
result += `${continueIndent(result, env)}group by ${select.groupBy.map(expr => exprRenderer.renderExpr(expr, env)).join(', ')}`;
|
|
944
997
|
|
|
945
998
|
if (select.having)
|
|
946
|
-
result += `${continueIndent(result, env)}having ${renderExpr(select.having, env
|
|
999
|
+
result += `${continueIndent(result, env)}having ${exprRenderer.renderExpr(select.having, env)}`;
|
|
947
1000
|
|
|
948
1001
|
if (select.orderBy)
|
|
949
1002
|
result += `${continueIndent(result, env)}order by ${select.orderBy.map(entry => renderOrderByEntry(entry, env)).join(', ')}`;
|
|
@@ -960,7 +1013,7 @@ function csnToCdl(csn, options) {
|
|
|
960
1013
|
* @param {CdlRenderEnvironment} indentEnv
|
|
961
1014
|
* @return {string}
|
|
962
1015
|
*/
|
|
963
|
-
function continueIndent(str, indentEnv) {
|
|
1016
|
+
function continueIndent( str, indentEnv ) {
|
|
964
1017
|
if (str.endsWith('}') || str.endsWith('})')) {
|
|
965
1018
|
// The preceding clause ended with '}', just append after that
|
|
966
1019
|
return ' ';
|
|
@@ -976,14 +1029,14 @@ function csnToCdl(csn, options) {
|
|
|
976
1029
|
* @param {CdlRenderEnvironment} limitEnv
|
|
977
1030
|
* @return {string}
|
|
978
1031
|
*/
|
|
979
|
-
function renderLimit(limit, limitEnv) {
|
|
1032
|
+
function renderLimit( limit, limitEnv ) {
|
|
980
1033
|
let limitStr = '';
|
|
981
1034
|
if (limit.rows !== undefined)
|
|
982
|
-
limitStr += `limit ${renderExpr(limit.rows, limitEnv)}`;
|
|
1035
|
+
limitStr += `limit ${exprRenderer.renderExpr(limit.rows, limitEnv)}`;
|
|
983
1036
|
|
|
984
1037
|
if (limit.offset !== undefined) {
|
|
985
1038
|
const offsetIndent = (limitStr === '') ? '' : `\n${increaseIndent(limitEnv).indent}`;
|
|
986
|
-
limitStr += `${offsetIndent}offset ${renderExpr(limit.offset, limitEnv)}`;
|
|
1039
|
+
limitStr += `${offsetIndent}offset ${exprRenderer.renderExpr(limit.offset, limitEnv)}`;
|
|
987
1040
|
}
|
|
988
1041
|
return limitStr;
|
|
989
1042
|
}
|
|
@@ -1020,8 +1073,8 @@ function csnToCdl(csn, options) {
|
|
|
1020
1073
|
* @param {CdlRenderEnvironment} env
|
|
1021
1074
|
* @return {string}
|
|
1022
1075
|
*/
|
|
1023
|
-
function renderOrderByEntry(entry, env) {
|
|
1024
|
-
let result = renderAnnotationAssignmentsAndDocComment(entry, env) + renderExpr(entry, env
|
|
1076
|
+
function renderOrderByEntry( entry, env ) {
|
|
1077
|
+
let result = renderAnnotationAssignmentsAndDocComment(entry, env) + exprRenderer.renderExpr(entry, env);
|
|
1025
1078
|
if (entry.sort)
|
|
1026
1079
|
result += ` ${entry.sort}`;
|
|
1027
1080
|
|
|
@@ -1041,7 +1094,7 @@ function csnToCdl(csn, options) {
|
|
|
1041
1094
|
* @param {CdlRenderEnvironment} env
|
|
1042
1095
|
* @return {string}
|
|
1043
1096
|
*/
|
|
1044
|
-
function renderActionsAndFunctions(art, env) {
|
|
1097
|
+
function renderActionsAndFunctions( art, env ) {
|
|
1045
1098
|
let result = '';
|
|
1046
1099
|
const childEnv = increaseIndent(env);
|
|
1047
1100
|
for (const name in art.actions)
|
|
@@ -1062,7 +1115,7 @@ function csnToCdl(csn, options) {
|
|
|
1062
1115
|
* @param {CdlRenderEnvironment} env
|
|
1063
1116
|
* @return {string}
|
|
1064
1117
|
*/
|
|
1065
|
-
function renderActionOrFunction(actionName, act, env) {
|
|
1118
|
+
function renderActionOrFunction( actionName, act, env ) {
|
|
1066
1119
|
let result = renderAnnotationAssignmentsAndDocComment(act, env) + env.indent + act.kind;
|
|
1067
1120
|
result += ` ${renderArtifactName(actionName)}`;
|
|
1068
1121
|
result += renderParameters(act, env);
|
|
@@ -1084,7 +1137,7 @@ function csnToCdl(csn, options) {
|
|
|
1084
1137
|
* @param {CdlRenderEnvironment} env
|
|
1085
1138
|
* @returns {string}
|
|
1086
1139
|
*/
|
|
1087
|
-
function renderParameters(art, env) {
|
|
1140
|
+
function renderParameters( art, env ) {
|
|
1088
1141
|
const childEnv = increaseIndent(env);
|
|
1089
1142
|
const parameters = Object.keys(art.params || {}).map(name => renderParameter(name, art.params[name], childEnv));
|
|
1090
1143
|
if (parameters.length === 0)
|
|
@@ -1100,7 +1153,7 @@ function csnToCdl(csn, options) {
|
|
|
1100
1153
|
* @param {CdlRenderEnvironment} env
|
|
1101
1154
|
* @return {string}
|
|
1102
1155
|
*/
|
|
1103
|
-
function renderParameter(parName, par, env) {
|
|
1156
|
+
function renderParameter( parName, par, env ) {
|
|
1104
1157
|
env = envAddPath(env, [ 'params', parName ]);
|
|
1105
1158
|
let result = `${renderAnnotationAssignmentsAndDocComment(par, env)}${env.indent}`;
|
|
1106
1159
|
result += `${quoteIdIfRequired(parName)} : ${renderTypeReferenceAndProps(par, env)}`;
|
|
@@ -1117,7 +1170,7 @@ function csnToCdl(csn, options) {
|
|
|
1117
1170
|
* @param {String} [artType] - used for rendering csn.vocabularies, as the annotations there do not have a kind.
|
|
1118
1171
|
* @return {string}
|
|
1119
1172
|
*/
|
|
1120
|
-
function renderTypeOrAnnotation(artifactName, art, env, artType) {
|
|
1173
|
+
function renderTypeOrAnnotation( artifactName, art, env, artType ) {
|
|
1121
1174
|
let result = renderAnnotationAssignmentsAndDocComment(art, env);
|
|
1122
1175
|
result += `${env.indent + (artType || art.$syntax || art.kind )} ${renderArtifactName(artifactName)}`;
|
|
1123
1176
|
if (art.includes)
|
|
@@ -1142,7 +1195,7 @@ function csnToCdl(csn, options) {
|
|
|
1142
1195
|
* - `noAnnoCollect` Do not collect annotations of sub-elements.
|
|
1143
1196
|
* @return {string}
|
|
1144
1197
|
*/
|
|
1145
|
-
function renderTypeReferenceAndProps(artifact, env, config = {}) {
|
|
1198
|
+
function renderTypeReferenceAndProps( artifact, env, config = {} ) {
|
|
1146
1199
|
let result = '';
|
|
1147
1200
|
const { typeRefOnly, noAnnoCollect } = config;
|
|
1148
1201
|
let isTypeDef = env.path?.length === 2; // e.g [ 'definitions', typeDef ];
|
|
@@ -1195,8 +1248,7 @@ function csnToCdl(csn, options) {
|
|
|
1195
1248
|
|
|
1196
1249
|
// ON-condition (if any)
|
|
1197
1250
|
if (artifact.on)
|
|
1198
|
-
result += ` on ${renderExpr(artifact.on, env
|
|
1199
|
-
|
|
1251
|
+
result += ` on ${exprRenderer.renderExpr(artifact.on, env)}`;
|
|
1200
1252
|
|
|
1201
1253
|
// Foreign keys (if any, unless we also have an ON_condition (which means we have been transformed from managed to unmanaged)
|
|
1202
1254
|
if (artifact.keys && !artifact.on)
|
|
@@ -1237,7 +1289,7 @@ function csnToCdl(csn, options) {
|
|
|
1237
1289
|
if (!isTypeDef) // NOT NULL not possible for not-arrayed type definitions
|
|
1238
1290
|
result += renderNullability(artifact);
|
|
1239
1291
|
if (artifact.default)
|
|
1240
|
-
result += ` default ${renderExpr(artifact.default, env)}`;
|
|
1292
|
+
result += ` default ${exprRenderer.renderExpr(artifact.default, env)}`;
|
|
1241
1293
|
|
|
1242
1294
|
return result;
|
|
1243
1295
|
}
|
|
@@ -1249,10 +1301,10 @@ function csnToCdl(csn, options) {
|
|
|
1249
1301
|
* @param {CdlRenderEnvironment} env
|
|
1250
1302
|
* @return {string}
|
|
1251
1303
|
*/
|
|
1252
|
-
function renderRedirectedTo(art, env) {
|
|
1253
|
-
let result = `redirected to ${
|
|
1304
|
+
function renderRedirectedTo( art, env ) {
|
|
1305
|
+
let result = `redirected to ${renderDefinitionReference(art.target)}`;
|
|
1254
1306
|
if (art.on)
|
|
1255
|
-
result += ` on ${renderExpr(art.on, env
|
|
1307
|
+
result += ` on ${exprRenderer.renderExpr(art.on, env)}`;
|
|
1256
1308
|
else if (art.keys)
|
|
1257
1309
|
result += ` { ${Object.keys(art.keys).map(name => renderForeignKey(art.keys[name], env)).join(', ')} }`;
|
|
1258
1310
|
return result;
|
|
@@ -1263,19 +1315,22 @@ function csnToCdl(csn, options) {
|
|
|
1263
1315
|
* @param {CSN.Artifact} artWithType
|
|
1264
1316
|
* @return {string}
|
|
1265
1317
|
*/
|
|
1266
|
-
function renderNamedTypeWithParameters(artWithType) {
|
|
1318
|
+
function renderNamedTypeWithParameters( artWithType ) {
|
|
1267
1319
|
let result = '';
|
|
1268
1320
|
|
|
1269
1321
|
if (isBuiltinType(artWithType.type)) {
|
|
1270
|
-
// If there is a user-defined type with the same short name
|
|
1271
|
-
// we render the full name, including the leading "cds."
|
|
1272
|
-
|
|
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))
|
|
1273
1328
|
result += artWithType.type;
|
|
1274
1329
|
else
|
|
1275
|
-
result +=
|
|
1330
|
+
result += shortHand;
|
|
1276
1331
|
}
|
|
1277
1332
|
else {
|
|
1278
|
-
result +=
|
|
1333
|
+
result += renderDefinitionReference(artWithType.type);
|
|
1279
1334
|
}
|
|
1280
1335
|
|
|
1281
1336
|
result += renderTypeParameters(artWithType);
|
|
@@ -1290,35 +1345,15 @@ function csnToCdl(csn, options) {
|
|
|
1290
1345
|
* @param {CdlRenderEnvironment} env
|
|
1291
1346
|
* @return {string}
|
|
1292
1347
|
*/
|
|
1293
|
-
function renderEnum(enumPart, env) {
|
|
1348
|
+
function renderEnum( enumPart, env ) {
|
|
1294
1349
|
let result = ' enum {\n';
|
|
1295
1350
|
const childEnv = increaseIndent(env);
|
|
1296
1351
|
for (const name in enumPart)
|
|
1297
|
-
result +=
|
|
1352
|
+
result += renderElement(name, enumPart[name], childEnv);
|
|
1298
1353
|
result += `${env.indent}}`;
|
|
1299
1354
|
return result;
|
|
1300
1355
|
}
|
|
1301
1356
|
|
|
1302
|
-
/**
|
|
1303
|
-
* Render the element of a `<type> enum {}` structure.
|
|
1304
|
-
*
|
|
1305
|
-
* @param {string} name
|
|
1306
|
-
* @param {CSN.EnumValue} enumValue
|
|
1307
|
-
* @param {CdlRenderEnvironment} env
|
|
1308
|
-
* @return {string}
|
|
1309
|
-
*/
|
|
1310
|
-
function renderEnumElement(name, enumValue, env) {
|
|
1311
|
-
let result = '';
|
|
1312
|
-
result += renderAnnotationAssignmentsAndDocComment(enumValue, env);
|
|
1313
|
-
result += env.indent + quoteIdIfRequired(name);
|
|
1314
|
-
if (enumValue.val !== undefined)
|
|
1315
|
-
result += ` = ${renderExpr(enumValue, env)}`;
|
|
1316
|
-
else if (enumValue['#'] !== undefined)
|
|
1317
|
-
result += ` = #${enumValue['#']}`;
|
|
1318
|
-
result += ';\n';
|
|
1319
|
-
return result;
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
1357
|
/**
|
|
1323
1358
|
* Render an annotation value (somewhat like a simplified expression, with slightly different
|
|
1324
1359
|
* representation)
|
|
@@ -1326,7 +1361,7 @@ function csnToCdl(csn, options) {
|
|
|
1326
1361
|
* @param {any} x
|
|
1327
1362
|
* @param {CdlRenderEnvironment} env
|
|
1328
1363
|
*/
|
|
1329
|
-
function renderAnnotationValue(x, env) {
|
|
1364
|
+
function renderAnnotationValue( x, env ) {
|
|
1330
1365
|
if (Array.isArray(x)) {
|
|
1331
1366
|
// Render array parts as values. Spaces required if last array value is
|
|
1332
1367
|
// a delimited identifier.
|
|
@@ -1373,11 +1408,10 @@ function csnToCdl(csn, options) {
|
|
|
1373
1408
|
*
|
|
1374
1409
|
* @param {string|object} s
|
|
1375
1410
|
* @param {number} idx
|
|
1376
|
-
* @param {boolean} inline
|
|
1377
1411
|
* @param {object} env
|
|
1378
1412
|
* @returns {string}
|
|
1379
1413
|
*/
|
|
1380
|
-
function renderPathStep(s, idx,
|
|
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.
|
|
@@ -1405,7 +1439,7 @@ function csnToCdl(csn, options) {
|
|
|
1405
1439
|
if (s.where) {
|
|
1406
1440
|
// Filter, possibly with cardinality
|
|
1407
1441
|
const cardinality = s.cardinality ? (`${s.cardinality.max}: `) : '';
|
|
1408
|
-
const expr = renderExpr(s.where, env
|
|
1442
|
+
const expr = exprRenderer.renderExpr(s.where, env);
|
|
1409
1443
|
result += `[${cardinality}${expr}]`;
|
|
1410
1444
|
}
|
|
1411
1445
|
|
|
@@ -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,11 +1511,13 @@ 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
|
-
// For nested xpr, `renderExpr()` will already add parentheses.
|
|
1516
|
+
// For nested xpr, `exprRenderer.renderExpr()` will already add parentheses.
|
|
1483
1517
|
env = { ...env, additionalKeywords };
|
|
1484
|
-
|
|
1518
|
+
if (isSimpleFunctionExpression(arg && arg.xpr, additionalKeywords))
|
|
1519
|
+
return exprRenderer.renderExpr(arg, env);
|
|
1520
|
+
return exprRenderer.renderSubExpr(arg, env);
|
|
1485
1521
|
}
|
|
1486
1522
|
|
|
1487
1523
|
/**
|
|
@@ -1490,7 +1526,7 @@ function csnToCdl(csn, options) {
|
|
|
1490
1526
|
* @param artifact
|
|
1491
1527
|
* @returns {string}
|
|
1492
1528
|
*/
|
|
1493
|
-
function renderCardinality(artifact) {
|
|
1529
|
+
function renderCardinality( artifact ) {
|
|
1494
1530
|
if (isSimpleCardinality(artifact.cardinality))
|
|
1495
1531
|
return renderSimpleCardinality(artifact);
|
|
1496
1532
|
return renderBracketCardinality(artifact);
|
|
@@ -1502,7 +1538,7 @@ function csnToCdl(csn, options) {
|
|
|
1502
1538
|
* @param {CSN.Artifact} art
|
|
1503
1539
|
* @return {string}
|
|
1504
1540
|
*/
|
|
1505
|
-
function renderBracketCardinality(art) {
|
|
1541
|
+
function renderBracketCardinality( art ) {
|
|
1506
1542
|
const isComp = art.type === 'cds.Composition';
|
|
1507
1543
|
const suffix = (isComp ? ' of ' : ' to ');
|
|
1508
1544
|
const card = art.cardinality;
|
|
@@ -1530,7 +1566,7 @@ function csnToCdl(csn, options) {
|
|
|
1530
1566
|
* @param {CSN.Cardinality} cardinality
|
|
1531
1567
|
* @return {boolean}
|
|
1532
1568
|
*/
|
|
1533
|
-
function isSimpleCardinality(cardinality) {
|
|
1569
|
+
function isSimpleCardinality( cardinality ) {
|
|
1534
1570
|
return !cardinality || (
|
|
1535
1571
|
cardinality.min === undefined &&
|
|
1536
1572
|
cardinality.src === undefined &&
|
|
@@ -1546,7 +1582,7 @@ function csnToCdl(csn, options) {
|
|
|
1546
1582
|
* @param {CSN.Element} elem
|
|
1547
1583
|
* @return {string}
|
|
1548
1584
|
*/
|
|
1549
|
-
function renderSimpleCardinality(elem) {
|
|
1585
|
+
function renderSimpleCardinality( elem ) {
|
|
1550
1586
|
let result = (elem.type === 'cds.Association' ? ' to ' : ' of ');
|
|
1551
1587
|
if (!elem.cardinality)
|
|
1552
1588
|
return result;
|
|
@@ -1558,7 +1594,7 @@ function csnToCdl(csn, options) {
|
|
|
1558
1594
|
}
|
|
1559
1595
|
|
|
1560
1596
|
// Render the nullability of an element or parameter (can be unset, true, or false)
|
|
1561
|
-
function renderNullability(obj /* , env */) {
|
|
1597
|
+
function renderNullability( obj /* , env */) {
|
|
1562
1598
|
if (obj.notNull === undefined) {
|
|
1563
1599
|
// Attribute not set at all
|
|
1564
1600
|
return '';
|
|
@@ -1573,9 +1609,9 @@ function csnToCdl(csn, options) {
|
|
|
1573
1609
|
* @param {CdlRenderEnvironment} env
|
|
1574
1610
|
* @return {string}
|
|
1575
1611
|
*/
|
|
1576
|
-
function renderForeignKey(fKey, env) {
|
|
1612
|
+
function renderForeignKey( fKey, env ) {
|
|
1577
1613
|
const alias = fKey.as ? (` as ${fKey.as}`) : '';
|
|
1578
|
-
return renderExpr(fKey, env) + alias;
|
|
1614
|
+
return exprRenderer.renderExpr(fKey, env) + alias;
|
|
1579
1615
|
}
|
|
1580
1616
|
|
|
1581
1617
|
/**
|
|
@@ -1583,18 +1619,22 @@ function csnToCdl(csn, options) {
|
|
|
1583
1619
|
* length, precision and scale (even if incomplete), plus any other unknown ones.
|
|
1584
1620
|
*
|
|
1585
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)`.
|
|
1586
1624
|
* @returns {string}
|
|
1587
1625
|
*/
|
|
1588
|
-
function renderTypeParameters(artWithType) {
|
|
1626
|
+
function renderTypeParameters( artWithType, noShortVersion = false ) {
|
|
1589
1627
|
const params = typeParameters.list.filter(param => artWithType[param] !== undefined);
|
|
1590
1628
|
if (params.length === 0)
|
|
1591
1629
|
return '';
|
|
1592
1630
|
|
|
1631
|
+
if (!noShortVersion) {
|
|
1593
1632
|
// Special cases for 1 or 2 arguments.
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
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
|
+
}
|
|
1598
1638
|
|
|
1599
1639
|
// Render named params
|
|
1600
1640
|
const renderedParams = [];
|
|
@@ -1612,7 +1652,7 @@ function csnToCdl(csn, options) {
|
|
|
1612
1652
|
* @param {{parens: boolean}} [config] Config for renderAnnotationAssignment()
|
|
1613
1653
|
* @return {string}
|
|
1614
1654
|
*/
|
|
1615
|
-
function renderAnnotationAssignmentsAndDocComment(obj, env, config) {
|
|
1655
|
+
function renderAnnotationAssignmentsAndDocComment( obj, env, config ) {
|
|
1616
1656
|
let result = renderDocComment(obj, env);
|
|
1617
1657
|
for (const name in obj) {
|
|
1618
1658
|
if (name.startsWith('@'))
|
|
@@ -1632,7 +1672,7 @@ function csnToCdl(csn, options) {
|
|
|
1632
1672
|
* @param {object} [config] parens: Whether the annotation assignment must be surrounded by parentheses.
|
|
1633
1673
|
* @return {string} Rendered annotation, possibly quoted: `@![A.B.C#foo.C]: value`
|
|
1634
1674
|
*/
|
|
1635
|
-
function renderAnnotationAssignment(anno, name, env, config = { parens: false }) {
|
|
1675
|
+
function renderAnnotationAssignment( anno, name, env, config = { parens: false } ) {
|
|
1636
1676
|
name = name.substring(1);
|
|
1637
1677
|
// Take the annotation assignment apart into <nameBeforeVariant>#<variantAndRest>
|
|
1638
1678
|
const parts = name.split('#');
|
|
@@ -1671,104 +1711,91 @@ function csnToCdl(csn, options) {
|
|
|
1671
1711
|
* @param {string} artifactName Artifact name to render
|
|
1672
1712
|
* @return {string} Artifact name ready for rendering
|
|
1673
1713
|
*/
|
|
1674
|
-
function renderArtifactName(artifactName) {
|
|
1714
|
+
function renderArtifactName( artifactName ) {
|
|
1675
1715
|
return quotePathIfRequired(artifactName);
|
|
1676
1716
|
}
|
|
1677
1717
|
|
|
1678
1718
|
/**
|
|
1679
|
-
* Render a
|
|
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.
|
|
1680
1721
|
*
|
|
1681
|
-
* @param {
|
|
1682
|
-
* @
|
|
1683
|
-
* @returns {string}
|
|
1722
|
+
* @param {string} name
|
|
1723
|
+
* @return {string}
|
|
1684
1724
|
*/
|
|
1685
|
-
function
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
const name = identifierRegex.test(obj.func) ? obj.func : quote(obj.func);
|
|
1689
|
-
return `${name}(${renderArguments( obj, '=>', env )})`;
|
|
1725
|
+
function renderDefinitionReference( name ) {
|
|
1726
|
+
usings.addIfRequired(name);
|
|
1727
|
+
return quotePathIfRequired(name);
|
|
1690
1728
|
}
|
|
1691
1729
|
|
|
1692
1730
|
/**
|
|
1693
|
-
*
|
|
1694
|
-
*
|
|
1695
|
-
* @param {any} expr
|
|
1696
|
-
* @param {CdlRenderEnvironment} exprEnv
|
|
1697
|
-
* @param {boolean} [isInline]
|
|
1698
|
-
* @param {boolean} [isNestedExpr]
|
|
1699
|
-
* @param {boolean} [alwaysRenderCast]
|
|
1700
|
-
* @returns {string}
|
|
1731
|
+
* @param {string[]} includes
|
|
1732
|
+
* @return {string}
|
|
1701
1733
|
*/
|
|
1702
|
-
function
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
finalize(x) {
|
|
1706
|
-
return x;
|
|
1707
|
-
},
|
|
1708
|
-
explicitTypeCast(x, env) {
|
|
1709
|
-
const typeRef = renderTypeReferenceAndProps(x.cast, env, { typeRefOnly: true, noAnnoCollect: true });
|
|
1710
|
-
const arg = { ...x, cast: null }; // "arg" without cast to avoid recursion.
|
|
1711
|
-
return `cast(${renderArgument(arg, env)} as ${typeRef})`;
|
|
1712
|
-
},
|
|
1713
|
-
val(x, env) {
|
|
1714
|
-
// Literal value, possibly with explicit 'literal' property
|
|
1715
|
-
switch (x.literal || typeof x.val) {
|
|
1716
|
-
case 'number':
|
|
1717
|
-
case 'boolean':
|
|
1718
|
-
case 'null':
|
|
1719
|
-
return x.val;
|
|
1720
|
-
case 'x':
|
|
1721
|
-
case 'date':
|
|
1722
|
-
case 'time':
|
|
1723
|
-
case 'timestamp':
|
|
1724
|
-
return `${x.literal}'${x.val}'`;
|
|
1725
|
-
case 'string':
|
|
1726
|
-
return renderString(x.val, env);
|
|
1727
|
-
case 'object':
|
|
1728
|
-
if (x.val === null)
|
|
1729
|
-
return 'null';
|
|
1730
|
-
// otherwise fall through to
|
|
1731
|
-
default:
|
|
1732
|
-
throw new ModelError(`Unknown literal or type: ${JSON.stringify(x)}`);
|
|
1733
|
-
}
|
|
1734
|
-
},
|
|
1735
|
-
aliasOnly(x, _env) {
|
|
1736
|
-
return x.as;
|
|
1737
|
-
},
|
|
1738
|
-
enum(x) {
|
|
1739
|
-
return `#${x['#']}`;
|
|
1740
|
-
},
|
|
1741
|
-
ref(x, env) {
|
|
1742
|
-
const { inline } = this;
|
|
1743
|
-
return `${(x.param || x.global) ? ':' : ''}${x.ref.map((step, index) => renderPathStep(step, index, inline, env)).join('.')}`;
|
|
1744
|
-
},
|
|
1745
|
-
windowFunction(x, env) {
|
|
1746
|
-
const funcDef = renderFuncExpr(x, env);
|
|
1747
|
-
const windowFunctionOperator = x.xpr.shift(); // OVER ...
|
|
1748
|
-
return `${funcDef} ${windowFunctionOperator} ( ${renderExpr(x.xpr, env, true)} )`;
|
|
1749
|
-
},
|
|
1750
|
-
func(x, env) {
|
|
1751
|
-
return renderFuncExpr(x, env);
|
|
1752
|
-
},
|
|
1753
|
-
xpr(x, env) {
|
|
1754
|
-
if (this.nestedExpr && !x.cast || x.xpr.some(s => s === 'exists'))
|
|
1755
|
-
return `(${renderExpr(x.xpr, env, this.inline, true)})`;
|
|
1756
|
-
return renderExpr(x.xpr, env, this.inline, true);
|
|
1757
|
-
},
|
|
1758
|
-
// Sub-queries in expressions need to be in parentheses, otherwise
|
|
1759
|
-
// left-associativity of UNIONS may result in different results.
|
|
1760
|
-
// For example: `select from E where id in (select from E union select from E);`:
|
|
1761
|
-
// Without parentheses, it would be different query.
|
|
1762
|
-
SET(x, env) {
|
|
1763
|
-
return `(${renderQuery(x, false, 'view', increaseIndent(env))})`;
|
|
1764
|
-
},
|
|
1765
|
-
SELECT(x, env) {
|
|
1766
|
-
return `(${renderQuery(x, false, 'view', increaseIndent(env))})`;
|
|
1767
|
-
},
|
|
1768
|
-
});
|
|
1769
|
-
}
|
|
1734
|
+
function renderIncludes( includes ) {
|
|
1735
|
+
return ` : ${includes.map(name => renderDefinitionReference(name)).join(', ')}`;
|
|
1736
|
+
}
|
|
1770
1737
|
|
|
1771
|
-
|
|
1738
|
+
function createCdlExpressionRenderer() {
|
|
1739
|
+
return createExpressionRenderer({
|
|
1740
|
+
finalize: x => x,
|
|
1741
|
+
typeCast(x) {
|
|
1742
|
+
const typeRef = renderTypeReferenceAndProps(x.cast, this.env, { typeRefOnly: true, noAnnoCollect: true });
|
|
1743
|
+
const arg = { ...x, cast: null }; // "arg" without cast to avoid recursion.
|
|
1744
|
+
return `cast(${renderArgument(arg, this.env)} as ${typeRef})`;
|
|
1745
|
+
},
|
|
1746
|
+
val(x) {
|
|
1747
|
+
// Literal value, possibly with explicit 'literal' property
|
|
1748
|
+
switch (x.literal || typeof x.val) {
|
|
1749
|
+
case 'number':
|
|
1750
|
+
case 'boolean':
|
|
1751
|
+
case 'null':
|
|
1752
|
+
return x.val;
|
|
1753
|
+
case 'x':
|
|
1754
|
+
case 'date':
|
|
1755
|
+
case 'time':
|
|
1756
|
+
case 'timestamp':
|
|
1757
|
+
return `${x.literal}'${x.val}'`;
|
|
1758
|
+
case 'string':
|
|
1759
|
+
return renderString(x.val, this.env);
|
|
1760
|
+
case 'object':
|
|
1761
|
+
if (x.val === null)
|
|
1762
|
+
return 'null';
|
|
1763
|
+
// otherwise fall through to
|
|
1764
|
+
default:
|
|
1765
|
+
throw new ModelError(`Unknown literal or type: ${JSON.stringify(x)}`);
|
|
1766
|
+
}
|
|
1767
|
+
},
|
|
1768
|
+
aliasOnly: x => x.as,
|
|
1769
|
+
enum: x => `#${x['#']}`,
|
|
1770
|
+
ref(x) {
|
|
1771
|
+
return `${(x.param || x.global) ? ':' : ''}${x.ref.map((step, index) => renderPathStep(step, index, this.env)).join('.')}`;
|
|
1772
|
+
},
|
|
1773
|
+
windowFunction(x) {
|
|
1774
|
+
const funcDef = this.func(x);
|
|
1775
|
+
return `${funcDef} ${this.renderExpr(x.xpr)}`; // xpr[0] is 'over'
|
|
1776
|
+
},
|
|
1777
|
+
func(x) {
|
|
1778
|
+
if (keywords.cdl_functions.includes(x.func.toUpperCase()))
|
|
1779
|
+
return x.func;
|
|
1780
|
+
const name = identifierRegex.test(x.func) ? x.func : quote(x.func);
|
|
1781
|
+
return `${name}(${renderArguments( x, '=>', this.env )})`;
|
|
1782
|
+
},
|
|
1783
|
+
xpr(x) {
|
|
1784
|
+
if (this.isNestedXpr && !x.cast || x.xpr.some(s => s === 'exists'))
|
|
1785
|
+
return `(${this.renderExpr(x.xpr)})`;
|
|
1786
|
+
return this.renderExpr(x.xpr);
|
|
1787
|
+
},
|
|
1788
|
+
// Sub-queries in expressions need to be in parentheses, otherwise
|
|
1789
|
+
// left-associativity of UNIONS may result in different results.
|
|
1790
|
+
// For example: `select from E where id in (select from E union select from E);`:
|
|
1791
|
+
// Without parentheses, it would be different query.
|
|
1792
|
+
SET(x) {
|
|
1793
|
+
return `(${renderQuery(x, false, 'view', increaseIndent(this.env))})`;
|
|
1794
|
+
},
|
|
1795
|
+
SELECT(x) {
|
|
1796
|
+
return `(${renderQuery(x, false, 'view', increaseIndent(this.env))})`;
|
|
1797
|
+
},
|
|
1798
|
+
});
|
|
1772
1799
|
}
|
|
1773
1800
|
}
|
|
1774
1801
|
|
|
@@ -1776,32 +1803,33 @@ function csnToCdl(csn, options) {
|
|
|
1776
1803
|
* Returns a newly created default environment (which keeps track of indentation, required USING
|
|
1777
1804
|
* declarations and name prefixes.
|
|
1778
1805
|
*
|
|
1806
|
+
* @param {object} [values]
|
|
1779
1807
|
* @return {CdlRenderEnvironment}
|
|
1780
1808
|
*/
|
|
1781
|
-
function createEnv() {
|
|
1782
|
-
return {
|
|
1809
|
+
function createEnv( values = {} ) {
|
|
1810
|
+
return Object.assign({
|
|
1783
1811
|
// Current indentation string
|
|
1784
1812
|
indent: '',
|
|
1785
1813
|
path: null,
|
|
1786
1814
|
artifactName: '',
|
|
1787
1815
|
elementName: '',
|
|
1788
|
-
};
|
|
1816
|
+
}, values);
|
|
1789
1817
|
}
|
|
1790
1818
|
|
|
1791
|
-
function envAddPath(env, path) {
|
|
1819
|
+
function envAddPath( env, path ) {
|
|
1792
1820
|
return Object.assign({}, env, { path: [ ...env.path, ...path ] } );
|
|
1793
1821
|
}
|
|
1794
|
-
function envNewPath(env, path) {
|
|
1822
|
+
function envNewPath( env, path ) {
|
|
1795
1823
|
return Object.assign({}, env, { path: [ ...path ] } );
|
|
1796
1824
|
}
|
|
1797
1825
|
|
|
1798
1826
|
/**
|
|
1799
1827
|
* Returns a copy of 'env' with increased indentation (and reset name prefix)
|
|
1800
1828
|
*
|
|
1801
|
-
* @param {
|
|
1802
|
-
* @returns {
|
|
1829
|
+
* @param {object} env
|
|
1830
|
+
* @returns {object}
|
|
1803
1831
|
*/
|
|
1804
|
-
function increaseIndent(env) {
|
|
1832
|
+
function increaseIndent( env ) {
|
|
1805
1833
|
return Object.assign({}, env, { indent: `${env.indent} ` });
|
|
1806
1834
|
}
|
|
1807
1835
|
|
|
@@ -1817,7 +1845,7 @@ function increaseIndent(env) {
|
|
|
1817
1845
|
*
|
|
1818
1846
|
* @todo For paths such as `E.key`, `key` does not have to be in quotes.
|
|
1819
1847
|
*/
|
|
1820
|
-
function quotePathIfRequired(path) {
|
|
1848
|
+
function quotePathIfRequired( path ) {
|
|
1821
1849
|
return path.split('.').map(step => quoteIdIfRequired(step)).join('.');
|
|
1822
1850
|
}
|
|
1823
1851
|
|
|
@@ -1832,7 +1860,7 @@ function quotePathIfRequired(path) {
|
|
|
1832
1860
|
* @param {string[]} [additionalKeywords]
|
|
1833
1861
|
* @return {string}
|
|
1834
1862
|
*/
|
|
1835
|
-
function quoteIdIfRequired(id, additionalKeywords) {
|
|
1863
|
+
function quoteIdIfRequired( id, additionalKeywords ) {
|
|
1836
1864
|
// Quote if required for CDL
|
|
1837
1865
|
if (requiresQuotingForCdl(id, additionalKeywords || []))
|
|
1838
1866
|
return quote(id);
|
|
@@ -1848,7 +1876,7 @@ function quoteIdIfRequired(id, additionalKeywords) {
|
|
|
1848
1876
|
* @param {string} anno
|
|
1849
1877
|
* @returns {string}
|
|
1850
1878
|
*/
|
|
1851
|
-
function quoteAnnotationPathIfRequired(anno) {
|
|
1879
|
+
function quoteAnnotationPathIfRequired( anno ) {
|
|
1852
1880
|
return anno.split('.').map((segment) => {
|
|
1853
1881
|
if (segment.startsWith('@'))
|
|
1854
1882
|
return `@${quoteIdIfRequired(segment.slice(1))}`;
|
|
@@ -1862,7 +1890,7 @@ function quoteAnnotationPathIfRequired(anno) {
|
|
|
1862
1890
|
* @param id
|
|
1863
1891
|
* @returns {string}
|
|
1864
1892
|
*/
|
|
1865
|
-
function quote(id) {
|
|
1893
|
+
function quote( id ) {
|
|
1866
1894
|
return `![${id.replace(/]/g, ']]')}]`;
|
|
1867
1895
|
}
|
|
1868
1896
|
|
|
@@ -1878,7 +1906,7 @@ function quote(id) {
|
|
|
1878
1906
|
* @param {string[]} [additionalKeywords]
|
|
1879
1907
|
* @return {boolean}
|
|
1880
1908
|
*/
|
|
1881
|
-
function requiresQuotingForCdl(id, additionalKeywords) {
|
|
1909
|
+
function requiresQuotingForCdl( id, additionalKeywords ) {
|
|
1882
1910
|
return !identifierRegex.test(id) ||
|
|
1883
1911
|
keywords.cdl.includes(id.toUpperCase()) ||
|
|
1884
1912
|
keywords.cdl_functions.includes(id.toUpperCase()) ||
|
|
@@ -1887,16 +1915,16 @@ function requiresQuotingForCdl(id, additionalKeywords) {
|
|
|
1887
1915
|
|
|
1888
1916
|
const functionExpressionOperatorsRequireParentheses = [
|
|
1889
1917
|
// Antlr rule 'condition', 'conditionAnd'
|
|
1890
|
-
'
|
|
1918
|
+
'AND', 'OR',
|
|
1891
1919
|
|
|
1892
1920
|
// Antlr rule 'conditionTerm'
|
|
1893
1921
|
'=', '<>', '>', '>=', '<', '<=', '!=',
|
|
1894
1922
|
// These are not forbidden, since they must be preceded by one of the comparators above.
|
|
1895
1923
|
// 'any', 'some', 'all',
|
|
1896
1924
|
|
|
1897
|
-
'
|
|
1925
|
+
'IS', 'IN', 'NOT', 'NULL', 'EXISTS',
|
|
1898
1926
|
// Antlr rule 'predicate'
|
|
1899
|
-
'
|
|
1927
|
+
'BETWEEN', 'LIKE', 'ESCAPE',
|
|
1900
1928
|
];
|
|
1901
1929
|
|
|
1902
1930
|
/**
|
|
@@ -1921,10 +1949,10 @@ const functionExpressionOperatorsRequireParentheses = [
|
|
|
1921
1949
|
* @param {string[]} additionalAllowedKeywords
|
|
1922
1950
|
* @return {boolean}
|
|
1923
1951
|
*/
|
|
1924
|
-
function isSimpleFunctionExpression(xpr, additionalAllowedKeywords = []) {
|
|
1952
|
+
function isSimpleFunctionExpression( xpr, additionalAllowedKeywords = [] ) {
|
|
1925
1953
|
return !xpr || xpr.every(val => typeof val !== 'string' ||
|
|
1926
|
-
(additionalAllowedKeywords.includes(val) ||
|
|
1927
|
-
!functionExpressionOperatorsRequireParentheses.includes(val.
|
|
1954
|
+
(additionalAllowedKeywords.includes(val.toUpperCase()) ||
|
|
1955
|
+
!functionExpressionOperatorsRequireParentheses.includes(val.toUpperCase())));
|
|
1928
1956
|
}
|
|
1929
1957
|
|
|
1930
1958
|
/**
|
|
@@ -1938,7 +1966,7 @@ function isSimpleFunctionExpression(xpr, additionalAllowedKeywords = []) {
|
|
|
1938
1966
|
* @param {number} argumentIndex
|
|
1939
1967
|
* @returns {string[]}
|
|
1940
1968
|
*/
|
|
1941
|
-
function getKeywordsForSpecialFunctionArgument(funcName, argumentIndex) {
|
|
1969
|
+
function getKeywordsForSpecialFunctionArgument( funcName, argumentIndex ) {
|
|
1942
1970
|
const f = specialFunctions[funcName] && specialFunctions[funcName][argumentIndex];
|
|
1943
1971
|
if (!f)
|
|
1944
1972
|
return [];
|
|
@@ -1952,14 +1980,6 @@ function getKeywordsForSpecialFunctionArgument(funcName, argumentIndex) {
|
|
|
1952
1980
|
return additionalKeywords;
|
|
1953
1981
|
}
|
|
1954
1982
|
|
|
1955
|
-
/**
|
|
1956
|
-
* @param {string[]} includes
|
|
1957
|
-
* @return {string}
|
|
1958
|
-
*/
|
|
1959
|
-
function renderIncludes(includes) {
|
|
1960
|
-
return ` : ${includes.map(name => quotePathIfRequired(name)).join(', ')}`;
|
|
1961
|
-
}
|
|
1962
|
-
|
|
1963
1983
|
/**
|
|
1964
1984
|
* Render the given string. Uses back-tick strings.
|
|
1965
1985
|
* env is used for indentation of three-back-tick strings.
|
|
@@ -1968,7 +1988,7 @@ function renderIncludes(includes) {
|
|
|
1968
1988
|
* @param env
|
|
1969
1989
|
* @returns {string}
|
|
1970
1990
|
*/
|
|
1971
|
-
function renderString(str, env) {
|
|
1991
|
+
function renderString( str, env ) {
|
|
1972
1992
|
if (isSimpleString(str))
|
|
1973
1993
|
return `'${str.replace(/'/g, '\'\'')}'`;
|
|
1974
1994
|
|
|
@@ -2013,7 +2033,7 @@ function renderString(str, env) {
|
|
|
2013
2033
|
}
|
|
2014
2034
|
|
|
2015
2035
|
/** @param {number} codePoint */
|
|
2016
|
-
function hexEscape(codePoint) {
|
|
2036
|
+
function hexEscape( codePoint ) {
|
|
2017
2037
|
const hex = codePoint.toString(16);
|
|
2018
2038
|
return `\\u{${hex}}`;
|
|
2019
2039
|
}
|
|
@@ -2022,7 +2042,7 @@ function hexEscape(codePoint) {
|
|
|
2022
2042
|
* Returns true if the given string can be represented by using single quotes.
|
|
2023
2043
|
* @param {string} str
|
|
2024
2044
|
*/
|
|
2025
|
-
function isSimpleString(str) {
|
|
2045
|
+
function isSimpleString( str ) {
|
|
2026
2046
|
// A single-line string allows everything except certain line separators/breaks.
|
|
2027
2047
|
// See ANTLR grammar for specifics.
|
|
2028
2048
|
// Furthermore, if control characters are used, we escape them,
|
|
@@ -2034,13 +2054,28 @@ function isSimpleString(str) {
|
|
|
2034
2054
|
!hasUnpairedUnicodeSurrogate(str));
|
|
2035
2055
|
}
|
|
2036
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
|
+
|
|
2037
2071
|
/**
|
|
2038
2072
|
* @typedef CdlRenderEnvironment Rendering environment used throughout the render process.
|
|
2039
2073
|
*
|
|
2040
2074
|
* @property {string} indent Current indentation as a string, e.g. ' ' for two spaces.
|
|
2041
|
-
* @property {
|
|
2075
|
+
* @property {CSN.Path} [path] CSN path to the current artifact
|
|
2042
2076
|
* @property {string} [artifactName] Name of the artifact - set in renderArtifact
|
|
2043
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.
|
|
2044
2079
|
*/
|
|
2045
2080
|
|
|
2046
2081
|
module.exports = { csnToCdl };
|