@sap/cds-compiler 2.4.4 → 2.10.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 +241 -1
- package/bin/.eslintrc.json +17 -0
- package/bin/cds_update_identifiers.js +8 -7
- package/bin/cdsc.js +180 -132
- package/bin/cdshi.js +18 -11
- package/bin/cdsse.js +38 -32
- package/bin/cdsv2m.js +8 -7
- package/doc/CHANGELOG_BETA.md +36 -1
- package/lib/api/main.js +81 -100
- package/lib/api/options.js +17 -11
- package/lib/api/validate.js +12 -8
- package/lib/backends.js +0 -81
- package/lib/base/keywords.js +32 -2
- package/lib/base/location.js +2 -2
- package/lib/base/message-registry.js +66 -4
- package/lib/base/messages.js +84 -27
- package/lib/base/model.js +2 -61
- package/lib/checks/arrayOfs.js +0 -1
- package/lib/checks/defaultValues.js +27 -2
- package/lib/checks/elements.js +1 -6
- package/lib/checks/enricher.js +8 -2
- package/lib/checks/foreignKeys.js +0 -6
- package/lib/checks/managedWithoutKeys.js +17 -0
- package/lib/checks/nonexpandableStructured.js +38 -0
- package/lib/checks/onConditions.js +9 -45
- package/lib/checks/queryNoDbArtifacts.js +27 -9
- package/lib/checks/selectItems.js +25 -2
- package/lib/checks/types.js +26 -2
- package/lib/checks/unknownMagic.js +38 -0
- package/lib/checks/utils.js +61 -0
- package/lib/checks/validator.js +66 -13
- package/lib/compiler/assert-consistency.js +24 -12
- package/lib/compiler/builtins.js +2 -0
- package/lib/compiler/checks.js +6 -4
- package/lib/compiler/definer.js +101 -39
- package/lib/compiler/index.js +88 -59
- package/lib/compiler/resolver.js +455 -209
- package/lib/compiler/shared.js +57 -33
- package/lib/edm/annotations/genericTranslation.js +183 -187
- package/lib/edm/csn2edm.js +128 -99
- package/lib/edm/edm.js +18 -21
- package/lib/edm/edmPreprocessor.js +361 -127
- package/lib/edm/edmUtils.js +103 -33
- package/lib/gen/Dictionary.json +74 -28
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +18 -4
- package/lib/gen/language.tokens +124 -118
- package/lib/gen/languageLexer.interp +13 -1
- package/lib/gen/languageLexer.js +870 -839
- package/lib/gen/languageLexer.tokens +116 -111
- package/lib/gen/languageParser.js +5894 -5614
- package/lib/json/from-csn.js +152 -67
- package/lib/json/to-csn.js +334 -135
- package/lib/language/antlrParser.js +4 -3
- package/lib/language/errorStrategy.js +1 -0
- package/lib/language/genericAntlrParser.js +24 -14
- package/lib/language/language.g4 +188 -128
- package/lib/main.d.ts +435 -0
- package/lib/main.js +31 -7
- package/lib/model/api.js +78 -0
- package/lib/model/csnRefs.js +463 -187
- package/lib/model/csnUtils.js +280 -136
- package/lib/model/enrichCsn.js +75 -4
- package/lib/model/revealInternalProperties.js +2 -1
- package/lib/modelCompare/compare.js +70 -25
- package/lib/optionProcessor.js +13 -10
- package/lib/render/.eslintrc.json +4 -1
- package/lib/render/DuplicateChecker.js +8 -5
- package/lib/render/toCdl.js +123 -40
- package/lib/render/toHdbcds.js +156 -65
- package/lib/render/toSql.js +87 -11
- package/lib/render/utils/common.js +55 -9
- package/lib/render/utils/sql.js +3 -3
- package/lib/sql-identifier.js +6 -1
- package/lib/transform/{sql → db}/.eslintrc.json +0 -0
- package/lib/transform/{sql → db}/assertUnique.js +7 -8
- package/lib/transform/{sql → db}/constraints.js +35 -20
- package/lib/transform/db/draft.js +353 -0
- package/lib/transform/db/expansion.js +582 -0
- package/lib/transform/db/flattening.js +325 -0
- package/lib/transform/{sql → db}/groupByOrderBy.js +8 -16
- package/lib/transform/{sql → db}/helpers.js +0 -0
- package/lib/transform/{sql → db}/transformExists.js +256 -60
- package/lib/transform/forHanaNew.js +216 -765
- package/lib/transform/forOdataNew.js +60 -56
- package/lib/transform/localized.js +48 -26
- package/lib/transform/odata/attachPath.js +19 -4
- package/lib/transform/odata/expandStructKeysInAssociations.js +2 -2
- package/lib/transform/odata/generateForeignKeyElements.js +13 -12
- package/lib/transform/odata/referenceFlattener.js +60 -36
- package/lib/transform/odata/sortByAssociationDependency.js +4 -4
- package/lib/transform/odata/structuralPath.js +76 -0
- package/lib/transform/odata/structureFlattener.js +21 -22
- package/lib/transform/odata/toFinalBaseType.js +5 -5
- package/lib/transform/odata/typesExposure.js +27 -17
- package/lib/transform/odata/utils.js +2 -2
- package/lib/transform/transformUtilsNew.js +141 -77
- package/lib/transform/translateAssocsToJoins.js +17 -14
- package/lib/transform/universalCsnEnricher.js +67 -0
- package/lib/utils/file.js +0 -11
- package/lib/utils/moduleResolve.js +6 -8
- package/lib/utils/timetrace.js +6 -1
- package/package.json +2 -1
- package/lib/base/deepCopy.js +0 -66
- package/lib/json/walker.js +0 -26
- package/lib/utils/string.js +0 -17
package/lib/json/from-csn.js
CHANGED
|
@@ -87,11 +87,11 @@
|
|
|
87
87
|
* @returns {any} XSN property (e.g. string, object, ...)
|
|
88
88
|
*/
|
|
89
89
|
|
|
90
|
-
const { makeMessageFunction } = require('../base/messages');
|
|
91
90
|
const { dictAdd } = require('../base/dictionaries');
|
|
92
91
|
|
|
93
92
|
let inExtensions = null;
|
|
94
|
-
|
|
93
|
+
|
|
94
|
+
let vocabInDefinitions = null; // must be reset!
|
|
95
95
|
|
|
96
96
|
// CSN property names reserved for CAP
|
|
97
97
|
const ourpropsRegex = /^[_$]?[a-zA-Z]+[0-9]*$/;
|
|
@@ -145,6 +145,21 @@ const schemaClasses = {
|
|
|
145
145
|
type: natnumOrStar,
|
|
146
146
|
msgId: 'syntax-csn-expected-cardinality',
|
|
147
147
|
},
|
|
148
|
+
columns: {
|
|
149
|
+
arrayOf: selectItem,
|
|
150
|
+
msgId: 'syntax-csn-expected-column',
|
|
151
|
+
defaultKind: '$column',
|
|
152
|
+
validKinds: [], // pseudo kind '$column'
|
|
153
|
+
requires: [ 'ref', 'xpr', 'val', '#', 'func', 'list', 'SELECT', 'SET', 'expand' ],
|
|
154
|
+
schema: {
|
|
155
|
+
xpr: {
|
|
156
|
+
class: 'condition',
|
|
157
|
+
type: xprInValue,
|
|
158
|
+
inKind: [ '$column' ],
|
|
159
|
+
inValue: true,
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
},
|
|
148
163
|
};
|
|
149
164
|
|
|
150
165
|
// TODO: also have stricter tests for strings in in xpr/args, join, op, sort, nulls ?
|
|
@@ -223,35 +238,15 @@ const schema = compileSchema( {
|
|
|
223
238
|
validKinds: [],
|
|
224
239
|
},
|
|
225
240
|
columns: {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
defaultKind: '$column',
|
|
229
|
-
validKinds: [], // pseudo kind '$column'
|
|
230
|
-
requires: [ 'ref', 'xpr', 'val', '#', 'func', 'list', 'SELECT', 'SET' ], // requires one of...
|
|
231
|
-
inKind: [ 'extend' ], // only valid in extend and SELECT
|
|
232
|
-
schema: {
|
|
233
|
-
xpr: {
|
|
234
|
-
class: 'condition',
|
|
235
|
-
type: xprInValue,
|
|
236
|
-
inKind: [ '$column' ],
|
|
237
|
-
inValue: true,
|
|
238
|
-
},
|
|
239
|
-
},
|
|
241
|
+
class: 'columns',
|
|
242
|
+
inKind: [ 'extend' ], // only valid in extend and SELECT/projection
|
|
240
243
|
},
|
|
241
244
|
expand: {
|
|
242
|
-
|
|
243
|
-
msgId: 'syntax-csn-expected-column',
|
|
244
|
-
defaultKind: '$column',
|
|
245
|
-
validKinds: [], // pseudo kind '$column'
|
|
246
|
-
requires: [ 'ref' ], // requires one of...
|
|
245
|
+
class: 'columns',
|
|
247
246
|
inKind: [ '$column' ], // only valid in $column
|
|
248
247
|
},
|
|
249
248
|
inline: {
|
|
250
|
-
|
|
251
|
-
msgId: 'syntax-csn-expected-column',
|
|
252
|
-
defaultKind: '$column',
|
|
253
|
-
validKinds: [], // pseudo kind '$column'
|
|
254
|
-
requires: [ 'ref' ], // requires one of...
|
|
249
|
+
class: 'columns',
|
|
255
250
|
inKind: [ '$column' ], // only valid in $column
|
|
256
251
|
},
|
|
257
252
|
keys: {
|
|
@@ -277,7 +272,7 @@ const schema = compileSchema( {
|
|
|
277
272
|
},
|
|
278
273
|
annotate: {
|
|
279
274
|
type: kindAndName,
|
|
280
|
-
inKind:
|
|
275
|
+
inKind: [ 'annotate' ],
|
|
281
276
|
},
|
|
282
277
|
extend: {
|
|
283
278
|
type: kindAndName,
|
|
@@ -331,7 +326,7 @@ const schema = compileSchema( {
|
|
|
331
326
|
inKind: [ 'element', 'type', 'param', 'annotation' ],
|
|
332
327
|
},
|
|
333
328
|
scale: {
|
|
334
|
-
type:
|
|
329
|
+
type: scalenum,
|
|
335
330
|
inKind: [ 'element', 'type', 'param', 'annotation' ],
|
|
336
331
|
},
|
|
337
332
|
srid: {
|
|
@@ -461,9 +456,19 @@ const schema = compileSchema( {
|
|
|
461
456
|
requires: 'from',
|
|
462
457
|
optional: [
|
|
463
458
|
'from', 'mixin', 'all', 'distinct', 'columns', 'excluding',
|
|
464
|
-
'where', 'groupBy', 'having', 'orderBy', 'limit',
|
|
459
|
+
'where', 'groupBy', 'having', 'orderBy', 'limit', 'elements',
|
|
465
460
|
],
|
|
466
461
|
inKind: [ '$column' ],
|
|
462
|
+
schema: {
|
|
463
|
+
elements: {
|
|
464
|
+
dictionaryOf: definition,
|
|
465
|
+
type: ( ...a ) => {
|
|
466
|
+
dictionaryOf( definition )( ...a );
|
|
467
|
+
}, // ignore, but test
|
|
468
|
+
defaultKind: 'element',
|
|
469
|
+
validKinds: [ 'element' ],
|
|
470
|
+
},
|
|
471
|
+
},
|
|
467
472
|
},
|
|
468
473
|
SET: {
|
|
469
474
|
type: queryTerm,
|
|
@@ -513,6 +518,7 @@ const schema = compileSchema( {
|
|
|
513
518
|
all: { type: asQuantifier },
|
|
514
519
|
// further query properties: -----------------------------------------------
|
|
515
520
|
excluding: {
|
|
521
|
+
inKind: [ '$column' ],
|
|
516
522
|
arrayOf: string,
|
|
517
523
|
type: excluding,
|
|
518
524
|
},
|
|
@@ -556,7 +562,7 @@ const schema = compileSchema( {
|
|
|
556
562
|
},
|
|
557
563
|
// miscellaneous properties in definitions: --------------------------------
|
|
558
564
|
doc: {
|
|
559
|
-
type:
|
|
565
|
+
type: stringValOrNull,
|
|
560
566
|
inKind: () => true, // allowed in all definitions (including columns and extensions)
|
|
561
567
|
},
|
|
562
568
|
'@': { // for all properties starting with '@'
|
|
@@ -603,10 +609,10 @@ const schema = compileSchema( {
|
|
|
603
609
|
inKind: [ 'entity', 'type', 'aspect', 'event', 'extend' ],
|
|
604
610
|
},
|
|
605
611
|
returns: {
|
|
606
|
-
type:
|
|
612
|
+
type: returnsDefinition,
|
|
607
613
|
defaultKind: 'param',
|
|
608
614
|
validKinds: [ 'param' ],
|
|
609
|
-
inKind: [ 'action', 'function' ],
|
|
615
|
+
inKind: [ 'action', 'function', 'annotate' ],
|
|
610
616
|
},
|
|
611
617
|
technicalConfig: { // treat it like external_property
|
|
612
618
|
type: extra,
|
|
@@ -654,7 +660,8 @@ const schema = compileSchema( {
|
|
|
654
660
|
indexNo: { // CSN v0.1.0, but ignored without message
|
|
655
661
|
ignore: true, type: ignore,
|
|
656
662
|
},
|
|
657
|
-
|
|
663
|
+
// TODO: should we keep $parens ?
|
|
664
|
+
$: { type: ignore, ignore: true }, // including $origin
|
|
658
665
|
_: { type: ignore, ignore: true },
|
|
659
666
|
} );
|
|
660
667
|
|
|
@@ -682,7 +689,7 @@ const validLiteralsExtra = Object.assign( Object.create(null), {
|
|
|
682
689
|
|
|
683
690
|
/** @type {(id, location, textOrArguments, texts?) => void} */
|
|
684
691
|
// eslint-disable-next-line no-unused-vars
|
|
685
|
-
let message = (
|
|
692
|
+
let message = (_id, loc, textOrArguments, texts) => undefined;
|
|
686
693
|
/** @type {(id, location, textOrArguments, texts?) => void} */
|
|
687
694
|
// eslint-disable-next-line no-unused-vars
|
|
688
695
|
let error = (id, loc, textOrArguments, texts) => undefined;
|
|
@@ -698,6 +705,7 @@ let csnFilename = '';
|
|
|
698
705
|
let virtualLine = 1;
|
|
699
706
|
/** @type {CSN.Location[]} */
|
|
700
707
|
let dollarLocations = [];
|
|
708
|
+
let arrayLvlCnt = 0;
|
|
701
709
|
|
|
702
710
|
/**
|
|
703
711
|
* @param {Object.<string, SchemaSpec>} specs
|
|
@@ -731,14 +739,15 @@ function compileSchema( specs, proto = null) {
|
|
|
731
739
|
throw new Error( `Missing type specification for property "${ p }"` );
|
|
732
740
|
}
|
|
733
741
|
}
|
|
734
|
-
|
|
735
|
-
return r;
|
|
742
|
+
// Set property 'xorGroup' in main and sub schema:
|
|
736
743
|
for (const group in xorGroups) {
|
|
737
744
|
for (const prop of xorGroups[group]) {
|
|
738
745
|
if (r[prop].xorGroup === undefined)
|
|
739
746
|
r[prop].xorGroup = group;
|
|
740
747
|
}
|
|
741
748
|
}
|
|
749
|
+
if (proto)
|
|
750
|
+
return r;
|
|
742
751
|
for (const prop of exprProperties) {
|
|
743
752
|
if (r[prop].inValue === undefined)
|
|
744
753
|
r[prop].inValue = true;
|
|
@@ -936,7 +945,10 @@ function definition( def, spec, xsn, csn, name ) {
|
|
|
936
945
|
return s.inKind && s.inKind( kind, spec );
|
|
937
946
|
return s.inKind.includes( kind ) &&
|
|
938
947
|
// for an 'annotate', both 'annotate' and the "host" kind must be expected
|
|
939
|
-
(!inExtensions || s.inKind.includes( inExtensions )
|
|
948
|
+
(!inExtensions || s.inKind.includes( inExtensions ) ||
|
|
949
|
+
// extending elements in returns can be without 'returns' in CSN
|
|
950
|
+
// TODO: with warning/info?
|
|
951
|
+
inExtensions === 'action' && p === 'elements');
|
|
940
952
|
}
|
|
941
953
|
}
|
|
942
954
|
|
|
@@ -984,12 +996,34 @@ function keys( array, spec, xsn ) {
|
|
|
984
996
|
}
|
|
985
997
|
|
|
986
998
|
function selectItem( def, spec, xsn, csn ) {
|
|
987
|
-
if (def === '*')
|
|
999
|
+
if (def === '*') // compile() will complain about repeated '*'s
|
|
988
1000
|
return { val: '*', location: location() };
|
|
989
1001
|
|
|
990
1002
|
return definition( def, spec, xsn, csn, null ); // definer sets name
|
|
991
1003
|
}
|
|
992
1004
|
|
|
1005
|
+
function returnsDefinition( def, spec, xsn, csn, name ) {
|
|
1006
|
+
// TODO: be stricter in what is allowed inside returns
|
|
1007
|
+
if (!inExtensions)
|
|
1008
|
+
return definition( def, spec, xsn, csn, name );
|
|
1009
|
+
// for the moment, flatten elements in returns in an annotate
|
|
1010
|
+
// TODO: bigger Core Compiler changes would have to be done otherwise
|
|
1011
|
+
xsn.elements = definition( def, spec, xsn, csn, name ).elements;
|
|
1012
|
+
xsn.$syntax = 'returns';
|
|
1013
|
+
return undefined;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
// For v1 CSNs with annotation definitions
|
|
1017
|
+
function attachVocabInDefinitions( csn ) {
|
|
1018
|
+
if (!csn.vocabularies) {
|
|
1019
|
+
csn.vocabularies = vocabInDefinitions;
|
|
1020
|
+
}
|
|
1021
|
+
else {
|
|
1022
|
+
for (const name in vocabInDefinitions)
|
|
1023
|
+
dictAdd( csn.vocabularies, name, vocabInDefinitions[name] );
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
|
|
993
1027
|
// Kind, names and references (std signature) --------------------------------
|
|
994
1028
|
|
|
995
1029
|
function kindAndName( id, spec, xsn ) {
|
|
@@ -1098,6 +1132,19 @@ function stringVal( val, spec ) {
|
|
|
1098
1132
|
return ignore( val );
|
|
1099
1133
|
}
|
|
1100
1134
|
|
|
1135
|
+
function stringValOrNull( val, spec ) {
|
|
1136
|
+
if (val === null)
|
|
1137
|
+
return { val, location: location() };
|
|
1138
|
+
|
|
1139
|
+
return stringVal(val, spec);
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
function scalenum( val, spec ) {
|
|
1143
|
+
if ([ 'floating', 'variable' ].includes(val))
|
|
1144
|
+
return { val, literal: 'string', location: location() };
|
|
1145
|
+
return natnum(val, spec );
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1101
1148
|
function natnum( val, spec ) {
|
|
1102
1149
|
if (typeof val === 'number' && val >= 0)
|
|
1103
1150
|
// XSN TODO: do not require literal
|
|
@@ -1128,11 +1175,23 @@ function annoValue( val, spec ) {
|
|
|
1128
1175
|
if (lit !== 'object')
|
|
1129
1176
|
return { val, literal: lit, location: location() };
|
|
1130
1177
|
if (Array.isArray( val )) {
|
|
1131
|
-
|
|
1178
|
+
const ec = val.reduce((c, v) => ((v && v['...'] && Object.keys(v).length === 1) ? ++c : c), 0);
|
|
1179
|
+
if (arrayLvlCnt === 0 && ec > 1) {
|
|
1180
|
+
error( 'syntax-csn-duplicate-ellipsis', location(true), { code: '...' },
|
|
1181
|
+
'Expected no more than one $(CODE)' );
|
|
1182
|
+
}
|
|
1183
|
+
if (arrayLvlCnt > 0 && ec > 0) {
|
|
1184
|
+
error( 'syntax-csn-unexpected-ellipsis', location(true), { code: '...' },
|
|
1185
|
+
'Unexpected $(CODE) in nested array' );
|
|
1186
|
+
}
|
|
1187
|
+
arrayLvlCnt++;
|
|
1188
|
+
const retval = {
|
|
1132
1189
|
location: location(),
|
|
1133
1190
|
val: arrayOf( annoValue )( val, spec ),
|
|
1134
1191
|
literal: 'array',
|
|
1135
1192
|
};
|
|
1193
|
+
arrayLvlCnt--;
|
|
1194
|
+
return retval;
|
|
1136
1195
|
}
|
|
1137
1196
|
if (typeof val['#'] === 'string') {
|
|
1138
1197
|
if (Object.keys( val ).length === 1) {
|
|
@@ -1150,6 +1209,13 @@ function annoValue( val, spec ) {
|
|
|
1150
1209
|
return refSplit( val['='], '=' );
|
|
1151
1210
|
}
|
|
1152
1211
|
}
|
|
1212
|
+
else if (val['...'] && Object.keys(val).length === 1) {
|
|
1213
|
+
return {
|
|
1214
|
+
val: '...',
|
|
1215
|
+
literal: 'token',
|
|
1216
|
+
location: location(),
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1153
1219
|
const struct = Object.create(null);
|
|
1154
1220
|
++virtualLine;
|
|
1155
1221
|
for (const name of Object.keys( val )) {
|
|
@@ -1203,9 +1269,14 @@ function func( val, spec, xsn ) {
|
|
|
1203
1269
|
return { path: [ { id: val, location: location() } ], location: location() };
|
|
1204
1270
|
}
|
|
1205
1271
|
|
|
1206
|
-
function xpr( exprs, spec, xsn ) {
|
|
1207
|
-
|
|
1208
|
-
|
|
1272
|
+
function xpr( exprs, spec, xsn, csn ) {
|
|
1273
|
+
if (csn.func) {
|
|
1274
|
+
xsn.suffix = exprArgs( exprs, spec );
|
|
1275
|
+
}
|
|
1276
|
+
else {
|
|
1277
|
+
xsn.op = { val: 'xpr', location: location() };
|
|
1278
|
+
xsn.args = exprArgs( exprs, spec, xsn );
|
|
1279
|
+
}
|
|
1209
1280
|
}
|
|
1210
1281
|
|
|
1211
1282
|
function list( exprs, spec, xsn ) {
|
|
@@ -1213,15 +1284,15 @@ function list( exprs, spec, xsn ) {
|
|
|
1213
1284
|
xsn.args = arrayOf( exprOrString )( exprs, spec, xsn );
|
|
1214
1285
|
}
|
|
1215
1286
|
|
|
1216
|
-
function xprInValue( exprs, spec, xsn ) {
|
|
1287
|
+
function xprInValue( exprs, spec, xsn, csn ) {
|
|
1217
1288
|
// if the top-level xpr is just for a cast:
|
|
1218
1289
|
if (exprs.length === 1 && exprs[0].cast) {
|
|
1219
1290
|
const x = {};
|
|
1220
|
-
xpr( exprs, spec, x );
|
|
1291
|
+
xpr( exprs, spec, x, csn );
|
|
1221
1292
|
Object.assign( xsn, x.args[0] );
|
|
1222
1293
|
}
|
|
1223
1294
|
else {
|
|
1224
|
-
xpr( exprs, spec, xsn );
|
|
1295
|
+
xpr( exprs, spec, xsn, csn );
|
|
1225
1296
|
}
|
|
1226
1297
|
}
|
|
1227
1298
|
|
|
@@ -1270,9 +1341,9 @@ function exprOrString( e, spec ) {
|
|
|
1270
1341
|
}
|
|
1271
1342
|
|
|
1272
1343
|
// mark path argument of 'exits' predicate with $expected:'exists'
|
|
1273
|
-
function
|
|
1274
|
-
const rxsn = arrayOf( exprOrString )(cond, spec, xsn, csn);
|
|
1275
|
-
if (Array.isArray(rxsn) && rxsn.some(x => x === 'exists')) {
|
|
1344
|
+
function exprArgs( cond, spec, xsn, csn ) {
|
|
1345
|
+
const rxsn = arrayOf( exprOrString )( cond, spec, xsn, csn );
|
|
1346
|
+
if (Array.isArray( rxsn ) && rxsn.some( x => x === 'exists' )) {
|
|
1276
1347
|
for (let i = 0; i < rxsn.length - 1; i++) {
|
|
1277
1348
|
if (rxsn[i] === 'exists' && rxsn[i + 1].path)
|
|
1278
1349
|
rxsn[++i].$expected = 'exists';
|
|
@@ -1285,7 +1356,7 @@ function condition( cond, spec ) {
|
|
|
1285
1356
|
const loc = location();
|
|
1286
1357
|
const x = {
|
|
1287
1358
|
op: { val: 'xpr', location: loc },
|
|
1288
|
-
args:
|
|
1359
|
+
args: exprArgs( cond, spec ),
|
|
1289
1360
|
location: loc,
|
|
1290
1361
|
};
|
|
1291
1362
|
return x;
|
|
@@ -1455,7 +1526,7 @@ function calculateKind( def, spec ) {
|
|
|
1455
1526
|
return 'annotate';
|
|
1456
1527
|
}
|
|
1457
1528
|
if (spec.prop === 'extensions') {
|
|
1458
|
-
inExtensions = (def.extend) ? '' : '
|
|
1529
|
+
inExtensions = (def.extend) ? '' : 'annotate';
|
|
1459
1530
|
return (def.extend) ? 'extend' : 'annotate';
|
|
1460
1531
|
}
|
|
1461
1532
|
const kind = (def.kind === 'view') ? 'entity' : def.kind; // 'view' is CSN v0.1.0
|
|
@@ -1511,6 +1582,9 @@ function checkAndSetXorGroup( group, prop, xor ) {
|
|
|
1511
1582
|
xor[group] = prop;
|
|
1512
1583
|
return true;
|
|
1513
1584
|
}
|
|
1585
|
+
if (prop === 'func' && xor[group] === 'xpr' ||
|
|
1586
|
+
prop === 'xpr' && xor[group] === 'func')
|
|
1587
|
+
return true; // hack for window function: both func and xpr is allowed
|
|
1514
1588
|
error( 'syntax-csn-excluded-property', location(true),
|
|
1515
1589
|
{ prop, otherprop: xor[group] },
|
|
1516
1590
|
'CSN property $(PROP) can only be used alternatively to $(OTHERPROP)');
|
|
@@ -1612,6 +1686,15 @@ function popLocation( obj ) {
|
|
|
1612
1686
|
dollarLocations.pop();
|
|
1613
1687
|
}
|
|
1614
1688
|
|
|
1689
|
+
function resetHeapModuleVars() {
|
|
1690
|
+
vocabInDefinitions = null;
|
|
1691
|
+
dollarLocations = [];
|
|
1692
|
+
message = () => undefined;
|
|
1693
|
+
error = () => undefined;
|
|
1694
|
+
warning = () => undefined;
|
|
1695
|
+
info = () => undefined;
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1615
1698
|
// API -----------------------------------------------------------------------
|
|
1616
1699
|
|
|
1617
1700
|
/**
|
|
@@ -1622,7 +1705,7 @@ function popLocation( obj ) {
|
|
|
1622
1705
|
* @param {CSN.Options} options
|
|
1623
1706
|
* @returns {object} Augmented CSN (a.k.a XSN)
|
|
1624
1707
|
*/
|
|
1625
|
-
function
|
|
1708
|
+
function toXsn( csn, filename, options, messageFunctions ) {
|
|
1626
1709
|
csnVersionZero = csn.version && csn.version.csn === '0.1.0';
|
|
1627
1710
|
csnFilename = filename;
|
|
1628
1711
|
virtualLine = 1;
|
|
@@ -1631,11 +1714,8 @@ function augment( csn, filename, options ) {
|
|
|
1631
1714
|
vocabInDefinitions = null;
|
|
1632
1715
|
const xsn = { $frontend: 'json' };
|
|
1633
1716
|
|
|
1634
|
-
|
|
1635
|
-
message =
|
|
1636
|
-
error = msgFcts.error;
|
|
1637
|
-
warning = msgFcts.warning;
|
|
1638
|
-
info = msgFcts.info;
|
|
1717
|
+
// eslint-disable-next-line object-curly-newline
|
|
1718
|
+
({ message, error, warning, info } = messageFunctions);
|
|
1639
1719
|
|
|
1640
1720
|
if (csnVersionZero) {
|
|
1641
1721
|
warning( 'syntax-csn-zero-version', location(true),
|
|
@@ -1644,25 +1724,31 @@ function augment( csn, filename, options ) {
|
|
|
1644
1724
|
const r = object( csn, topLevelSpec );
|
|
1645
1725
|
if (vocabInDefinitions)
|
|
1646
1726
|
attachVocabInDefinitions( r );
|
|
1727
|
+
if (csn.$sources && Array.isArray( csn.$sources ) &&
|
|
1728
|
+
csn.$sources.every( fname => typeof fname === 'string' ))
|
|
1729
|
+
// non-enumerable or enumerable, ignore with wrong value
|
|
1730
|
+
r.$sources = csn.$sources;
|
|
1731
|
+
resetHeapModuleVars();
|
|
1647
1732
|
return Object.assign( xsn, r );
|
|
1648
1733
|
}
|
|
1649
1734
|
|
|
1650
|
-
|
|
1651
|
-
function
|
|
1652
|
-
|
|
1653
|
-
csn
|
|
1735
|
+
|
|
1736
|
+
function augment( csn, filename = 'csn.json', options = {}, messageFunctions ) {
|
|
1737
|
+
try {
|
|
1738
|
+
return toXsn( csn, filename, options, messageFunctions );
|
|
1654
1739
|
}
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1740
|
+
catch ( e ) {
|
|
1741
|
+
resetHeapModuleVars();
|
|
1742
|
+
throw e;
|
|
1658
1743
|
}
|
|
1659
1744
|
}
|
|
1660
1745
|
|
|
1661
|
-
function parse( source, filename = 'csn.json', options = {} ) {
|
|
1746
|
+
function parse( source, filename = 'csn.json', options = {}, messageFunctions ) {
|
|
1662
1747
|
try {
|
|
1663
|
-
return augment( JSON.parse(source), filename, options );
|
|
1748
|
+
return augment( JSON.parse(source), filename, options, messageFunctions );
|
|
1664
1749
|
}
|
|
1665
1750
|
catch ( e ) {
|
|
1751
|
+
resetHeapModuleVars();
|
|
1666
1752
|
if (!(e instanceof SyntaxError))
|
|
1667
1753
|
throw e;
|
|
1668
1754
|
const xsn = {};
|
|
@@ -1688,8 +1774,7 @@ function parse( source, filename = 'csn.json', options = {} ) {
|
|
|
1688
1774
|
line,
|
|
1689
1775
|
col: column,
|
|
1690
1776
|
};
|
|
1691
|
-
|
|
1692
|
-
msgs.error( 'syntax-csn-illegal-json', loc, { msg }, 'Illegal JSON: $(MSG)' );
|
|
1777
|
+
messageFunctions.error( 'syntax-csn-illegal-json', loc, { msg }, 'Illegal JSON: $(MSG)' );
|
|
1693
1778
|
return xsn;
|
|
1694
1779
|
}
|
|
1695
1780
|
}
|