@sap/cds-compiler 2.5.0 → 2.10.4
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 +191 -9
- package/bin/cdsc.js +2 -2
- package/doc/CHANGELOG_BETA.md +33 -3
- package/lib/api/main.js +29 -101
- package/lib/api/options.js +15 -11
- package/lib/api/validate.js +12 -8
- package/lib/backends.js +0 -81
- package/lib/base/keywords.js +32 -2
- package/lib/base/message-registry.js +63 -9
- package/lib/base/messages.js +63 -21
- package/lib/base/model.js +2 -3
- package/lib/checks/defaultValues.js +27 -2
- package/lib/checks/elements.js +1 -6
- 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 +25 -7
- 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 +60 -7
- package/lib/compiler/assert-consistency.js +16 -7
- package/lib/compiler/builtins.js +2 -0
- package/lib/compiler/checks.js +6 -4
- package/lib/compiler/definer.js +99 -42
- package/lib/compiler/index.js +73 -27
- package/lib/compiler/resolver.js +288 -157
- package/lib/compiler/shared.js +31 -11
- package/lib/edm/annotations/genericTranslation.js +182 -186
- package/lib/edm/csn2edm.js +103 -108
- package/lib/edm/edm.js +18 -21
- package/lib/edm/edmPreprocessor.js +361 -114
- package/lib/edm/edmUtils.js +103 -33
- package/lib/gen/Dictionary.json +22 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +12 -1
- package/lib/gen/language.tokens +57 -53
- package/lib/gen/languageLexer.interp +10 -1
- package/lib/gen/languageLexer.js +770 -744
- package/lib/gen/languageLexer.tokens +49 -46
- package/lib/gen/languageParser.js +4713 -4279
- package/lib/json/from-csn.js +103 -45
- package/lib/json/to-csn.js +296 -117
- package/lib/language/antlrParser.js +4 -3
- package/lib/language/errorStrategy.js +1 -0
- package/lib/language/genericAntlrParser.js +21 -12
- package/lib/language/language.g4 +99 -31
- package/lib/main.d.ts +81 -3
- package/lib/main.js +30 -7
- package/lib/model/api.js +78 -0
- package/lib/model/csnRefs.js +329 -142
- package/lib/model/csnUtils.js +235 -58
- package/lib/model/enrichCsn.js +18 -1
- package/lib/model/revealInternalProperties.js +2 -1
- package/lib/modelCompare/compare.js +37 -20
- package/lib/optionProcessor.js +9 -3
- package/lib/render/.eslintrc.json +4 -1
- package/lib/render/DuplicateChecker.js +8 -5
- package/lib/render/toCdl.js +112 -33
- package/lib/render/toHdbcds.js +134 -64
- package/lib/render/toSql.js +91 -38
- package/lib/render/utils/common.js +8 -13
- package/lib/render/utils/sql.js +3 -3
- package/lib/sql-identifier.js +6 -1
- package/lib/transform/db/assertUnique.js +5 -6
- package/lib/transform/db/constraints.js +29 -13
- package/lib/transform/db/draft.js +8 -6
- package/lib/transform/db/expansion.js +582 -0
- package/lib/transform/db/flattening.js +325 -0
- package/lib/transform/db/groupByOrderBy.js +2 -2
- package/lib/transform/db/transformExists.js +284 -63
- package/lib/transform/forHanaNew.js +98 -381
- package/lib/transform/forOdataNew.js +21 -22
- package/lib/transform/localized.js +37 -10
- package/lib/transform/odata/attachPath.js +19 -4
- package/lib/transform/odata/generateForeignKeyElements.js +11 -10
- package/lib/transform/odata/referenceFlattener.js +60 -39
- package/lib/transform/odata/sortByAssociationDependency.js +2 -2
- package/lib/transform/odata/structuralPath.js +72 -0
- package/lib/transform/odata/structureFlattener.js +19 -18
- package/lib/transform/odata/typesExposure.js +22 -12
- package/lib/transform/transformUtilsNew.js +134 -78
- 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/package.json +1 -1
- package/lib/json/walker.js +0 -26
- package/lib/transform/sqlite +0 -0
- 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,7 +145,7 @@ const schemaClasses = {
|
|
|
145
145
|
type: natnumOrStar,
|
|
146
146
|
msgId: 'syntax-csn-expected-cardinality',
|
|
147
147
|
},
|
|
148
|
-
|
|
148
|
+
columns: {
|
|
149
149
|
arrayOf: selectItem,
|
|
150
150
|
msgId: 'syntax-csn-expected-column',
|
|
151
151
|
defaultKind: '$column',
|
|
@@ -238,15 +238,15 @@ const schema = compileSchema( {
|
|
|
238
238
|
validKinds: [],
|
|
239
239
|
},
|
|
240
240
|
columns: {
|
|
241
|
-
class: '
|
|
241
|
+
class: 'columns',
|
|
242
242
|
inKind: [ 'extend' ], // only valid in extend and SELECT/projection
|
|
243
243
|
},
|
|
244
244
|
expand: {
|
|
245
|
-
class: '
|
|
245
|
+
class: 'columns',
|
|
246
246
|
inKind: [ '$column' ], // only valid in $column
|
|
247
247
|
},
|
|
248
248
|
inline: {
|
|
249
|
-
class: '
|
|
249
|
+
class: 'columns',
|
|
250
250
|
inKind: [ '$column' ], // only valid in $column
|
|
251
251
|
},
|
|
252
252
|
keys: {
|
|
@@ -272,7 +272,7 @@ const schema = compileSchema( {
|
|
|
272
272
|
},
|
|
273
273
|
annotate: {
|
|
274
274
|
type: kindAndName,
|
|
275
|
-
inKind:
|
|
275
|
+
inKind: [ 'annotate' ],
|
|
276
276
|
},
|
|
277
277
|
extend: {
|
|
278
278
|
type: kindAndName,
|
|
@@ -326,7 +326,7 @@ const schema = compileSchema( {
|
|
|
326
326
|
inKind: [ 'element', 'type', 'param', 'annotation' ],
|
|
327
327
|
},
|
|
328
328
|
scale: {
|
|
329
|
-
type:
|
|
329
|
+
type: scalenum,
|
|
330
330
|
inKind: [ 'element', 'type', 'param', 'annotation' ],
|
|
331
331
|
},
|
|
332
332
|
srid: {
|
|
@@ -456,9 +456,19 @@ const schema = compileSchema( {
|
|
|
456
456
|
requires: 'from',
|
|
457
457
|
optional: [
|
|
458
458
|
'from', 'mixin', 'all', 'distinct', 'columns', 'excluding',
|
|
459
|
-
'where', 'groupBy', 'having', 'orderBy', 'limit',
|
|
459
|
+
'where', 'groupBy', 'having', 'orderBy', 'limit', 'elements',
|
|
460
460
|
],
|
|
461
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
|
+
},
|
|
462
472
|
},
|
|
463
473
|
SET: {
|
|
464
474
|
type: queryTerm,
|
|
@@ -599,10 +609,10 @@ const schema = compileSchema( {
|
|
|
599
609
|
inKind: [ 'entity', 'type', 'aspect', 'event', 'extend' ],
|
|
600
610
|
},
|
|
601
611
|
returns: {
|
|
602
|
-
type:
|
|
612
|
+
type: returnsDefinition,
|
|
603
613
|
defaultKind: 'param',
|
|
604
614
|
validKinds: [ 'param' ],
|
|
605
|
-
inKind: [ 'action', 'function' ],
|
|
615
|
+
inKind: [ 'action', 'function', 'annotate' ],
|
|
606
616
|
},
|
|
607
617
|
technicalConfig: { // treat it like external_property
|
|
608
618
|
type: extra,
|
|
@@ -650,7 +660,8 @@ const schema = compileSchema( {
|
|
|
650
660
|
indexNo: { // CSN v0.1.0, but ignored without message
|
|
651
661
|
ignore: true, type: ignore,
|
|
652
662
|
},
|
|
653
|
-
|
|
663
|
+
// TODO: should we keep $parens ?
|
|
664
|
+
$: { type: ignore, ignore: true }, // including $origin
|
|
654
665
|
_: { type: ignore, ignore: true },
|
|
655
666
|
} );
|
|
656
667
|
|
|
@@ -678,7 +689,7 @@ const validLiteralsExtra = Object.assign( Object.create(null), {
|
|
|
678
689
|
|
|
679
690
|
/** @type {(id, location, textOrArguments, texts?) => void} */
|
|
680
691
|
// eslint-disable-next-line no-unused-vars
|
|
681
|
-
let message = (
|
|
692
|
+
let message = (_id, loc, textOrArguments, texts) => undefined;
|
|
682
693
|
/** @type {(id, location, textOrArguments, texts?) => void} */
|
|
683
694
|
// eslint-disable-next-line no-unused-vars
|
|
684
695
|
let error = (id, loc, textOrArguments, texts) => undefined;
|
|
@@ -728,14 +739,15 @@ function compileSchema( specs, proto = null) {
|
|
|
728
739
|
throw new Error( `Missing type specification for property "${ p }"` );
|
|
729
740
|
}
|
|
730
741
|
}
|
|
731
|
-
|
|
732
|
-
return r;
|
|
742
|
+
// Set property 'xorGroup' in main and sub schema:
|
|
733
743
|
for (const group in xorGroups) {
|
|
734
744
|
for (const prop of xorGroups[group]) {
|
|
735
745
|
if (r[prop].xorGroup === undefined)
|
|
736
746
|
r[prop].xorGroup = group;
|
|
737
747
|
}
|
|
738
748
|
}
|
|
749
|
+
if (proto)
|
|
750
|
+
return r;
|
|
739
751
|
for (const prop of exprProperties) {
|
|
740
752
|
if (r[prop].inValue === undefined)
|
|
741
753
|
r[prop].inValue = true;
|
|
@@ -933,7 +945,10 @@ function definition( def, spec, xsn, csn, name ) {
|
|
|
933
945
|
return s.inKind && s.inKind( kind, spec );
|
|
934
946
|
return s.inKind.includes( kind ) &&
|
|
935
947
|
// for an 'annotate', both 'annotate' and the "host" kind must be expected
|
|
936
|
-
(!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');
|
|
937
952
|
}
|
|
938
953
|
}
|
|
939
954
|
|
|
@@ -981,12 +996,34 @@ function keys( array, spec, xsn ) {
|
|
|
981
996
|
}
|
|
982
997
|
|
|
983
998
|
function selectItem( def, spec, xsn, csn ) {
|
|
984
|
-
if (def === '*')
|
|
999
|
+
if (def === '*') // compile() will complain about repeated '*'s
|
|
985
1000
|
return { val: '*', location: location() };
|
|
986
1001
|
|
|
987
1002
|
return definition( def, spec, xsn, csn, null ); // definer sets name
|
|
988
1003
|
}
|
|
989
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
|
+
|
|
990
1027
|
// Kind, names and references (std signature) --------------------------------
|
|
991
1028
|
|
|
992
1029
|
function kindAndName( id, spec, xsn ) {
|
|
@@ -1102,6 +1139,12 @@ function stringValOrNull( val, spec ) {
|
|
|
1102
1139
|
return stringVal(val, spec);
|
|
1103
1140
|
}
|
|
1104
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
|
+
|
|
1105
1148
|
function natnum( val, spec ) {
|
|
1106
1149
|
if (typeof val === 'number' && val >= 0)
|
|
1107
1150
|
// XSN TODO: do not require literal
|
|
@@ -1226,9 +1269,14 @@ function func( val, spec, xsn ) {
|
|
|
1226
1269
|
return { path: [ { id: val, location: location() } ], location: location() };
|
|
1227
1270
|
}
|
|
1228
1271
|
|
|
1229
|
-
function xpr( exprs, spec, xsn ) {
|
|
1230
|
-
|
|
1231
|
-
|
|
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
|
+
}
|
|
1232
1280
|
}
|
|
1233
1281
|
|
|
1234
1282
|
function list( exprs, spec, xsn ) {
|
|
@@ -1236,15 +1284,15 @@ function list( exprs, spec, xsn ) {
|
|
|
1236
1284
|
xsn.args = arrayOf( exprOrString )( exprs, spec, xsn );
|
|
1237
1285
|
}
|
|
1238
1286
|
|
|
1239
|
-
function xprInValue( exprs, spec, xsn ) {
|
|
1287
|
+
function xprInValue( exprs, spec, xsn, csn ) {
|
|
1240
1288
|
// if the top-level xpr is just for a cast:
|
|
1241
1289
|
if (exprs.length === 1 && exprs[0].cast) {
|
|
1242
1290
|
const x = {};
|
|
1243
|
-
xpr( exprs, spec, x );
|
|
1291
|
+
xpr( exprs, spec, x, csn );
|
|
1244
1292
|
Object.assign( xsn, x.args[0] );
|
|
1245
1293
|
}
|
|
1246
1294
|
else {
|
|
1247
|
-
xpr( exprs, spec, xsn );
|
|
1295
|
+
xpr( exprs, spec, xsn, csn );
|
|
1248
1296
|
}
|
|
1249
1297
|
}
|
|
1250
1298
|
|
|
@@ -1293,9 +1341,9 @@ function exprOrString( e, spec ) {
|
|
|
1293
1341
|
}
|
|
1294
1342
|
|
|
1295
1343
|
// mark path argument of 'exits' predicate with $expected:'exists'
|
|
1296
|
-
function
|
|
1297
|
-
const rxsn = arrayOf( exprOrString )(cond, spec, xsn, csn);
|
|
1298
|
-
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' )) {
|
|
1299
1347
|
for (let i = 0; i < rxsn.length - 1; i++) {
|
|
1300
1348
|
if (rxsn[i] === 'exists' && rxsn[i + 1].path)
|
|
1301
1349
|
rxsn[++i].$expected = 'exists';
|
|
@@ -1308,7 +1356,7 @@ function condition( cond, spec ) {
|
|
|
1308
1356
|
const loc = location();
|
|
1309
1357
|
const x = {
|
|
1310
1358
|
op: { val: 'xpr', location: loc },
|
|
1311
|
-
args:
|
|
1359
|
+
args: exprArgs( cond, spec ),
|
|
1312
1360
|
location: loc,
|
|
1313
1361
|
};
|
|
1314
1362
|
return x;
|
|
@@ -1478,7 +1526,7 @@ function calculateKind( def, spec ) {
|
|
|
1478
1526
|
return 'annotate';
|
|
1479
1527
|
}
|
|
1480
1528
|
if (spec.prop === 'extensions') {
|
|
1481
|
-
inExtensions = (def.extend) ? '' : '
|
|
1529
|
+
inExtensions = (def.extend) ? '' : 'annotate';
|
|
1482
1530
|
return (def.extend) ? 'extend' : 'annotate';
|
|
1483
1531
|
}
|
|
1484
1532
|
const kind = (def.kind === 'view') ? 'entity' : def.kind; // 'view' is CSN v0.1.0
|
|
@@ -1534,6 +1582,9 @@ function checkAndSetXorGroup( group, prop, xor ) {
|
|
|
1534
1582
|
xor[group] = prop;
|
|
1535
1583
|
return true;
|
|
1536
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
|
|
1537
1588
|
error( 'syntax-csn-excluded-property', location(true),
|
|
1538
1589
|
{ prop, otherprop: xor[group] },
|
|
1539
1590
|
'CSN property $(PROP) can only be used alternatively to $(OTHERPROP)');
|
|
@@ -1635,6 +1686,15 @@ function popLocation( obj ) {
|
|
|
1635
1686
|
dollarLocations.pop();
|
|
1636
1687
|
}
|
|
1637
1688
|
|
|
1689
|
+
function resetHeapModuleVars() {
|
|
1690
|
+
vocabInDefinitions = null;
|
|
1691
|
+
dollarLocations = [];
|
|
1692
|
+
message = () => undefined;
|
|
1693
|
+
error = () => undefined;
|
|
1694
|
+
warning = () => undefined;
|
|
1695
|
+
info = () => undefined;
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1638
1698
|
// API -----------------------------------------------------------------------
|
|
1639
1699
|
|
|
1640
1700
|
/**
|
|
@@ -1645,7 +1705,7 @@ function popLocation( obj ) {
|
|
|
1645
1705
|
* @param {CSN.Options} options
|
|
1646
1706
|
* @returns {object} Augmented CSN (a.k.a XSN)
|
|
1647
1707
|
*/
|
|
1648
|
-
function
|
|
1708
|
+
function toXsn( csn, filename, options, messageFunctions ) {
|
|
1649
1709
|
csnVersionZero = csn.version && csn.version.csn === '0.1.0';
|
|
1650
1710
|
csnFilename = filename;
|
|
1651
1711
|
virtualLine = 1;
|
|
@@ -1654,11 +1714,8 @@ function augment( csn, filename, options ) {
|
|
|
1654
1714
|
vocabInDefinitions = null;
|
|
1655
1715
|
const xsn = { $frontend: 'json' };
|
|
1656
1716
|
|
|
1657
|
-
|
|
1658
|
-
message =
|
|
1659
|
-
error = msgFcts.error;
|
|
1660
|
-
warning = msgFcts.warning;
|
|
1661
|
-
info = msgFcts.info;
|
|
1717
|
+
// eslint-disable-next-line object-curly-newline
|
|
1718
|
+
({ message, error, warning, info } = messageFunctions);
|
|
1662
1719
|
|
|
1663
1720
|
if (csnVersionZero) {
|
|
1664
1721
|
warning( 'syntax-csn-zero-version', location(true),
|
|
@@ -1671,25 +1728,27 @@ function augment( csn, filename, options ) {
|
|
|
1671
1728
|
csn.$sources.every( fname => typeof fname === 'string' ))
|
|
1672
1729
|
// non-enumerable or enumerable, ignore with wrong value
|
|
1673
1730
|
r.$sources = csn.$sources;
|
|
1731
|
+
resetHeapModuleVars();
|
|
1674
1732
|
return Object.assign( xsn, r );
|
|
1675
1733
|
}
|
|
1676
1734
|
|
|
1677
|
-
|
|
1678
|
-
function
|
|
1679
|
-
|
|
1680
|
-
csn
|
|
1735
|
+
|
|
1736
|
+
function augment( csn, filename = 'csn.json', options = {}, messageFunctions ) {
|
|
1737
|
+
try {
|
|
1738
|
+
return toXsn( csn, filename, options, messageFunctions );
|
|
1681
1739
|
}
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1740
|
+
catch ( e ) {
|
|
1741
|
+
resetHeapModuleVars();
|
|
1742
|
+
throw e;
|
|
1685
1743
|
}
|
|
1686
1744
|
}
|
|
1687
1745
|
|
|
1688
|
-
function parse( source, filename = 'csn.json', options = {} ) {
|
|
1746
|
+
function parse( source, filename = 'csn.json', options = {}, messageFunctions ) {
|
|
1689
1747
|
try {
|
|
1690
|
-
return augment( JSON.parse(source), filename, options );
|
|
1748
|
+
return augment( JSON.parse(source), filename, options, messageFunctions );
|
|
1691
1749
|
}
|
|
1692
1750
|
catch ( e ) {
|
|
1751
|
+
resetHeapModuleVars();
|
|
1693
1752
|
if (!(e instanceof SyntaxError))
|
|
1694
1753
|
throw e;
|
|
1695
1754
|
const xsn = {};
|
|
@@ -1715,8 +1774,7 @@ function parse( source, filename = 'csn.json', options = {} ) {
|
|
|
1715
1774
|
line,
|
|
1716
1775
|
col: column,
|
|
1717
1776
|
};
|
|
1718
|
-
|
|
1719
|
-
msgs.error( 'syntax-csn-illegal-json', loc, { msg }, 'Illegal JSON: $(MSG)' );
|
|
1777
|
+
messageFunctions.error( 'syntax-csn-illegal-json', loc, { msg }, 'Illegal JSON: $(MSG)' );
|
|
1720
1778
|
return xsn;
|
|
1721
1779
|
}
|
|
1722
1780
|
}
|