@sap/cds-compiler 3.8.2 → 3.9.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 +53 -0
- package/bin/cdsc.js +2 -2
- package/doc/CHANGELOG_BETA.md +26 -5
- package/lib/api/.eslintrc.json +3 -2
- package/lib/api/options.js +3 -1
- package/lib/api/validate.js +1 -1
- package/lib/base/message-registry.js +27 -18
- package/lib/base/messages.js +6 -1
- package/lib/base/model.js +2 -2
- package/lib/checks/.eslintrc.json +1 -0
- package/lib/checks/actionsFunctions.js +6 -6
- package/lib/checks/annotationsOData.js +1 -1
- package/lib/checks/elements.js +28 -17
- package/lib/checks/foreignKeys.js +1 -1
- package/lib/checks/invalidTarget.js +1 -1
- package/lib/checks/onConditions.js +11 -6
- package/lib/checks/queryNoDbArtifacts.js +1 -1
- package/lib/checks/types.js +1 -1
- package/lib/checks/utils.js +1 -1
- package/lib/checks/validator.js +3 -2
- package/lib/compiler/assert-consistency.js +7 -2
- package/lib/compiler/base.js +8 -4
- package/lib/compiler/builtins.js +7 -0
- package/lib/compiler/checks.js +73 -6
- package/lib/compiler/define.js +10 -5
- package/lib/compiler/extend.js +910 -1711
- package/lib/compiler/finalize-parse-cdl.js +1 -1
- package/lib/compiler/generate.js +838 -0
- package/lib/compiler/index.js +2 -0
- package/lib/compiler/populate.js +2 -2
- package/lib/compiler/propagator.js +20 -8
- package/lib/compiler/resolve.js +3 -3
- package/lib/compiler/shared.js +3 -1
- package/lib/edm/annotations/genericTranslation.js +6 -6
- package/lib/edm/csn2edm.js +1 -1
- package/lib/edm/edm.js +25 -11
- package/lib/edm/edmPreprocessor.js +47 -23
- package/lib/edm/edmUtils.js +37 -9
- package/lib/gen/Dictionary.json +5 -7
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +3 -1
- package/lib/gen/language.tokens +24 -23
- package/lib/gen/languageLexer.interp +4 -1
- package/lib/gen/languageLexer.js +792 -784
- package/lib/gen/languageLexer.tokens +12 -11
- package/lib/gen/languageParser.js +3564 -3493
- package/lib/json/from-csn.js +26 -4
- package/lib/json/to-csn.js +10 -6
- package/lib/language/antlrParser.js +11 -3
- package/lib/language/genericAntlrParser.js +2 -1
- package/lib/language/language.g4 +14 -3
- package/lib/model/csnRefs.js +10 -5
- package/lib/model/csnUtils.js +41 -76
- package/lib/modelCompare/utils/.eslintrc.json +1 -1
- package/lib/optionProcessor.js +7 -4
- package/lib/render/.eslintrc.json +1 -1
- package/lib/render/toCdl.js +244 -168
- package/lib/render/toHdbcds.js +18 -10
- package/lib/render/toSql.js +24 -2
- package/lib/transform/db/.eslintrc.json +4 -3
- package/lib/transform/db/cdsPersistence.js +1 -1
- package/lib/transform/db/expansion.js +11 -6
- package/lib/transform/db/flattening.js +22 -15
- package/lib/transform/db/rewriteCalculatedElements.js +50 -29
- package/lib/transform/db/temporal.js +1 -1
- package/lib/transform/db/views.js +1 -1
- package/lib/transform/draft/db.js +1 -1
- package/lib/transform/draft/odata.js +3 -4
- package/lib/transform/forOdataNew.js +5 -6
- package/lib/transform/forRelationalDB.js +7 -7
- package/lib/transform/odata/toFinalBaseType.js +6 -6
- package/lib/transform/odata/typesExposure.js +12 -3
- package/lib/transform/odata/utils.js +3 -0
- package/lib/transform/transformUtilsNew.js +11 -26
- package/lib/transform/translateAssocsToJoins.js +9 -9
- package/lib/transform/universalCsn/.eslintrc.json +3 -2
- package/lib/transform/universalCsn/coreComputed.js +1 -1
- package/lib/transform/universalCsn/universalCsnEnricher.js +6 -4
- package/package.json +1 -1
package/lib/render/toCdl.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const keywords = require('../base/keywords');
|
|
4
|
+
const { cdlNewLineRegEx } = require('../language/textUtils');
|
|
4
5
|
const { findElement, createExpressionRenderer, withoutCast } = require('./utils/common');
|
|
5
6
|
const { escapeString, hasUnpairedUnicodeSurrogate } = require('./utils/stringEscapes');
|
|
6
7
|
const { checkCSNVersion } = require('../json/csnVersion');
|
|
@@ -79,7 +80,7 @@ function csnToCdl( csn, options ) {
|
|
|
79
80
|
cdlResult.model += renderExtensions(csn.extensions, createEnv());
|
|
80
81
|
|
|
81
82
|
if (csn.namespace) {
|
|
82
|
-
cdlResult.namespace = `namespace ${renderArtifactName(csn.namespace)};\n`;
|
|
83
|
+
cdlResult.namespace = `namespace ${renderArtifactName(csn.namespace, createEnv())};\n`;
|
|
83
84
|
cdlResult.namespace += 'using from \'./model.cds\';';
|
|
84
85
|
}
|
|
85
86
|
|
|
@@ -175,12 +176,12 @@ function csnToCdl( csn, options ) {
|
|
|
175
176
|
// Element extensions have `kind` set. Don't use for enum extension.
|
|
176
177
|
const isElementExtend = (ext.kind === 'extend' && !ext.enum);
|
|
177
178
|
let result = renderAnnotationAssignmentsAndDocComment(ext, env);
|
|
178
|
-
extName = isElementExtend ? renderArtifactName(extName) : renderDefinitionReference(extName);
|
|
179
|
+
extName = isElementExtend ? renderArtifactName(extName, env) : renderDefinitionReference(extName, env);
|
|
179
180
|
|
|
180
181
|
if (ext.includes && ext.includes.length > 0) {
|
|
181
182
|
// Includes can't be combined with anything in braces {}.
|
|
182
183
|
const affix = isElementExtend ? 'element ' : '';
|
|
183
|
-
const includes = ext.includes.map(inc => renderDefinitionReference(inc)).join(', ');
|
|
184
|
+
const includes = ext.includes.map(inc => renderDefinitionReference(inc, env)).join(', ');
|
|
184
185
|
result += `${env.indent}extend ${affix}${extName} with ${includes};\n`;
|
|
185
186
|
return result;
|
|
186
187
|
}
|
|
@@ -303,7 +304,7 @@ function csnToCdl( csn, options ) {
|
|
|
303
304
|
let result = renderAnnotationAssignmentsAndDocComment(ext, env);
|
|
304
305
|
// Note: Not renderDefinitionReference, because we don't care if there
|
|
305
306
|
// are annotations to unknown things. That's allowed!
|
|
306
|
-
result += `${env.indent}annotate ${renderArtifactName(ext.annotate)}`;
|
|
307
|
+
result += `${env.indent}annotate ${renderArtifactName(ext.annotate, env)}`;
|
|
307
308
|
|
|
308
309
|
if (ext.params)
|
|
309
310
|
result += renderAnnotateParamsInParentheses(ext.params, env);
|
|
@@ -326,7 +327,7 @@ function csnToCdl( csn, options ) {
|
|
|
326
327
|
const childEnv = increaseIndent(env);
|
|
327
328
|
for (const name in ext.actions) {
|
|
328
329
|
const action = ext.actions[name];
|
|
329
|
-
result += renderAnnotationAssignmentsAndDocComment(action, childEnv) + childEnv.indent + quoteNonIdentifierOrKeyword(name);
|
|
330
|
+
result += renderAnnotationAssignmentsAndDocComment(action, childEnv) + childEnv.indent + quoteNonIdentifierOrKeyword(name, env);
|
|
330
331
|
// Action parameter annotations
|
|
331
332
|
if (action.params)
|
|
332
333
|
result += renderAnnotateParamsInParentheses(action.params, childEnv);
|
|
@@ -361,7 +362,7 @@ function csnToCdl( csn, options ) {
|
|
|
361
362
|
for (const name in elements) {
|
|
362
363
|
const elem = elements[name];
|
|
363
364
|
result += renderAnnotationAssignmentsAndDocComment(elem, childEnv);
|
|
364
|
-
result += childEnv.indent + quoteNonIdentifierOrKeyword(name);
|
|
365
|
+
result += childEnv.indent + quoteNonIdentifierOrKeyword(name, env);
|
|
365
366
|
if (elem.elements)
|
|
366
367
|
result += renderAnnotateStatementElements(elem.elements, childEnv);
|
|
367
368
|
if (elem.enum)
|
|
@@ -385,7 +386,7 @@ function csnToCdl( csn, options ) {
|
|
|
385
386
|
let result = '(\n';
|
|
386
387
|
const paramAnnotations = [];
|
|
387
388
|
forEach(params, (paramName, param) => {
|
|
388
|
-
paramAnnotations.push( renderAnnotationAssignmentsAndDocComment(param, childEnv) + childEnv.indent + quoteNonIdentifierOrKeyword(paramName) );
|
|
389
|
+
paramAnnotations.push( renderAnnotationAssignmentsAndDocComment(param, childEnv) + childEnv.indent + quoteNonIdentifierOrKeyword(paramName, env) );
|
|
389
390
|
});
|
|
390
391
|
result += `${paramAnnotations.join(',\n')}\n${env.indent})`;
|
|
391
392
|
return result;
|
|
@@ -437,10 +438,10 @@ function csnToCdl( csn, options ) {
|
|
|
437
438
|
*/
|
|
438
439
|
function renderEvent( artifactName, art, env ) {
|
|
439
440
|
let result = renderAnnotationAssignmentsAndDocComment(art, env);
|
|
440
|
-
const normalizedArtifactName = renderArtifactName(artifactName);
|
|
441
|
+
const normalizedArtifactName = renderArtifactName(artifactName, env);
|
|
441
442
|
result += `${env.indent}event ${normalizedArtifactName}`;
|
|
442
443
|
if (art.includes)
|
|
443
|
-
result += renderIncludes(art.includes);
|
|
444
|
+
result += renderIncludes(art.includes, env);
|
|
444
445
|
if (art.query || art.projection) {
|
|
445
446
|
result += ' : ';
|
|
446
447
|
result += renderQuery(getNormalizedQuery(art).query, true, 'projection', env,
|
|
@@ -465,7 +466,7 @@ function csnToCdl( csn, options ) {
|
|
|
465
466
|
*/
|
|
466
467
|
function renderContextOrService( artifactName, art, env ) {
|
|
467
468
|
let result = renderAnnotationAssignmentsAndDocComment(art, env);
|
|
468
|
-
result += `${env.indent}${art.kind} ${renderArtifactName(artifactName)}`;
|
|
469
|
+
result += `${env.indent}${art.kind} ${renderArtifactName(artifactName, env)}`;
|
|
469
470
|
return `${result} {};\n`;
|
|
470
471
|
}
|
|
471
472
|
|
|
@@ -480,12 +481,12 @@ function csnToCdl( csn, options ) {
|
|
|
480
481
|
function renderEntity( artifactName, art, env ) {
|
|
481
482
|
let result = renderAnnotationAssignmentsAndDocComment(art, env);
|
|
482
483
|
result += env.indent + (art.abstract ? 'abstract ' : '');
|
|
483
|
-
result += `entity ${renderArtifactName(artifactName)}`;
|
|
484
|
+
result += `entity ${renderArtifactName(artifactName, env)}`;
|
|
484
485
|
|
|
485
486
|
if (art.params)
|
|
486
487
|
result += renderParameters(art, env);
|
|
487
488
|
if (art.includes)
|
|
488
|
-
result += renderIncludes(art.includes);
|
|
489
|
+
result += renderIncludes(art.includes, env);
|
|
489
490
|
result += ` ${renderElements(art, env)}`;
|
|
490
491
|
result += `${renderActionsAndFunctions(art, env)};\n`;
|
|
491
492
|
return result;
|
|
@@ -503,9 +504,9 @@ function csnToCdl( csn, options ) {
|
|
|
503
504
|
*/
|
|
504
505
|
function renderAspect( artifactName, art, env ) {
|
|
505
506
|
let result = renderAnnotationAssignmentsAndDocComment(art, env);
|
|
506
|
-
result += `${env.indent}aspect ${renderArtifactName(artifactName)}`;
|
|
507
|
+
result += `${env.indent}aspect ${renderArtifactName(artifactName, env)}`;
|
|
507
508
|
if (art.includes)
|
|
508
|
-
result += renderIncludes(art.includes);
|
|
509
|
+
result += renderIncludes(art.includes, env);
|
|
509
510
|
|
|
510
511
|
if (art.elements)
|
|
511
512
|
result += ` ${renderElements(art, env)}`;
|
|
@@ -552,7 +553,7 @@ function csnToCdl( csn, options ) {
|
|
|
552
553
|
result += element.key ? 'key ' : '';
|
|
553
554
|
// TODO(v4): Remove once deprecated flag for `masked` is removed.
|
|
554
555
|
result += element.masked ? 'masked ' : '';
|
|
555
|
-
result += quoteNonIdentifierOrKeyword(elementName);
|
|
556
|
+
result += quoteNonIdentifierOrKeyword(elementName, env);
|
|
556
557
|
if (element.val !== undefined) { // enum value
|
|
557
558
|
result += ` = ${exprRenderer.renderExpr(element, env)}`;
|
|
558
559
|
}
|
|
@@ -566,7 +567,13 @@ function csnToCdl( csn, options ) {
|
|
|
566
567
|
}
|
|
567
568
|
|
|
568
569
|
if (element.value !== undefined) { // calculated element // @ts-ignore
|
|
569
|
-
result +=
|
|
570
|
+
result += ' = ';
|
|
571
|
+
if (element.value.xpr && xprContainsCondition(element.value.xpr))
|
|
572
|
+
result += exprRenderer.renderSubExpr(element.value, env);
|
|
573
|
+
else
|
|
574
|
+
result += exprRenderer.renderExpr(element.value, env);
|
|
575
|
+
if (element.value.stored === true)
|
|
576
|
+
result += ' stored';
|
|
570
577
|
}
|
|
571
578
|
|
|
572
579
|
return `${result};\n`;
|
|
@@ -695,7 +702,7 @@ function csnToCdl( csn, options ) {
|
|
|
695
702
|
const subEnv = increaseIndent(env);
|
|
696
703
|
let result = `(\n${subEnv.indent}${renderQuery(source, false, 'view', subEnv)}\n${env.indent})`;
|
|
697
704
|
if (source.as)
|
|
698
|
-
result += renderAlias(source.as);
|
|
705
|
+
result += renderAlias(source.as, env);
|
|
699
706
|
|
|
700
707
|
return result;
|
|
701
708
|
}
|
|
@@ -751,7 +758,7 @@ function csnToCdl( csn, options ) {
|
|
|
751
758
|
const firstArtifactName = path.ref[0].id || path.ref[0];
|
|
752
759
|
|
|
753
760
|
// Render the first path step (absolute name, with different quoting/naming ..)
|
|
754
|
-
let result = renderDefinitionReference(firstArtifactName);
|
|
761
|
+
let result = renderDefinitionReference(firstArtifactName, env);
|
|
755
762
|
|
|
756
763
|
// Even the first step might have parameters and/or a filter
|
|
757
764
|
if (path.ref[0].args)
|
|
@@ -789,7 +796,7 @@ function csnToCdl( csn, options ) {
|
|
|
789
796
|
let result = renderAbsolutePath(path, env);
|
|
790
797
|
if (path.as) {
|
|
791
798
|
// Source had an alias - render it
|
|
792
|
-
result += renderAlias(path.as);
|
|
799
|
+
result += renderAlias(path.as, env);
|
|
793
800
|
}
|
|
794
801
|
return result;
|
|
795
802
|
}
|
|
@@ -837,6 +844,8 @@ function csnToCdl( csn, options ) {
|
|
|
837
844
|
// Use special rendering for .expand/.inline - renderExpr cannot easily handle some cases
|
|
838
845
|
if (col.expand || col.inline)
|
|
839
846
|
result += renderInlineExpand(col, env);
|
|
847
|
+
else if (col.xpr && xprContainsCondition(col.xpr))
|
|
848
|
+
result += exprRenderer.renderSubExpr(withoutCast(col), env);
|
|
840
849
|
else
|
|
841
850
|
result += exprRenderer.renderExpr(withoutCast(col), env);
|
|
842
851
|
|
|
@@ -844,7 +853,7 @@ function csnToCdl( csn, options ) {
|
|
|
844
853
|
// A new association (cast with `type` and `target`) uses `as` as its primary name, not alias.
|
|
845
854
|
const isNewAssociation = col.cast?.type && col.cast.target;
|
|
846
855
|
if (!isNewAssociation && col.as && !col.inline && !col.expand)
|
|
847
|
-
result += renderAlias(col.as);
|
|
856
|
+
result += renderAlias(col.as, env);
|
|
848
857
|
|
|
849
858
|
// Explicit type provided for the view element?
|
|
850
859
|
if (col.cast) {
|
|
@@ -871,7 +880,7 @@ function csnToCdl( csn, options ) {
|
|
|
871
880
|
|
|
872
881
|
// s as alias { * }
|
|
873
882
|
if (obj.as && (obj.ref || obj.xpr || obj.val !== undefined || obj.func !== undefined))
|
|
874
|
-
result += renderAlias(obj.as);
|
|
883
|
+
result += renderAlias(obj.as, env);
|
|
875
884
|
|
|
876
885
|
// We found a leaf - no further drilling
|
|
877
886
|
if (!obj.inline && !obj.expand) {
|
|
@@ -901,7 +910,7 @@ function csnToCdl( csn, options ) {
|
|
|
901
910
|
|
|
902
911
|
// { * } as expand
|
|
903
912
|
if (!obj.ref && obj.as)
|
|
904
|
-
result += renderAlias(obj.as);
|
|
913
|
+
result += renderAlias(obj.as, env);
|
|
905
914
|
|
|
906
915
|
return result;
|
|
907
916
|
}
|
|
@@ -940,7 +949,7 @@ function csnToCdl( csn, options ) {
|
|
|
940
949
|
function renderView( artifactName, art, env ) {
|
|
941
950
|
const syntax = (art.projection) ? 'projection' : 'entity';
|
|
942
951
|
let result = renderAnnotationAssignmentsAndDocComment(art, env);
|
|
943
|
-
result += `${env.indent}entity ${renderArtifactName(artifactName)}`;
|
|
952
|
+
result += `${env.indent}entity ${renderArtifactName(artifactName, env)}`;
|
|
944
953
|
if (art.params)
|
|
945
954
|
result += renderParameters(art, env);
|
|
946
955
|
result += ' as ';
|
|
@@ -1004,7 +1013,7 @@ function csnToCdl( csn, options ) {
|
|
|
1004
1013
|
}
|
|
1005
1014
|
|
|
1006
1015
|
if (select.excluding) {
|
|
1007
|
-
const excludes = select.excluding.map(id => `${childEnv.indent}${quoteNonIdentifierOrKeyword(id)}`).join(',\n');
|
|
1016
|
+
const excludes = select.excluding.map(id => `${childEnv.indent}${quoteNonIdentifierOrKeyword(id, env)}`).join(',\n');
|
|
1008
1017
|
result += ` excluding {\n${excludes}\n`;
|
|
1009
1018
|
result += `${env.indent}}`;
|
|
1010
1019
|
}
|
|
@@ -1140,7 +1149,7 @@ function csnToCdl( csn, options ) {
|
|
|
1140
1149
|
*/
|
|
1141
1150
|
function renderActionOrFunction( actionName, act, env ) {
|
|
1142
1151
|
let result = renderAnnotationAssignmentsAndDocComment(act, env) + env.indent + act.kind;
|
|
1143
|
-
result += ` ${renderArtifactName(actionName)}`;
|
|
1152
|
+
result += ` ${renderArtifactName(actionName, env)}`;
|
|
1144
1153
|
result += renderParameters(act, env);
|
|
1145
1154
|
if (act.returns) {
|
|
1146
1155
|
const actEnv = envAddPath(env, [ 'returns' ]);
|
|
@@ -1179,7 +1188,7 @@ function csnToCdl( csn, options ) {
|
|
|
1179
1188
|
function renderParameter( parName, par, env ) {
|
|
1180
1189
|
env = envAddPath(env, [ 'params', parName ]);
|
|
1181
1190
|
let result = `${renderAnnotationAssignmentsAndDocComment(par, env)}${env.indent}`;
|
|
1182
|
-
result += `${quoteNonIdentifierOrKeyword(parName)} : ${renderTypeReferenceAndProps(par, env)}`;
|
|
1191
|
+
result += `${quoteNonIdentifierOrKeyword(parName, env)} : ${renderTypeReferenceAndProps(par, env)}`;
|
|
1183
1192
|
return result;
|
|
1184
1193
|
}
|
|
1185
1194
|
|
|
@@ -1195,9 +1204,9 @@ function csnToCdl( csn, options ) {
|
|
|
1195
1204
|
*/
|
|
1196
1205
|
function renderTypeOrAnnotation( artifactName, art, env, artType ) {
|
|
1197
1206
|
let result = renderAnnotationAssignmentsAndDocComment(art, env);
|
|
1198
|
-
result += `${env.indent + (artType || art.$syntax || art.kind )} ${renderArtifactName(artifactName)}`;
|
|
1207
|
+
result += `${env.indent + (artType || art.$syntax || art.kind )} ${renderArtifactName(artifactName, env)}`;
|
|
1199
1208
|
if (art.includes)
|
|
1200
|
-
result += renderIncludes(art.includes);
|
|
1209
|
+
result += renderIncludes(art.includes, env);
|
|
1201
1210
|
|
|
1202
1211
|
if (!art.type && art.elements) // For nicer output, no colon if unnamed structure is used.
|
|
1203
1212
|
result += ` ${renderTypeReferenceAndProps(art, env)}`;
|
|
@@ -1296,7 +1305,7 @@ function csnToCdl( csn, options ) {
|
|
|
1296
1305
|
// Reference to another artifact
|
|
1297
1306
|
if (typeof type === 'string') {
|
|
1298
1307
|
// If we get here, it must be a named type
|
|
1299
|
-
result += renderNamedTypeWithParameters(artifact);
|
|
1308
|
+
result += renderNamedTypeWithParameters(artifact, env);
|
|
1300
1309
|
}
|
|
1301
1310
|
else if (type?.ref) {
|
|
1302
1311
|
result += renderAbsolutePath(artifact.type, env);
|
|
@@ -1320,7 +1329,7 @@ function csnToCdl( csn, options ) {
|
|
|
1320
1329
|
* @return {string}
|
|
1321
1330
|
*/
|
|
1322
1331
|
function renderRedirectedTo( art, env ) {
|
|
1323
|
-
let result = `redirected to ${renderDefinitionReference(art.target)}`;
|
|
1332
|
+
let result = `redirected to ${renderDefinitionReference(art.target, env)}`;
|
|
1324
1333
|
if (art.on)
|
|
1325
1334
|
result += ` on ${exprRenderer.renderExpr(art.on, env)}`;
|
|
1326
1335
|
else if (art.keys)
|
|
@@ -1330,10 +1339,12 @@ function csnToCdl( csn, options ) {
|
|
|
1330
1339
|
|
|
1331
1340
|
/**
|
|
1332
1341
|
* Render the named type with optional parameters, e.g. `MyString(length: 10)`.
|
|
1342
|
+
*
|
|
1333
1343
|
* @param {CSN.Artifact} artWithType
|
|
1344
|
+
* @param {CdlRenderEnvironment} env
|
|
1334
1345
|
* @return {string}
|
|
1335
1346
|
*/
|
|
1336
|
-
function renderNamedTypeWithParameters( artWithType ) {
|
|
1347
|
+
function renderNamedTypeWithParameters( artWithType, env ) {
|
|
1337
1348
|
const type = normalizeTypeRef(artWithType.type);
|
|
1338
1349
|
let result = '';
|
|
1339
1350
|
|
|
@@ -1349,7 +1360,7 @@ function csnToCdl( csn, options ) {
|
|
|
1349
1360
|
result += shortHand;
|
|
1350
1361
|
}
|
|
1351
1362
|
else {
|
|
1352
|
-
result += renderDefinitionReference(type);
|
|
1363
|
+
result += renderDefinitionReference(type, env);
|
|
1353
1364
|
}
|
|
1354
1365
|
|
|
1355
1366
|
result += renderTypeParameters(artWithType);
|
|
@@ -1402,8 +1413,8 @@ function csnToCdl( csn, options ) {
|
|
|
1402
1413
|
// Shorthand for absolute path (as string)
|
|
1403
1414
|
else if (annoValue['=']) {
|
|
1404
1415
|
if (annoValue['='].startsWith('@'))
|
|
1405
|
-
return quoteAnnotationPathIfRequired(annoValue['=']);
|
|
1406
|
-
return quotePathIfRequired(annoValue['=']);
|
|
1416
|
+
return quoteAnnotationPathIfRequired(annoValue['='], env);
|
|
1417
|
+
return quotePathIfRequired(annoValue['='], env);
|
|
1407
1418
|
}
|
|
1408
1419
|
// Shorthand for ellipsis: `... up to <val>`
|
|
1409
1420
|
else if (annoValue['...']) {
|
|
@@ -1417,7 +1428,7 @@ function csnToCdl( csn, options ) {
|
|
|
1417
1428
|
// struct if there are more and use nicer indentation.
|
|
1418
1429
|
const keys = Object.keys(annoValue);
|
|
1419
1430
|
const childEnv = keys.length <= 1 ? env : increaseIndent(env);
|
|
1420
|
-
const values = keys.map(key => `${quoteAnnotationPathIfRequired(key)}: ${renderAnnotationValue(annoValue[key], childEnv)}`);
|
|
1431
|
+
const values = keys.map(key => `${quoteAnnotationPathIfRequired(key, env)}: ${renderAnnotationValue(annoValue[key], childEnv)}`);
|
|
1421
1432
|
if (values.length <= 1)
|
|
1422
1433
|
return `{ ${values.join(', ')} }`;
|
|
1423
1434
|
const valueList = values.join(`,\n${childEnv.indent}`);
|
|
@@ -1479,7 +1490,7 @@ function csnToCdl( csn, options ) {
|
|
|
1479
1490
|
// FIXME: We should rather explicitly recognize quoting somehow
|
|
1480
1491
|
if (idx === 0 && s.startsWith('$'))
|
|
1481
1492
|
return s;
|
|
1482
|
-
return quoteNonIdentifierOrKeyword(s, env
|
|
1493
|
+
return quoteNonIdentifierOrKeyword(s, env);
|
|
1483
1494
|
}
|
|
1484
1495
|
// ID with filters or parameters
|
|
1485
1496
|
else if (typeof s === 'object') {
|
|
@@ -1492,7 +1503,7 @@ function csnToCdl( csn, options ) {
|
|
|
1492
1503
|
return `${s.func}(${renderArguments(s, '=>', env)})`;
|
|
1493
1504
|
|
|
1494
1505
|
// Path step, possibly with view parameters and/or filters
|
|
1495
|
-
let result = `${quoteNonIdentifierOrKeyword(s.id, env
|
|
1506
|
+
let result = `${quoteNonIdentifierOrKeyword(s.id, env)}`;
|
|
1496
1507
|
if (s.args) {
|
|
1497
1508
|
// View parameters
|
|
1498
1509
|
result += `(${renderArguments(s, ':', env)})`;
|
|
@@ -1543,7 +1554,7 @@ function csnToCdl( csn, options ) {
|
|
|
1543
1554
|
*/
|
|
1544
1555
|
function renderNamedArguments( node, separator, env ) {
|
|
1545
1556
|
return Object.keys(node.args).map(function renderNamedArgument(key) {
|
|
1546
|
-
return `${quoteNonIdentifierOrKeyword(key, env
|
|
1557
|
+
return `${quoteNonIdentifierOrKeyword(key, env)} ${separator} ${renderArgument(node.args[key], env)}`;
|
|
1547
1558
|
}).join(', ');
|
|
1548
1559
|
}
|
|
1549
1560
|
|
|
@@ -1599,6 +1610,8 @@ function csnToCdl( csn, options ) {
|
|
|
1599
1610
|
/**
|
|
1600
1611
|
* Render a cardinality (only those parts that were actually provided)
|
|
1601
1612
|
*
|
|
1613
|
+
* TODO: Check srcmin as well?
|
|
1614
|
+
*
|
|
1602
1615
|
* @param {CSN.Artifact} art
|
|
1603
1616
|
* @return {string}
|
|
1604
1617
|
*/
|
|
@@ -1674,7 +1687,7 @@ function csnToCdl( csn, options ) {
|
|
|
1674
1687
|
* @return {string}
|
|
1675
1688
|
*/
|
|
1676
1689
|
function renderForeignKey( fKey, env ) {
|
|
1677
|
-
const alias = fKey.as ? renderAlias(fKey.as) : '';
|
|
1690
|
+
const alias = fKey.as ? renderAlias(fKey.as, env) : '';
|
|
1678
1691
|
return exprRenderer.renderExpr(fKey, env) + alias;
|
|
1679
1692
|
}
|
|
1680
1693
|
|
|
@@ -1682,10 +1695,11 @@ function csnToCdl( csn, options ) {
|
|
|
1682
1695
|
* Render an explicit alias, e.g. for columns.
|
|
1683
1696
|
*
|
|
1684
1697
|
* @param {string} alias
|
|
1698
|
+
* @param {CdlRenderEnvironment} env
|
|
1685
1699
|
* @return {string}
|
|
1686
1700
|
*/
|
|
1687
|
-
function renderAlias( alias ) {
|
|
1688
|
-
return ` as ${quoteNonIdentifierOrKeyword(alias)}`;
|
|
1701
|
+
function renderAlias( alias, env ) {
|
|
1702
|
+
return ` as ${quoteNonIdentifierOrKeyword(alias, env)}`;
|
|
1689
1703
|
}
|
|
1690
1704
|
|
|
1691
1705
|
/**
|
|
@@ -1758,11 +1772,11 @@ function csnToCdl( csn, options ) {
|
|
|
1758
1772
|
if (parentheses)
|
|
1759
1773
|
result += '(';
|
|
1760
1774
|
|
|
1761
|
-
result += quoteAnnotationPathIfRequired(nameBeforeVariant);
|
|
1775
|
+
result += quoteAnnotationPathIfRequired(nameBeforeVariant, env);
|
|
1762
1776
|
if (variant !== undefined)
|
|
1763
1777
|
// Unfortunately, the compiler does not allow `.@` after the first variant identifier,
|
|
1764
1778
|
// so we're back at simple paths.
|
|
1765
|
-
result += `#${quotePathIfRequired(variant)}`;
|
|
1779
|
+
result += `#${quotePathIfRequired(variant, env)}`;
|
|
1766
1780
|
result += ` : ${renderAnnotationValue(anno, env)}`;
|
|
1767
1781
|
|
|
1768
1782
|
if (parentheses)
|
|
@@ -1774,10 +1788,11 @@ function csnToCdl( csn, options ) {
|
|
|
1774
1788
|
* Render the name of an artifact, quote path steps if necessary.
|
|
1775
1789
|
*
|
|
1776
1790
|
* @param {string} artifactName Artifact name to render
|
|
1791
|
+
* @param {CdlRenderEnvironment} env
|
|
1777
1792
|
* @return {string} Artifact name ready for rendering
|
|
1778
1793
|
*/
|
|
1779
|
-
function renderArtifactName( artifactName ) {
|
|
1780
|
-
return quotePathIfRequired(artifactName);
|
|
1794
|
+
function renderArtifactName( artifactName, env ) {
|
|
1795
|
+
return quotePathIfRequired(artifactName, env);
|
|
1781
1796
|
}
|
|
1782
1797
|
|
|
1783
1798
|
/**
|
|
@@ -1785,19 +1800,21 @@ function csnToCdl( csn, options ) {
|
|
|
1785
1800
|
* is available in the rendered CDL. Otherwise, a USING is added.
|
|
1786
1801
|
*
|
|
1787
1802
|
* @param {string} name
|
|
1803
|
+
* @param {CdlRenderEnvironment} env
|
|
1788
1804
|
* @return {string}
|
|
1789
1805
|
*/
|
|
1790
|
-
function renderDefinitionReference( name ) {
|
|
1806
|
+
function renderDefinitionReference( name, env ) {
|
|
1791
1807
|
usings.addIfRequired(name);
|
|
1792
|
-
return quotePathIfRequired(name);
|
|
1808
|
+
return quotePathIfRequired(name, env);
|
|
1793
1809
|
}
|
|
1794
1810
|
|
|
1795
1811
|
/**
|
|
1796
1812
|
* @param {string[]} includes
|
|
1813
|
+
* @param {CdlRenderEnvironment} env
|
|
1797
1814
|
* @return {string}
|
|
1798
1815
|
*/
|
|
1799
|
-
function renderIncludes( includes ) {
|
|
1800
|
-
return ` : ${includes.map(name => renderDefinitionReference(name)).join(', ')}`;
|
|
1816
|
+
function renderIncludes( includes, env ) {
|
|
1817
|
+
return ` : ${includes.map(name => renderDefinitionReference(name, env)).join(', ')}`;
|
|
1801
1818
|
}
|
|
1802
1819
|
|
|
1803
1820
|
function createCdlExpressionRenderer() {
|
|
@@ -1842,13 +1859,13 @@ function csnToCdl( csn, options ) {
|
|
|
1842
1859
|
func(x) {
|
|
1843
1860
|
if (keywords.cdl_functions.includes(x.func.toUpperCase()) && !x.args)
|
|
1844
1861
|
return x.func;
|
|
1845
|
-
const name =
|
|
1862
|
+
const name = quoteFunctionIfRequired(x.func, this.env);
|
|
1846
1863
|
if (!x.args) // e.g. for methods without arguments, `args` is not set at all.
|
|
1847
1864
|
return `${name}`;
|
|
1848
1865
|
return `${name}(${renderArguments( x, '=>', this.env )})`;
|
|
1849
1866
|
},
|
|
1850
1867
|
xpr(x) {
|
|
1851
|
-
if (this.isNestedXpr && !x.cast
|
|
1868
|
+
if (this.isNestedXpr && !x.cast)
|
|
1852
1869
|
return `(${this.renderExpr(x.xpr)})`;
|
|
1853
1870
|
return this.renderExpr(x.xpr);
|
|
1854
1871
|
},
|
|
@@ -1920,6 +1937,129 @@ function csnToCdl( csn, options ) {
|
|
|
1920
1937
|
'Property $(PROP) not rendered, because it can only be rendered inside $(OTHERPROP) for arrayed artifacts');
|
|
1921
1938
|
}
|
|
1922
1939
|
}
|
|
1940
|
+
|
|
1941
|
+
/**
|
|
1942
|
+
* Quote simple path steps with `![]` if necessary. For simple ids such as
|
|
1943
|
+
* `elem` use `quoteNonIdentifierOrKeyword` instead.
|
|
1944
|
+
*
|
|
1945
|
+
* In contrast to quoteNonIdentifierOrKeyword, does not handle additional keywords,
|
|
1946
|
+
* because it was not required, yet.
|
|
1947
|
+
*
|
|
1948
|
+
* Due to token rewrite, all keywords after a dot (`.`) are rewritten to
|
|
1949
|
+
* identifiers, i.e. we only need to check for the identifier RegEx.
|
|
1950
|
+
*
|
|
1951
|
+
* @param {string} path
|
|
1952
|
+
* @param {CdlRenderEnvironment} env
|
|
1953
|
+
* @returns {string}
|
|
1954
|
+
*/
|
|
1955
|
+
function quotePathIfRequired( path, env ) {
|
|
1956
|
+
return path.split('.').map((step, index) => {
|
|
1957
|
+
if (index === 0)
|
|
1958
|
+
return quoteNonIdentifierOrKeyword(step, env);
|
|
1959
|
+
else if (!identifierRegex.test(step))
|
|
1960
|
+
return delimitedId(step, env);
|
|
1961
|
+
return step;
|
|
1962
|
+
}).join('.');
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
/**
|
|
1966
|
+
* Quote the id with `![]` if necessary. For paths such as `E.key` use
|
|
1967
|
+
* `quotePathIfRequired` instead.
|
|
1968
|
+
* See quoteNonIdentifier() if you want to ignore keywords.
|
|
1969
|
+
*
|
|
1970
|
+
* Set env.additionalKeywords to an array of UPPERCASE keywords
|
|
1971
|
+
* that also need quoting, e.g. in special functions.
|
|
1972
|
+
*
|
|
1973
|
+
* @param {string} id
|
|
1974
|
+
* @param {CdlRenderEnvironment} env
|
|
1975
|
+
* @return {string}
|
|
1976
|
+
*/
|
|
1977
|
+
function quoteNonIdentifierOrKeyword( id, env ) {
|
|
1978
|
+
// Quote if required for CDL
|
|
1979
|
+
if (requiresQuotingForCdl(id, env?.additionalKeywords || []))
|
|
1980
|
+
return delimitedId(id, env);
|
|
1981
|
+
return id;
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
/**
|
|
1985
|
+
* Quote the id with `![]` if necessary. For paths such as `E.key` use
|
|
1986
|
+
* `quotePathIfRequired` instead.
|
|
1987
|
+
* See quoteNonIdentifierOrKeyword() if you want to quote identifiers
|
|
1988
|
+
* that are keywords as well.
|
|
1989
|
+
*
|
|
1990
|
+
* Does not quote the given id if it is a keyword.
|
|
1991
|
+
*
|
|
1992
|
+
* @param {string} id
|
|
1993
|
+
* @param {CdlRenderEnvironment} env
|
|
1994
|
+
* @return {string}
|
|
1995
|
+
*/
|
|
1996
|
+
function quoteNonIdentifier( id, env ) {
|
|
1997
|
+
if (!identifierRegex.test(id))
|
|
1998
|
+
return delimitedId(id, env);
|
|
1999
|
+
return id;
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
/**
|
|
2003
|
+
* Quote the given function name if required.
|
|
2004
|
+
*
|
|
2005
|
+
* @param {string} funcName
|
|
2006
|
+
* @param {CdlRenderEnvironment} env
|
|
2007
|
+
* @return {string}
|
|
2008
|
+
*/
|
|
2009
|
+
function quoteFunctionIfRequired( funcName, env ) {
|
|
2010
|
+
if (cdlNewLineRegEx.test(funcName)) {
|
|
2011
|
+
msg.error('name-invalid-identifier', env.path, {},
|
|
2012
|
+
'An identifier can\'t contain newline characters in CDL');
|
|
2013
|
+
}
|
|
2014
|
+
return apiSmartFunctionId(funcName);
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
/**
|
|
2018
|
+
* Quote an annotation path, e.g. `@My.@Anno.Description` if necessary.
|
|
2019
|
+
* `anno` can start with `@` but is not required to be.
|
|
2020
|
+
* Example of an annotation path that needs to be quoted:
|
|
2021
|
+
* `@![ spaces in path ].@!["double quotes"]`.
|
|
2022
|
+
*
|
|
2023
|
+
* @param {string} anno
|
|
2024
|
+
* @param {CdlRenderEnvironment} env
|
|
2025
|
+
* @returns {string}
|
|
2026
|
+
*/
|
|
2027
|
+
function quoteAnnotationPathIfRequired( anno, env ) {
|
|
2028
|
+
return anno.split('.').map((segment) => {
|
|
2029
|
+
if (segment.startsWith('@'))
|
|
2030
|
+
return `@${quoteNonIdentifier(segment.slice(1), env)}`;
|
|
2031
|
+
return quoteNonIdentifier(segment, env);
|
|
2032
|
+
}).join('.');
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
/**
|
|
2036
|
+
* The same as the exported function apiDelimitedId, but checks that we can actually represent the
|
|
2037
|
+
* string: newline characters are not allowed.
|
|
2038
|
+
*
|
|
2039
|
+
* @param {string} id
|
|
2040
|
+
* @param {CdlRenderEnvironment} env
|
|
2041
|
+
* @return {string}
|
|
2042
|
+
*/
|
|
2043
|
+
function delimitedId( id, env ) {
|
|
2044
|
+
if (cdlNewLineRegEx.test(id)) {
|
|
2045
|
+
msg.error('name-invalid-identifier', env.path, {},
|
|
2046
|
+
'An identifier can\'t contain newline characters in CDL');
|
|
2047
|
+
}
|
|
2048
|
+
return apiDelimitedId(id);
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
|
|
2053
|
+
class CdlRenderEnvironment {
|
|
2054
|
+
indent = '';
|
|
2055
|
+
path = null;
|
|
2056
|
+
artifactName = null;
|
|
2057
|
+
elementName = null;
|
|
2058
|
+
additionalKeywords = [];
|
|
2059
|
+
|
|
2060
|
+
constructor(values) {
|
|
2061
|
+
Object.assign(this, values);
|
|
2062
|
+
}
|
|
1923
2063
|
}
|
|
1924
2064
|
|
|
1925
2065
|
/**
|
|
@@ -1930,20 +2070,14 @@ function csnToCdl( csn, options ) {
|
|
|
1930
2070
|
* @return {CdlRenderEnvironment}
|
|
1931
2071
|
*/
|
|
1932
2072
|
function createEnv( values = {} ) {
|
|
1933
|
-
return
|
|
1934
|
-
// Current indentation string
|
|
1935
|
-
indent: '',
|
|
1936
|
-
path: null,
|
|
1937
|
-
artifactName: '',
|
|
1938
|
-
elementName: '',
|
|
1939
|
-
}, values);
|
|
2073
|
+
return new CdlRenderEnvironment( values );
|
|
1940
2074
|
}
|
|
1941
2075
|
|
|
1942
2076
|
function envAddPath( env, path ) {
|
|
1943
|
-
return Object.assign(
|
|
2077
|
+
return Object.assign(new CdlRenderEnvironment(env), { path: [ ...env.path, ...path ] } );
|
|
1944
2078
|
}
|
|
1945
2079
|
function envNewPath( env, path ) {
|
|
1946
|
-
return Object.assign(
|
|
2080
|
+
return Object.assign(new CdlRenderEnvironment(env), { path: [ ...path ] } );
|
|
1947
2081
|
}
|
|
1948
2082
|
|
|
1949
2083
|
/**
|
|
@@ -1956,92 +2090,6 @@ function increaseIndent( env ) {
|
|
|
1956
2090
|
return Object.assign({}, env, { indent: `${env.indent} ` });
|
|
1957
2091
|
}
|
|
1958
2092
|
|
|
1959
|
-
/**
|
|
1960
|
-
* Quote simple path steps with `![]` if necessary. For simple ids such as
|
|
1961
|
-
* `elem` use `quoteNonIdentifierOrKeyword` instead.
|
|
1962
|
-
*
|
|
1963
|
-
* In contrast to quoteNonIdentifierOrKeyword, does not handle additional keywords,
|
|
1964
|
-
* because it was not required, yet.
|
|
1965
|
-
*
|
|
1966
|
-
* Due to token rewrite, all keywords after a dot (`.`) are rewritten to
|
|
1967
|
-
* identifiers, i.e. we only need to check for the identifier RegEx.
|
|
1968
|
-
*
|
|
1969
|
-
* @param {string} path
|
|
1970
|
-
* @returns {string}
|
|
1971
|
-
*/
|
|
1972
|
-
function quotePathIfRequired( path ) {
|
|
1973
|
-
return path.split('.').map((step, index) => {
|
|
1974
|
-
if (index === 0)
|
|
1975
|
-
return quoteNonIdentifierOrKeyword(step);
|
|
1976
|
-
else if (!identifierRegex.test(step))
|
|
1977
|
-
return delimitedId(step);
|
|
1978
|
-
return step;
|
|
1979
|
-
}).join('.');
|
|
1980
|
-
}
|
|
1981
|
-
|
|
1982
|
-
/**
|
|
1983
|
-
* Quote the id with `![]` if necessary. For paths such as `E.key` use
|
|
1984
|
-
* `quotePathIfRequired` instead.
|
|
1985
|
-
* See quoteNonIdentifier() if you want to ignore keywords.
|
|
1986
|
-
*
|
|
1987
|
-
* Set additionalKeywords to an array of UPPERCASE keywords
|
|
1988
|
-
* that also need quoting, e.g. in special functions.
|
|
1989
|
-
*
|
|
1990
|
-
* @param {string} id
|
|
1991
|
-
* @param {string[]} [additionalKeywords]
|
|
1992
|
-
* @return {string}
|
|
1993
|
-
*/
|
|
1994
|
-
function quoteNonIdentifierOrKeyword( id, additionalKeywords ) {
|
|
1995
|
-
// Quote if required for CDL
|
|
1996
|
-
if (requiresQuotingForCdl(id, additionalKeywords || []))
|
|
1997
|
-
return delimitedId(id);
|
|
1998
|
-
return id;
|
|
1999
|
-
}
|
|
2000
|
-
|
|
2001
|
-
/**
|
|
2002
|
-
* Quote the id with `![]` if necessary. For paths such as `E.key` use
|
|
2003
|
-
* `quotePathIfRequired` instead.
|
|
2004
|
-
* See quoteNonIdentifierOrKeyword() if you want to quote identifiers
|
|
2005
|
-
* that are keywords as well.
|
|
2006
|
-
*
|
|
2007
|
-
* Does not quote the given id if it is a keyword.
|
|
2008
|
-
*
|
|
2009
|
-
* @param {string} id
|
|
2010
|
-
* @return {string}
|
|
2011
|
-
*/
|
|
2012
|
-
function quoteNonIdentifier( id ) {
|
|
2013
|
-
if (!identifierRegex.test(id))
|
|
2014
|
-
return delimitedId(id);
|
|
2015
|
-
return id;
|
|
2016
|
-
}
|
|
2017
|
-
|
|
2018
|
-
/**
|
|
2019
|
-
* Quote an annotation path, e.g. `@My.@Anno.Description` if necessary.
|
|
2020
|
-
* `anno` can start with `@` but is not required to be.
|
|
2021
|
-
* Example of an annotation path that needs to be quoted:
|
|
2022
|
-
* `@![ spaces in path ].@!["double quotes"]`.
|
|
2023
|
-
*
|
|
2024
|
-
* @param {string} anno
|
|
2025
|
-
* @returns {string}
|
|
2026
|
-
*/
|
|
2027
|
-
function quoteAnnotationPathIfRequired( anno ) {
|
|
2028
|
-
return anno.split('.').map((segment) => {
|
|
2029
|
-
if (segment.startsWith('@'))
|
|
2030
|
-
return `@${quoteNonIdentifier(segment.slice(1))}`;
|
|
2031
|
-
return quoteNonIdentifier(segment);
|
|
2032
|
-
}).join('.');
|
|
2033
|
-
}
|
|
2034
|
-
|
|
2035
|
-
/**
|
|
2036
|
-
* Quotes the identifier using CDL-style ![]-quotes.
|
|
2037
|
-
*
|
|
2038
|
-
* @param id
|
|
2039
|
-
* @returns {string}
|
|
2040
|
-
*/
|
|
2041
|
-
function delimitedId( id ) {
|
|
2042
|
-
return `![${id.replace(/]/g, ']]')}]`;
|
|
2043
|
-
}
|
|
2044
|
-
|
|
2045
2093
|
/**
|
|
2046
2094
|
* Returns true if 'id' requires quotes for CDL, i.e. if 'id'
|
|
2047
2095
|
* does not match the first part of the `Identifier` rule of `language.g4`
|
|
@@ -2061,7 +2109,7 @@ function requiresQuotingForCdl( id, additionalKeywords ) {
|
|
|
2061
2109
|
additionalKeywords.includes(id.toUpperCase());
|
|
2062
2110
|
}
|
|
2063
2111
|
|
|
2064
|
-
const
|
|
2112
|
+
const conditionOperators = [
|
|
2065
2113
|
// Antlr rule 'condition', 'conditionAnd'
|
|
2066
2114
|
'AND', 'OR',
|
|
2067
2115
|
|
|
@@ -2080,8 +2128,7 @@ const functionExpressionOperatorsRequireParentheses = [
|
|
|
2080
2128
|
* in a `fct(<xpr>)` expression such as `cast(<xpr> as Type)`. We only need to
|
|
2081
2129
|
* look at the first nesting level. Otherwise, `renderExpr()` will already add parentheses.
|
|
2082
2130
|
*
|
|
2083
|
-
* The list of `
|
|
2084
|
-
* the `expression` Antlr rule.
|
|
2131
|
+
* The list of `conditionOperators` was created by looking at the `expression` Antlr rule.
|
|
2085
2132
|
* Because of token-rewrites, there are functions that allow operators/tokens that would
|
|
2086
2133
|
* require parentheses in other functions. For example *regex functions allow `IN` but
|
|
2087
2134
|
* if `IN` is used in other functions, it requires parentheses. To allow for that case,
|
|
@@ -2100,7 +2147,22 @@ const functionExpressionOperatorsRequireParentheses = [
|
|
|
2100
2147
|
function isSimpleFunctionExpression( xpr, additionalAllowedKeywords = [] ) {
|
|
2101
2148
|
return !xpr || xpr.every(val => typeof val !== 'string' ||
|
|
2102
2149
|
(additionalAllowedKeywords.includes(val.toUpperCase()) ||
|
|
2103
|
-
!
|
|
2150
|
+
!conditionOperators.includes(val.toUpperCase())));
|
|
2151
|
+
}
|
|
2152
|
+
|
|
2153
|
+
/**
|
|
2154
|
+
* If `xpr` contains tokens that are used in conditions, it may be required to put the
|
|
2155
|
+
* rendered expression in parentheses. This function checks if any direkt entry in
|
|
2156
|
+
* `xpr` is a condition token such as `AND`.
|
|
2157
|
+
*
|
|
2158
|
+
* May report false positives for e.g. `CASE WHEN 1>1 THEN …`.
|
|
2159
|
+
*
|
|
2160
|
+
* @param {any[]} xpr
|
|
2161
|
+
* @return {boolean}
|
|
2162
|
+
*/
|
|
2163
|
+
function xprContainsCondition( xpr ) {
|
|
2164
|
+
return xpr && xpr.some(val => typeof val === 'string' &&
|
|
2165
|
+
conditionOperators.includes(val.toUpperCase()));
|
|
2104
2166
|
}
|
|
2105
2167
|
|
|
2106
2168
|
/**
|
|
@@ -2241,50 +2303,64 @@ function availableFirstPathSteps( csn ) {
|
|
|
2241
2303
|
return Array.from(unique);
|
|
2242
2304
|
}
|
|
2243
2305
|
|
|
2306
|
+
/**
|
|
2307
|
+
* Quotes the identifier using CDL-style ![]-quotes.
|
|
2308
|
+
*
|
|
2309
|
+
* NOTE: It is not guaranteed that the resulting string can _always_ be parsed!
|
|
2310
|
+
* If `id` contains newline characters, the resulting delimited identifier
|
|
2311
|
+
* will not be parsable by the compiler!
|
|
2312
|
+
*
|
|
2313
|
+
* @param id
|
|
2314
|
+
* @returns {string}
|
|
2315
|
+
*/
|
|
2316
|
+
function apiDelimitedId( id ) {
|
|
2317
|
+
return `![${id.replace(/]/g, ']]')}]`;
|
|
2318
|
+
}
|
|
2319
|
+
|
|
2244
2320
|
/**
|
|
2245
2321
|
* Returns a delimited identifier if the given identifier needs quoting.
|
|
2246
2322
|
* Because "special functions" such as SAP HANA RegEx functions have local keywords that
|
|
2247
2323
|
* are not default CDL keywords, specify a function name to take care of that.
|
|
2248
2324
|
*
|
|
2325
|
+
* NOTE: It is not guaranteed that the resulting string can _always_ be parsed!
|
|
2326
|
+
* If `id` contains newline characters, the resulting delimited identifier
|
|
2327
|
+
* will not be parsable by the compiler!
|
|
2328
|
+
*
|
|
2249
2329
|
* @param {string} id
|
|
2250
2330
|
* @param {null|string} insideFunction
|
|
2251
2331
|
* @return {string}
|
|
2252
2332
|
*/
|
|
2253
|
-
function
|
|
2333
|
+
function apiSmartId( id, insideFunction = null ) {
|
|
2254
2334
|
insideFunction = insideFunction?.toUpperCase();
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2335
|
+
const extra = insideFunction && specialFunctions[insideFunction] ? getAllKeywordsForSpecialFunction(insideFunction) : [];
|
|
2336
|
+
if (requiresQuotingForCdl(id, extra))
|
|
2337
|
+
return apiDelimitedId(id);
|
|
2338
|
+
return id;
|
|
2258
2339
|
}
|
|
2259
2340
|
|
|
2260
2341
|
/**
|
|
2261
2342
|
* Quote the given function name if required.
|
|
2262
2343
|
*
|
|
2344
|
+
* NOTE: It is not guaranteed that the resulting string can _always_ be parsed!
|
|
2345
|
+
* If `funcName` contains newline characters, the resulting delimited identifier
|
|
2346
|
+
* will not be parsable by the compiler!
|
|
2347
|
+
*
|
|
2263
2348
|
* @param {string} funcName
|
|
2264
2349
|
* @return {string}
|
|
2265
2350
|
*/
|
|
2266
|
-
function
|
|
2351
|
+
function apiSmartFunctionId( funcName ) {
|
|
2267
2352
|
const funcId = funcName.toUpperCase();
|
|
2268
2353
|
const requiresQuoting = !identifierRegex.test(funcName) ||
|
|
2269
2354
|
(keywords.cdl.includes(funcId) && !specialFunctions[funcId]);
|
|
2270
2355
|
if (requiresQuoting)
|
|
2271
|
-
return
|
|
2356
|
+
return apiDelimitedId(funcName);
|
|
2272
2357
|
return funcName;
|
|
2273
2358
|
}
|
|
2274
2359
|
|
|
2275
|
-
/**
|
|
2276
|
-
* @typedef CdlRenderEnvironment Rendering environment used throughout the render process.
|
|
2277
|
-
*
|
|
2278
|
-
* @property {string} indent Current indentation as a string, e.g. ' ' for two spaces.
|
|
2279
|
-
* @property {CSN.Path} [path] CSN path to the current artifact
|
|
2280
|
-
* @property {string} [artifactName] Name of the artifact - set in renderArtifact
|
|
2281
|
-
* @property {string} [elementName] Name of the element being rendered - set in renderElement
|
|
2282
|
-
* @property {string[]} [additionalKeywords] For function rendering: Words that are also keywords.
|
|
2283
|
-
*/
|
|
2284
2360
|
|
|
2285
2361
|
module.exports = {
|
|
2286
2362
|
csnToCdl,
|
|
2287
|
-
smartId,
|
|
2288
|
-
smartFunctionId,
|
|
2289
|
-
delimitedId,
|
|
2363
|
+
smartId: apiSmartId,
|
|
2364
|
+
smartFunctionId: apiSmartFunctionId,
|
|
2365
|
+
delimitedId: apiDelimitedId,
|
|
2290
2366
|
};
|