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