@sap/cds-compiler 2.15.8 → 3.1.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 +102 -1590
- package/bin/.eslintrc.json +2 -1
- package/bin/cdsc.js +61 -46
- package/doc/API.md +11 -0
- package/doc/CHANGELOG_ARCHIVE.md +1592 -0
- package/doc/CHANGELOG_BETA.md +26 -5
- package/doc/CHANGELOG_DEPRECATED.md +55 -1
- package/doc/{DeprecatedOptions.md → DeprecatedOptions_v2.md} +3 -1
- package/doc/Versioning.md +20 -1
- package/lib/api/.eslintrc.json +2 -2
- package/lib/api/main.js +282 -156
- package/lib/api/options.js +17 -88
- package/lib/api/validate.js +6 -10
- package/lib/base/keywords.js +280 -110
- package/lib/base/message-registry.js +85 -25
- package/lib/base/messages.js +119 -89
- package/lib/base/model.js +46 -2
- package/lib/base/optionProcessorHelper.js +53 -21
- package/lib/checks/actionsFunctions.js +15 -12
- package/lib/checks/annotationsOData.js +1 -1
- package/lib/checks/cdsPersistence.js +1 -0
- package/lib/checks/elements.js +6 -6
- package/lib/checks/invalidTarget.js +1 -1
- package/lib/checks/nonexpandableStructured.js +1 -1
- package/lib/checks/queryNoDbArtifacts.js +2 -1
- package/lib/checks/selectItems.js +101 -15
- package/lib/checks/types.js +7 -8
- package/lib/checks/utils.js +2 -2
- package/lib/checks/validator.js +3 -3
- package/lib/compiler/assert-consistency.js +78 -21
- package/lib/compiler/base.js +6 -4
- package/lib/compiler/builtins.js +177 -10
- package/lib/compiler/checks.js +1 -1
- package/lib/compiler/define.js +28 -23
- package/lib/compiler/extend.js +75 -18
- package/lib/compiler/finalize-parse-cdl.js +25 -18
- package/lib/compiler/index.js +27 -11
- package/lib/compiler/moduleLayers.js +7 -0
- package/lib/compiler/populate.js +26 -39
- package/lib/compiler/propagator.js +12 -7
- package/lib/compiler/resolve.js +207 -236
- package/lib/compiler/shared.js +100 -93
- package/lib/compiler/tweak-assocs.js +13 -20
- package/lib/compiler/utils.js +20 -6
- package/lib/edm/annotations/preprocessAnnotations.js +12 -13
- package/lib/edm/csn2edm.js +35 -37
- package/lib/edm/edm.js +22 -13
- package/lib/edm/edmAnnoPreprocessor.js +349 -0
- package/lib/edm/edmInboundChecks.js +85 -0
- package/lib/edm/edmPreprocessor.js +338 -689
- package/lib/edm/edmUtils.js +97 -67
- package/lib/gen/Dictionary.json +29 -9
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +8 -31
- package/lib/gen/language.tokens +105 -114
- package/lib/gen/languageLexer.interp +1 -34
- package/lib/gen/languageLexer.js +892 -1007
- package/lib/gen/languageLexer.tokens +95 -106
- package/lib/gen/languageParser.js +20629 -22474
- package/lib/inspect/.eslintrc.json +4 -0
- package/lib/inspect/index.js +14 -0
- package/lib/inspect/inspectModelStatistics.js +81 -0
- package/lib/inspect/inspectPropagation.js +189 -0
- package/lib/inspect/inspectUtils.js +44 -0
- package/lib/json/from-csn.js +74 -69
- package/lib/json/to-csn.js +17 -14
- package/lib/language/antlrParser.js +2 -2
- package/lib/language/docCommentParser.js +61 -38
- package/lib/language/errorStrategy.js +52 -40
- package/lib/language/genericAntlrParser.js +424 -292
- package/lib/language/language.g4 +604 -687
- package/lib/language/multiLineStringParser.js +14 -42
- package/lib/language/textUtils.js +44 -0
- package/lib/main.d.ts +28 -42
- package/lib/main.js +104 -81
- package/lib/model/api.js +1 -1
- package/lib/model/csnRefs.js +57 -30
- package/lib/model/csnUtils.js +189 -287
- package/lib/model/revealInternalProperties.js +32 -10
- package/lib/model/sortViews.js +32 -31
- package/lib/modelCompare/compare.js +3 -0
- package/lib/optionProcessor.js +91 -57
- package/lib/render/.eslintrc.json +1 -1
- package/lib/render/DuplicateChecker.js +4 -7
- package/lib/render/manageConstraints.js +70 -2
- package/lib/render/toCdl.js +387 -367
- package/lib/render/toHdbcds.js +20 -16
- package/lib/render/toRename.js +44 -22
- package/lib/render/toSql.js +81 -59
- package/lib/render/utils/common.js +16 -3
- package/lib/render/utils/sql.js +20 -19
- package/lib/sql-identifier.js +6 -0
- package/lib/transform/db/.eslintrc.json +3 -2
- package/lib/transform/db/associations.js +43 -35
- package/lib/transform/db/cdsPersistence.js +5 -16
- package/lib/transform/db/constraints.js +1 -1
- package/lib/transform/db/expansion.js +7 -6
- package/lib/transform/db/flattening.js +16 -18
- package/lib/transform/db/transformExists.js +7 -5
- package/lib/transform/db/views.js +3 -3
- package/lib/transform/draft/.eslintrc.json +2 -2
- package/lib/transform/draft/db.js +6 -6
- package/lib/transform/draft/odata.js +6 -7
- package/lib/transform/forHanaNew.js +30 -24
- package/lib/transform/forOdataNew.js +14 -16
- package/lib/transform/localized.js +35 -25
- package/lib/transform/odata/toFinalBaseType.js +10 -10
- package/lib/transform/odata/typesExposure.js +17 -8
- package/lib/transform/odata/utils.js +1 -38
- package/lib/transform/transformUtilsNew.js +63 -77
- package/lib/transform/translateAssocsToJoins.js +2 -2
- package/lib/transform/universalCsn/.eslintrc.json +2 -2
- package/lib/transform/universalCsn/coreComputed.js +11 -6
- package/lib/transform/universalCsn/universalCsnEnricher.js +33 -5
- package/lib/utils/file.js +31 -21
- package/lib/utils/moduleResolve.js +0 -1
- package/lib/utils/timetrace.js +20 -21
- package/package.json +34 -4
- package/share/messages/syntax-expected-integer.md +9 -8
- package/doc/ApiMigration.md +0 -237
- package/doc/CommandLineMigration.md +0 -58
- package/doc/ErrorMessages.md +0 -175
- package/doc/FioriAnnotations.md +0 -94
- package/doc/ODataTransformation.md +0 -273
- package/lib/backends.js +0 -529
- package/lib/checks/unknownMagic.js +0 -41
- package/lib/fix_antlr4-8_warning.js +0 -56
package/lib/json/from-csn.js
CHANGED
|
@@ -88,6 +88,7 @@
|
|
|
88
88
|
*/
|
|
89
89
|
|
|
90
90
|
const { dictAdd } = require('../base/dictionaries');
|
|
91
|
+
const { quotedLiteralPatterns } = require('../compiler/builtins');
|
|
91
92
|
|
|
92
93
|
const $location = Symbol.for('cds.$location');
|
|
93
94
|
|
|
@@ -136,7 +137,7 @@ const schemaClasses = {
|
|
|
136
137
|
condition: {
|
|
137
138
|
arrayOf: exprOrString,
|
|
138
139
|
type: condition,
|
|
139
|
-
msgId: 'syntax-
|
|
140
|
+
msgId: 'syntax-expected-term',
|
|
140
141
|
// TODO: also specify requires here, and adapt onlyWith()
|
|
141
142
|
optional: exprProperties,
|
|
142
143
|
},
|
|
@@ -146,11 +147,11 @@ const schemaClasses = {
|
|
|
146
147
|
},
|
|
147
148
|
natnumOrStar: {
|
|
148
149
|
type: natnumOrStar,
|
|
149
|
-
msgId: 'syntax-
|
|
150
|
+
msgId: 'syntax-expected-cardinality',
|
|
150
151
|
},
|
|
151
152
|
columns: {
|
|
152
153
|
arrayOf: selectItem,
|
|
153
|
-
msgId: 'syntax-
|
|
154
|
+
msgId: 'syntax-expected-column',
|
|
154
155
|
defaultKind: '$column',
|
|
155
156
|
validKinds: [], // pseudo kind '$column'
|
|
156
157
|
// A column with only as+cast.type is a new association
|
|
@@ -228,7 +229,7 @@ const schema = compileSchema( {
|
|
|
228
229
|
dictionaryOf: definition,
|
|
229
230
|
defaultKind: 'action',
|
|
230
231
|
validKinds: [ 'action', 'function' ],
|
|
231
|
-
inKind: [ 'entity', 'annotate', 'extend' ],
|
|
232
|
+
inKind: [ 'entity', 'aspect', 'annotate', 'extend' ],
|
|
232
233
|
},
|
|
233
234
|
params: {
|
|
234
235
|
dictionaryOf: definition,
|
|
@@ -291,7 +292,7 @@ const schema = compileSchema( {
|
|
|
291
292
|
// type properties (except: elements, enum, keys, on): ---------------------
|
|
292
293
|
type: {
|
|
293
294
|
type: artifactRef,
|
|
294
|
-
msgId: 'syntax-
|
|
295
|
+
msgId: 'syntax-expected-reference',
|
|
295
296
|
optional: [ 'ref', 'global' ],
|
|
296
297
|
inKind: [ 'element', 'type', 'param', 'mixin', 'event', 'annotation' ],
|
|
297
298
|
},
|
|
@@ -367,7 +368,7 @@ const schema = compileSchema( {
|
|
|
367
368
|
ref: {
|
|
368
369
|
arrayOf: refItem,
|
|
369
370
|
type: renameTo( 'path', arrayOf( refItem ) ),
|
|
370
|
-
msgId: 'syntax-
|
|
371
|
+
msgId: 'syntax-expected-reference',
|
|
371
372
|
minLength: 1,
|
|
372
373
|
requires: 'id',
|
|
373
374
|
optional: [ 'id', 'args', 'cardinality', 'where' ],
|
|
@@ -583,7 +584,7 @@ const schema = compileSchema( {
|
|
|
583
584
|
inKind: [ 'element', '$column' ],
|
|
584
585
|
},
|
|
585
586
|
masked: {
|
|
586
|
-
type:
|
|
587
|
+
type: masked,
|
|
587
588
|
inKind: [ 'element' ],
|
|
588
589
|
},
|
|
589
590
|
notNull: {
|
|
@@ -683,15 +684,6 @@ const topLevelSpec = {
|
|
|
683
684
|
schema,
|
|
684
685
|
};
|
|
685
686
|
|
|
686
|
-
const validLiteralsExtra = Object.assign( Object.create(null), {
|
|
687
|
-
// TODO: should we use quotedLiteralPatterns from genericAntlrParser?
|
|
688
|
-
number: 'string',
|
|
689
|
-
x: 'string',
|
|
690
|
-
time: 'string',
|
|
691
|
-
date: 'string',
|
|
692
|
-
timestamp: 'string',
|
|
693
|
-
} );
|
|
694
|
-
|
|
695
687
|
// Module variables, schema compilation, and functors ------------------------
|
|
696
688
|
|
|
697
689
|
/** @type {(id, location, textOrArguments, texts?) => void} */
|
|
@@ -780,7 +772,7 @@ function arrayOf( fn, filter = undefined ) {
|
|
|
780
772
|
} );
|
|
781
773
|
const minLength = spec.minLength || 0;
|
|
782
774
|
if (minLength > val.length) {
|
|
783
|
-
message( 'syntax-
|
|
775
|
+
message( 'syntax-expected-length', location(true),
|
|
784
776
|
{ prop: spec.prop, n: minLength, '#': minLength === 1 ? 'one' : 'std' });
|
|
785
777
|
}
|
|
786
778
|
if (val.length)
|
|
@@ -850,7 +842,7 @@ function object( obj, spec ) {
|
|
|
850
842
|
if (requires === undefined || requires === true) {
|
|
851
843
|
// console.log(csnProps,JSON.stringify(spec))
|
|
852
844
|
if (!relevantProps) {
|
|
853
|
-
error( 'syntax-
|
|
845
|
+
error( 'syntax-required-subproperty', location(true),
|
|
854
846
|
{
|
|
855
847
|
prop: spec.msgProp,
|
|
856
848
|
'#': (
|
|
@@ -876,7 +868,7 @@ function object( obj, spec ) {
|
|
|
876
868
|
|
|
877
869
|
function vZeroDelete( o, spec ) { // for old-CSN property 'origin'
|
|
878
870
|
if (!csnVersionZero) {
|
|
879
|
-
warning( 'syntax-
|
|
871
|
+
warning( 'syntax-zero-delete', location(true), { prop: spec.msgProp },
|
|
880
872
|
'Delete/inline CSN v0.1.0 property $(PROP)' );
|
|
881
873
|
}
|
|
882
874
|
string( o, spec );
|
|
@@ -961,7 +953,7 @@ function definition( def, spec, xsn, csn, name ) {
|
|
|
961
953
|
function dictionaryOf( elementFct ) {
|
|
962
954
|
return function dictionary( dict, spec ) {
|
|
963
955
|
if (!dict || typeof dict !== 'object' || Array.isArray( dict )) {
|
|
964
|
-
error( 'syntax-
|
|
956
|
+
error( 'syntax-expected-object', location(true),
|
|
965
957
|
{ prop: spec.prop }); // spec.prop, not spec.msgProp!
|
|
966
958
|
return ignore( dict );
|
|
967
959
|
}
|
|
@@ -973,7 +965,7 @@ function dictionaryOf( elementFct ) {
|
|
|
973
965
|
++virtualLine;
|
|
974
966
|
for (const name of allNames) {
|
|
975
967
|
if (!name) {
|
|
976
|
-
warning( 'syntax-
|
|
968
|
+
warning( 'syntax-empty-name', location(true),
|
|
977
969
|
{ prop: spec.prop }, // TODO: Error
|
|
978
970
|
'Property names in dictionary $(PROP) must not be empty' );
|
|
979
971
|
}
|
|
@@ -1050,11 +1042,11 @@ function validKind( val, spec, xsn ) {
|
|
|
1050
1042
|
if (val === xsn.kind) // has been set in definition - the same = ok!
|
|
1051
1043
|
return undefined; // already set in definition
|
|
1052
1044
|
if (val === 'view' && xsn.kind === 'entity') {
|
|
1053
|
-
warning( 'syntax-
|
|
1045
|
+
warning( 'syntax-zero-value', location(true), { prop: spec.msgProp },
|
|
1054
1046
|
'Replace CSN v0.1.0 value in $(PROP) by something specified' );
|
|
1055
1047
|
}
|
|
1056
1048
|
else if ((val === 'entity' || val === 'type') && xsn.kind === 'aspect') {
|
|
1057
|
-
info( 'syntax-
|
|
1049
|
+
info( 'syntax-aspect', location(true), { kind: 'aspect', '#': val },
|
|
1058
1050
|
{
|
|
1059
1051
|
std: 'Use the dedicated kind $(KIND) for aspect definitions',
|
|
1060
1052
|
// eslint-disable-next-line max-len
|
|
@@ -1062,7 +1054,7 @@ function validKind( val, spec, xsn ) {
|
|
|
1062
1054
|
} );
|
|
1063
1055
|
}
|
|
1064
1056
|
else {
|
|
1065
|
-
error( 'syntax-
|
|
1057
|
+
error( 'syntax-expected-valid', location(true), { prop: spec.msgProp },
|
|
1066
1058
|
'Expected valid string for property $(PROP)' );
|
|
1067
1059
|
}
|
|
1068
1060
|
return ignore( val );
|
|
@@ -1104,7 +1096,7 @@ function vZeroRef( name, spec, xsn ) {
|
|
|
1104
1096
|
return;
|
|
1105
1097
|
const path = name.split('.');
|
|
1106
1098
|
if (!path.every( id => id)) {
|
|
1107
|
-
warning( 'syntax-
|
|
1099
|
+
warning( 'syntax-expected-name', location(true), { prop: spec.msgProp },
|
|
1108
1100
|
'Expected correct name for property $(PROP)' );
|
|
1109
1101
|
}
|
|
1110
1102
|
xsn.path = path.map( id => ({ id, location: location() }) );
|
|
@@ -1115,7 +1107,7 @@ function vZeroRef( name, spec, xsn ) {
|
|
|
1115
1107
|
function boolOrNull( val, spec ) {
|
|
1116
1108
|
if ([ true, false, null ].includes( val ))
|
|
1117
1109
|
return { val, location: location() };
|
|
1118
|
-
warning( 'syntax-
|
|
1110
|
+
warning( 'syntax-expected-boolean', location(true), { prop: spec.msgProp },
|
|
1119
1111
|
'Expected boolean or null for property $(PROP)' );
|
|
1120
1112
|
ignore( val );
|
|
1121
1113
|
return { val: !!val, location: location() };
|
|
@@ -1125,7 +1117,7 @@ function string( val, spec ) {
|
|
|
1125
1117
|
if (typeof val === 'string' && val)
|
|
1126
1118
|
// XSN TODO: do not require literal
|
|
1127
1119
|
return val;
|
|
1128
|
-
error( 'syntax-
|
|
1120
|
+
error( 'syntax-expected-string', location(true), { prop: spec.msgProp },
|
|
1129
1121
|
'Expected non-empty string for property $(PROP)' );
|
|
1130
1122
|
return ignore( val );
|
|
1131
1123
|
}
|
|
@@ -1134,7 +1126,7 @@ function stringVal( val, spec ) {
|
|
|
1134
1126
|
if (typeof val === 'string' && val)
|
|
1135
1127
|
// XSN TODO: do not require literal
|
|
1136
1128
|
return { val, literal: 'string', location: location() };
|
|
1137
|
-
error( 'syntax-
|
|
1129
|
+
error( 'syntax-expected-string', location(true), { prop: spec.msgProp },
|
|
1138
1130
|
'Expected non-empty string for property $(PROP)' );
|
|
1139
1131
|
return ignore( val );
|
|
1140
1132
|
}
|
|
@@ -1156,7 +1148,7 @@ function natnum( val, spec ) {
|
|
|
1156
1148
|
if (typeof val === 'number' && val >= 0)
|
|
1157
1149
|
// XSN TODO: do not require literal
|
|
1158
1150
|
return { val, literal: 'number', location: location() };
|
|
1159
|
-
error( spec.msgId || 'syntax-
|
|
1151
|
+
error( spec.msgId || 'syntax-expected-natnum', location(true),
|
|
1160
1152
|
{ prop: spec.msgProp } );
|
|
1161
1153
|
return ignore( val );
|
|
1162
1154
|
}
|
|
@@ -1191,10 +1183,8 @@ function annoValue( val, spec ) {
|
|
|
1191
1183
|
/** @type {string|boolean} */
|
|
1192
1184
|
let seenEllipsis = false;
|
|
1193
1185
|
if (arrayLevelCount > 0) { // TODO: also inside structure (possible in CSN!)
|
|
1194
|
-
if (val.some( isEllipsis ))
|
|
1195
|
-
error( 'syntax-
|
|
1196
|
-
'Unexpected $(CODE) in nested array' );
|
|
1197
|
-
}
|
|
1186
|
+
if (val.some( isEllipsis ))
|
|
1187
|
+
error( 'syntax-unexpected-ellipsis', location(true), { '#': 'nested-array', code: '...' } );
|
|
1198
1188
|
}
|
|
1199
1189
|
else {
|
|
1200
1190
|
for (const item of val) {
|
|
@@ -1203,7 +1193,7 @@ function annoValue( val, spec ) {
|
|
|
1203
1193
|
}
|
|
1204
1194
|
else if (isEllipsis( item )) { // with or without UP TO
|
|
1205
1195
|
// error position at the beginning of the array, but that is fine
|
|
1206
|
-
error( 'syntax-
|
|
1196
|
+
error( 'syntax-duplicate-ellipsis', location(true), { code: '...' },
|
|
1207
1197
|
'Expected no more than one $(CODE)' );
|
|
1208
1198
|
break;
|
|
1209
1199
|
}
|
|
@@ -1217,7 +1207,7 @@ function annoValue( val, spec ) {
|
|
|
1217
1207
|
};
|
|
1218
1208
|
arrayLevelCount--;
|
|
1219
1209
|
if (seenEllipsis === 'upTo') {
|
|
1220
|
-
error( 'syntax-
|
|
1210
|
+
error( 'syntax-expecting-ellipsis', location(true), // at closing bracket
|
|
1221
1211
|
{ code: '... up to', newcode: '...' },
|
|
1222
1212
|
// TODO: should we be more CSN specific in the message?
|
|
1223
1213
|
'Expecting an array item $(NEWCODE) after an item with $(CODE)' );
|
|
@@ -1264,11 +1254,14 @@ function annoValue( val, spec ) {
|
|
|
1264
1254
|
}
|
|
1265
1255
|
|
|
1266
1256
|
function annotation( val, spec, xsn, csn, name ) {
|
|
1267
|
-
const
|
|
1268
|
-
|
|
1257
|
+
const absolute = (xsn ? name.substring(1) : name);
|
|
1258
|
+
// TODO: really care about variant (qualifier parts)?
|
|
1259
|
+
const variantIndex = absolute.indexOf('#') + 1 || absolute.length;
|
|
1260
|
+
const n = refSplit( absolute.substring( 0, variantIndex ), spec.msgProp );
|
|
1269
1261
|
if (!n)
|
|
1270
1262
|
return undefined;
|
|
1271
|
-
|
|
1263
|
+
n.absolute = absolute;
|
|
1264
|
+
if (variantIndex < absolute.length)
|
|
1272
1265
|
n.variant = { id: name.substring( variantIndex ), location: location() };
|
|
1273
1266
|
const r = annoValue( val, spec );
|
|
1274
1267
|
r.name = n;
|
|
@@ -1283,21 +1276,27 @@ function value( val, spec, xsn ) { // for CSN property 'val'
|
|
|
1283
1276
|
xsn.literal = (val === null) ? 'null' : typeof val;
|
|
1284
1277
|
return val;
|
|
1285
1278
|
}
|
|
1286
|
-
error( 'syntax-
|
|
1279
|
+
error( 'syntax-expected-scalar', location(true), { prop: spec.msgProp },
|
|
1287
1280
|
'Only scalar values are supported for property $(PROP)' );
|
|
1288
1281
|
return ignore( val );
|
|
1289
1282
|
}
|
|
1290
1283
|
|
|
1291
|
-
function literal(
|
|
1284
|
+
function literal( lit, spec, xsn, csn ) {
|
|
1292
1285
|
// TODO: general: requires other property (here: 'val')
|
|
1293
1286
|
const type = (csn.val == null) ? 'null' : typeof csn.val;
|
|
1294
|
-
if (
|
|
1295
|
-
return
|
|
1296
|
-
if (typeof
|
|
1297
|
-
|
|
1298
|
-
|
|
1287
|
+
if (lit === type) // also for 'object' which is an error for 'val'
|
|
1288
|
+
return lit;
|
|
1289
|
+
if (typeof lit === 'string' && quotedLiteralPatterns[lit]?.json_type === type) {
|
|
1290
|
+
const p = quotedLiteralPatterns[lit];
|
|
1291
|
+
if (p && p.test_fn && !p.test_fn(csn.val))
|
|
1292
|
+
warning( 'syntax-invalid-literal', location(), { '#': p.test_variant } );
|
|
1293
|
+
return lit;
|
|
1294
|
+
}
|
|
1295
|
+
if (lit === 'number' && type === 'string') // special case, not a quoted literal in CDL
|
|
1296
|
+
return lit;
|
|
1297
|
+
error( 'syntax-expected-valid', location(true), { prop: spec.msgProp },
|
|
1299
1298
|
'Expected valid string for property $(PROP)' );
|
|
1300
|
-
return ignore(
|
|
1299
|
+
return ignore( lit );
|
|
1301
1300
|
}
|
|
1302
1301
|
|
|
1303
1302
|
function func( val, spec, xsn ) {
|
|
@@ -1310,7 +1309,7 @@ function func( val, spec, xsn ) {
|
|
|
1310
1309
|
function xpr( exprs, spec, xsn, csn ) {
|
|
1311
1310
|
if (csn.func) {
|
|
1312
1311
|
if (!exprs.length) {
|
|
1313
|
-
message( 'syntax-
|
|
1312
|
+
message( 'syntax-expected-length', location(true),
|
|
1314
1313
|
{ prop: 'xpr', otherprop: 'func', '#': 'suffix' });
|
|
1315
1314
|
}
|
|
1316
1315
|
xsn.suffix = exprArgs( exprs, spec );
|
|
@@ -1343,7 +1342,7 @@ function args( exprs, spec ) {
|
|
|
1343
1342
|
return arrayOf( exprOrString )( exprs, spec );
|
|
1344
1343
|
}
|
|
1345
1344
|
else if (!exprs || typeof exprs !== 'object') {
|
|
1346
|
-
error( 'syntax-
|
|
1345
|
+
error( 'syntax-expected-args', location(true),
|
|
1347
1346
|
{ prop: spec.prop }, // spec.prop, not spec.msgProp!
|
|
1348
1347
|
'Expected array or object for property $(PROP)' );
|
|
1349
1348
|
return ignore( exprs );
|
|
@@ -1406,12 +1405,12 @@ function condition( cond, spec ) {
|
|
|
1406
1405
|
function vZeroValue( obj, spec, xsn ) {
|
|
1407
1406
|
if (xsn.value) {
|
|
1408
1407
|
// TODO: also "sign" xsn.value created by inValue to complain about both 'value' and 'ref' etc
|
|
1409
|
-
warning( 'syntax-
|
|
1408
|
+
warning( 'syntax-unexpected-property', location(true), { prop: spec.msgProp },
|
|
1410
1409
|
'Unexpected CSN property $(PROP)' );
|
|
1411
1410
|
return undefined;
|
|
1412
1411
|
}
|
|
1413
1412
|
if (!csnVersionZero) {
|
|
1414
|
-
warning( 'syntax-
|
|
1413
|
+
warning( 'syntax-zero-delete', location(true), { prop: spec.msgProp },
|
|
1415
1414
|
'Delete/inline CSN v0.1.0 property $(PROP)' );
|
|
1416
1415
|
}
|
|
1417
1416
|
return expr( obj, spec );
|
|
@@ -1458,6 +1457,12 @@ function excluding( array, spec, xsn ) {
|
|
|
1458
1457
|
xsn.excludingDict = r;
|
|
1459
1458
|
}
|
|
1460
1459
|
|
|
1460
|
+
function masked( val, spec ) {
|
|
1461
|
+
message('syntax-invalid-masked', location(), { keyword: 'masked' },
|
|
1462
|
+
'Keyword $(KEYWORD) not supported');
|
|
1463
|
+
return boolOrNull( val, spec );
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1461
1466
|
function duplicateExcluding( name, loc ) {
|
|
1462
1467
|
error( 'duplicate-excluding', loc, { name, keyword: 'excluding' },
|
|
1463
1468
|
'Duplicate $(NAME) in the $(KEYWORD) clause' );
|
|
@@ -1478,7 +1483,7 @@ function join( val, spec, xsn ) {
|
|
|
1478
1483
|
|
|
1479
1484
|
function queryArgs( val, spec, xsn, csn ) {
|
|
1480
1485
|
if (Array.isArray( val ) && val.length > 1 && !csn.op) {
|
|
1481
|
-
warning( 'syntax-
|
|
1486
|
+
warning( 'syntax-expected-property', location(true),
|
|
1482
1487
|
{ prop: 'args', otherprop: 'op' },
|
|
1483
1488
|
'CSN property $(PROP) expects property $(OTHERPROP) to be specified' );
|
|
1484
1489
|
xsn.op = { val: 'union', location: location() };
|
|
@@ -1497,7 +1502,7 @@ function i18nLang( val, spec, xsn, csn, langKey ) {
|
|
|
1497
1502
|
function translations( keyVal, spec, xsn, csn, textKey ) {
|
|
1498
1503
|
if (typeof keyVal === 'string') // allow empty string
|
|
1499
1504
|
return { val: keyVal, literal: 'string', location: location() };
|
|
1500
|
-
error( 'syntax-
|
|
1505
|
+
error( 'syntax-expected-translation', location(true),
|
|
1501
1506
|
{ prop: textKey, otherprop: spec.prop },
|
|
1502
1507
|
'Expected string for text key $(PROP) of language $(OTHERPROP)' );
|
|
1503
1508
|
return ignore( keyVal );
|
|
@@ -1511,7 +1516,7 @@ function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
|
|
|
1511
1516
|
if (!s || s.noPrefix && prop !== p0 ) {
|
|
1512
1517
|
if (ourpropsRegex.test( prop )) {
|
|
1513
1518
|
// TODO v2: Warning only with --sloppy
|
|
1514
|
-
warning( 'syntax-
|
|
1519
|
+
warning( 'syntax-unknown-property', location(true), { prop },
|
|
1515
1520
|
'Unknown CSN property $(PROP)' );
|
|
1516
1521
|
}
|
|
1517
1522
|
else { // TODO v2: always (i.e. also with message) add to $extra
|
|
@@ -1522,14 +1527,14 @@ function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
|
|
|
1522
1527
|
if (s.ignore)
|
|
1523
1528
|
return { type: ignore };
|
|
1524
1529
|
if (s.vZeroIgnore && s.vZeroIgnore === csn[prop]) { // for "op": "call"
|
|
1525
|
-
warning( 'syntax-
|
|
1530
|
+
warning( 'syntax-zero-delete', location(true), { prop },
|
|
1526
1531
|
'Delete/inline CSN v0.1.0 property $(PROP)' );
|
|
1527
1532
|
return { type: ignore };
|
|
1528
1533
|
}
|
|
1529
1534
|
const zero = s.vZeroFor;
|
|
1530
1535
|
if (zero) { // (potential) CSN v0.1.0 property
|
|
1531
1536
|
const group = s.xorGroup;
|
|
1532
|
-
if (
|
|
1537
|
+
if (expected( zero, schema[zero] ) && !(group && xor[group])) {
|
|
1533
1538
|
replaceZeroProp( prop, zero );
|
|
1534
1539
|
if (group)
|
|
1535
1540
|
xor[group] = prop;
|
|
@@ -1541,7 +1546,7 @@ function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
|
|
|
1541
1546
|
const variant = kind && s.inKind
|
|
1542
1547
|
? ([ 'extend', 'annotate' ].includes(kind) ? kind : 'def')
|
|
1543
1548
|
: (parentSpec.msgProp ? 'std' : 'top');
|
|
1544
|
-
message( 'syntax-
|
|
1549
|
+
message( 'syntax-unexpected-property', location(true),
|
|
1545
1550
|
{
|
|
1546
1551
|
prop, otherprop: parentSpec.msgProp, kind, '#': variant,
|
|
1547
1552
|
},
|
|
@@ -1549,7 +1554,7 @@ function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
|
|
|
1549
1554
|
std: 'CSN property $(PROP) is not expected in $(OTHERPROP)',
|
|
1550
1555
|
top: 'CSN property $(PROP) is not expected top-level',
|
|
1551
1556
|
def: 'CSN property $(PROP) is not expected by a definition of kind $(KIND)',
|
|
1552
|
-
extend: 'CSN property $(PROP) is not expected by an extend in $(OTHERPROP)
|
|
1557
|
+
extend: 'CSN property $(PROP) is not expected by an extend in $(OTHERPROP)',
|
|
1553
1558
|
annotate: 'CSN property $(PROP) is not expected by an annotate in $(OTHERPROP)',
|
|
1554
1559
|
} );
|
|
1555
1560
|
// TODO: or still augment it? (but then also handle xorGroup)
|
|
@@ -1599,13 +1604,13 @@ function onlyWith( spec, need, csn, prop, xor, expected ) {
|
|
|
1599
1604
|
need = allowed.find( p => !xor[schema[p].xorGroup] ) || allowed[0];
|
|
1600
1605
|
}
|
|
1601
1606
|
if (prop) {
|
|
1602
|
-
error( 'syntax-
|
|
1607
|
+
error( 'syntax-dependent-property', location(true),
|
|
1603
1608
|
{ prop, otherprop: need },
|
|
1604
1609
|
'CSN property $(PROP) can only be used in combination with $(OTHERPROP)');
|
|
1605
1610
|
xor['no:req'] = prop;
|
|
1606
1611
|
}
|
|
1607
1612
|
else if (!xor['no:req']) {
|
|
1608
|
-
error( 'syntax-
|
|
1613
|
+
error( 'syntax-required-property', location(true),
|
|
1609
1614
|
{ prop: need, otherprop: spec.msgProp, '#': spec.prop },
|
|
1610
1615
|
{ // TODO $(PARENT), TODO: do not use prop===0 hack
|
|
1611
1616
|
std: 'Object in $(OTHERPROP) must have the property $(PROP)',
|
|
@@ -1627,7 +1632,7 @@ function checkAndSetXorGroup( group, prop, xor ) {
|
|
|
1627
1632
|
if (prop === 'func' && xor[group] === 'xpr' ||
|
|
1628
1633
|
prop === 'xpr' && xor[group] === 'func')
|
|
1629
1634
|
return true; // hack for window function: both func and xpr is allowed
|
|
1630
|
-
error( 'syntax-
|
|
1635
|
+
error( 'syntax-excluded-property', location(true),
|
|
1631
1636
|
{ prop, otherprop: xor[group] },
|
|
1632
1637
|
'CSN property $(PROP) can only be used alternatively to $(OTHERPROP)');
|
|
1633
1638
|
return false;
|
|
@@ -1642,7 +1647,7 @@ function implicitName( ref ) {
|
|
|
1642
1647
|
function replaceZeroProp( otherprop, prop ) {
|
|
1643
1648
|
if (csnVersionZero)
|
|
1644
1649
|
return;
|
|
1645
|
-
warning( 'syntax-
|
|
1650
|
+
warning( 'syntax-zero-prop', location(true), { prop, otherprop },
|
|
1646
1651
|
'Replace CSN v0.1.0 property $(OTHERPROP) by $(PROP)' );
|
|
1647
1652
|
}
|
|
1648
1653
|
|
|
@@ -1651,7 +1656,7 @@ function replaceZeroProp( otherprop, prop ) {
|
|
|
1651
1656
|
function isArray( array, spec ) {
|
|
1652
1657
|
if (Array.isArray( array ))
|
|
1653
1658
|
return array;
|
|
1654
|
-
error( 'syntax-
|
|
1659
|
+
error( 'syntax-expected-array', location(true), { prop: spec.prop },
|
|
1655
1660
|
'Expected array for property $(PROP)' );
|
|
1656
1661
|
return ignore( array );
|
|
1657
1662
|
}
|
|
@@ -1659,7 +1664,7 @@ function isArray( array, spec ) {
|
|
|
1659
1664
|
function isObject( obj, spec ) {
|
|
1660
1665
|
if (obj && typeof obj === 'object' && !Array.isArray( obj ))
|
|
1661
1666
|
return obj;
|
|
1662
|
-
error( spec.msgId || 'syntax-
|
|
1667
|
+
error( spec.msgId || 'syntax-expected-object', location(true),
|
|
1663
1668
|
{ prop: spec.msgProp });
|
|
1664
1669
|
return ignore( obj );
|
|
1665
1670
|
}
|
|
@@ -1667,7 +1672,7 @@ function isObject( obj, spec ) {
|
|
|
1667
1672
|
function refSplit( name, prop ) {
|
|
1668
1673
|
const path = name.split('.');
|
|
1669
1674
|
if (!path.every( id => id)) {
|
|
1670
|
-
warning( 'syntax-
|
|
1675
|
+
warning( 'syntax-expected-name', location(true), { prop },
|
|
1671
1676
|
'Expected correct name for property $(PROP)' );
|
|
1672
1677
|
}
|
|
1673
1678
|
return { path: path.map( id => ({ id, location: location() }) ), location: location() };
|
|
@@ -1675,7 +1680,7 @@ function refSplit( name, prop ) {
|
|
|
1675
1680
|
|
|
1676
1681
|
function replaceZeroValue( spec ) {
|
|
1677
1682
|
if (!csnVersionZero && spec.vZeroFor == null) { // but 0 does not match!
|
|
1678
|
-
warning( 'syntax-
|
|
1683
|
+
warning( 'syntax-zero-value', location(true), { prop: spec.msgProp },
|
|
1679
1684
|
'Replace CSN v0.1.0 value in $(PROP) by something specified' );
|
|
1680
1685
|
}
|
|
1681
1686
|
}
|
|
@@ -1705,7 +1710,7 @@ function pushLocation( obj ) {
|
|
|
1705
1710
|
else if (!loc || typeof loc !== 'string') {
|
|
1706
1711
|
if (loc)
|
|
1707
1712
|
dollarLocations.push( null ); // must match with popLocation()
|
|
1708
|
-
error( 'syntax-
|
|
1713
|
+
error( 'syntax-expected-object', location(true), { prop: '$location' } );
|
|
1709
1714
|
}
|
|
1710
1715
|
// hidden feature: string $location
|
|
1711
1716
|
const m = /:(\d+)(?::(\d+))?$/.exec( loc ); // extra '^'s at end deliberately left out
|
|
@@ -1777,7 +1782,7 @@ function toXsn( csn, filename, options, messageFunctions ) {
|
|
|
1777
1782
|
}
|
|
1778
1783
|
|
|
1779
1784
|
|
|
1780
|
-
function augment( csn, filename = 'csn.json', options = {}, messageFunctions ) {
|
|
1785
|
+
function augment( csn, filename = 'csn.json', options = {}, messageFunctions = {} ) {
|
|
1781
1786
|
try {
|
|
1782
1787
|
return toXsn( csn, filename, options, messageFunctions );
|
|
1783
1788
|
}
|
|
@@ -1787,7 +1792,7 @@ function augment( csn, filename = 'csn.json', options = {}, messageFunctions ) {
|
|
|
1787
1792
|
}
|
|
1788
1793
|
}
|
|
1789
1794
|
|
|
1790
|
-
function parse( source, filename = 'csn.json', options = {}, messageFunctions ) {
|
|
1795
|
+
function parse( source, filename = 'csn.json', options = {}, messageFunctions = {} ) {
|
|
1791
1796
|
try {
|
|
1792
1797
|
return augment( JSON.parse(source), filename, options, messageFunctions );
|
|
1793
1798
|
}
|
|
@@ -1818,7 +1823,7 @@ function parse( source, filename = 'csn.json', options = {}, messageFunctions )
|
|
|
1818
1823
|
line,
|
|
1819
1824
|
col: column,
|
|
1820
1825
|
};
|
|
1821
|
-
messageFunctions.error( 'syntax-
|
|
1826
|
+
messageFunctions.error( 'syntax-illegal-json', loc, { msg }, 'Illegal JSON: $(MSG)' );
|
|
1822
1827
|
return xsn;
|
|
1823
1828
|
}
|
|
1824
1829
|
}
|
package/lib/json/to-csn.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
const { locationString } = require('../base/messages');
|
|
15
15
|
const { isBetaEnabled, isDeprecatedEnabled } = require('../base/model');
|
|
16
|
+
const { pathName } = require('../compiler/utils');
|
|
16
17
|
|
|
17
18
|
const compilerVersion = require('../../package.json').version;
|
|
18
19
|
const creator = `CDS Compiler v${ compilerVersion }`;
|
|
@@ -126,9 +127,6 @@ const transformers = {
|
|
|
126
127
|
// location is not renamed to $location as the name is well established in
|
|
127
128
|
// XSN and too many places (also outside the compiler) had to be adapted
|
|
128
129
|
location, // non-enumerable $location in CSN
|
|
129
|
-
$a2j: (e, csn) => { // on artifact level
|
|
130
|
-
Object.assign( csn, e );
|
|
131
|
-
},
|
|
132
130
|
$extra: (e, csn) => {
|
|
133
131
|
Object.assign( csn, e );
|
|
134
132
|
},
|
|
@@ -224,7 +222,7 @@ const operators = {
|
|
|
224
222
|
unboundedFollowing: [ 'unbounded', 'following' ],
|
|
225
223
|
following: postfix( [ 'following' ] ),
|
|
226
224
|
frameBetween: exprs => [ 'between', ...exprs[0], 'and', ...exprs[1] ],
|
|
227
|
-
|
|
225
|
+
ixpr: exprs => [].concat( ...exprs ), // xpr extra, due to extra parentheses
|
|
228
226
|
};
|
|
229
227
|
|
|
230
228
|
const csnDictionaries = [
|
|
@@ -727,7 +725,8 @@ function annotationsAndDocComment( node, annotated ) {
|
|
|
727
725
|
const val = node[prop];
|
|
728
726
|
// val.$priority isn't set for computed annotations like @Core.Computed
|
|
729
727
|
// and @odata.containment.ignore
|
|
730
|
-
|
|
728
|
+
// TODO: use $inferred instead special $priority value
|
|
729
|
+
if (val.$priority !== undefined && (!!val.$priority) === annotated) {
|
|
731
730
|
// transformer (= value) takes care to exclude $inferred annotation assignments
|
|
732
731
|
const sub = transformer( val );
|
|
733
732
|
// As value() just has one value, so we do not provide ( val, csn, node, prop )
|
|
@@ -1219,8 +1218,8 @@ function value( node ) {
|
|
|
1219
1218
|
if (node.$inferred && gensrcFlavor)
|
|
1220
1219
|
return undefined;
|
|
1221
1220
|
if (node.path) {
|
|
1222
|
-
const ref = node.path
|
|
1223
|
-
return extra( { '=': node.variant ? `${ ref }#${ node.variant.
|
|
1221
|
+
const ref = pathName( node.path );
|
|
1222
|
+
return extra( { '=': node.variant ? `${ ref }#${ pathName(node.variant.path) }` : ref }, node );
|
|
1224
1223
|
}
|
|
1225
1224
|
if (node.literal === 'enum')
|
|
1226
1225
|
return extra( { '#': node.sym.id }, node );
|
|
@@ -1276,8 +1275,11 @@ function expression( node, dollarExtra ) {
|
|
|
1276
1275
|
return { ref: [ node.param.val ], param: true }; // CDL rule for runtimes
|
|
1277
1276
|
}
|
|
1278
1277
|
if (node.path) {
|
|
1278
|
+
const ref = node.path.map( pathItem );
|
|
1279
|
+
if (node.path.$prefix)
|
|
1280
|
+
ref.unshift( node.path.$prefix );
|
|
1279
1281
|
// we would need to consider node.global here if we introduce that
|
|
1280
|
-
return extra( { ref
|
|
1282
|
+
return extra( { ref }, dollarExtraNode );
|
|
1281
1283
|
}
|
|
1282
1284
|
if (node.literal) {
|
|
1283
1285
|
if (typeof node.val === node.literal || node.val === null)
|
|
@@ -1590,10 +1592,11 @@ function compactExpr( e ) { // TODO: options
|
|
|
1590
1592
|
*/
|
|
1591
1593
|
function initModuleVars( options = { csnFlavor: 'gensrc' } ) {
|
|
1592
1594
|
gensrcFlavor = options.parseCdl || options.csnFlavor === 'gensrc' ||
|
|
1593
|
-
|
|
1594
|
-
universalCsn = (options.csnFlavor === 'universal' ||
|
|
1595
|
-
|
|
1596
|
-
|
|
1595
|
+
( options.toCsn && options.toCsn.flavor === 'gensrc');
|
|
1596
|
+
universalCsn = ( options.csnFlavor === 'universal' ||
|
|
1597
|
+
( options.toCsn && options.toCsn.flavor === 'universal') ) &&
|
|
1598
|
+
isBetaEnabled( options, 'enableUniversalCsn' ) &&
|
|
1599
|
+
!options.parseCdl;
|
|
1597
1600
|
strictMode = options.testMode;
|
|
1598
1601
|
const proto = options.dictionaryPrototype;
|
|
1599
1602
|
// eslint-disable-next-line no-nested-ternary
|
|
@@ -1601,8 +1604,8 @@ function initModuleVars( options = { csnFlavor: 'gensrc' } ) {
|
|
|
1601
1604
|
? proto
|
|
1602
1605
|
: (proto) ? Object.prototype : null;
|
|
1603
1606
|
withLocations = options.withLocations;
|
|
1604
|
-
parensAsStrings = isDeprecatedEnabled( options, '
|
|
1605
|
-
projectionAsQuery = isDeprecatedEnabled( options, '
|
|
1607
|
+
parensAsStrings = isDeprecatedEnabled( options, '_parensAsStrings' );
|
|
1608
|
+
projectionAsQuery = isDeprecatedEnabled( options, '_projectionAsQuery' );
|
|
1606
1609
|
}
|
|
1607
1610
|
|
|
1608
1611
|
module.exports = {
|
|
@@ -13,8 +13,8 @@ const antlr4 = require('antlr4');
|
|
|
13
13
|
const { CompileMessage } = require('../base/messages');
|
|
14
14
|
const errorStrategy = require('./errorStrategy');
|
|
15
15
|
|
|
16
|
-
const Parser = require('../gen/languageParser').
|
|
17
|
-
const Lexer = require('../gen/languageLexer').
|
|
16
|
+
const Parser = require('../gen/languageParser').default;
|
|
17
|
+
const Lexer = require('../gen/languageLexer').default;
|
|
18
18
|
|
|
19
19
|
// Error listener used for ANTLR4-generated parser
|
|
20
20
|
class ErrorListener extends antlr4.error.ErrorListener {
|