@sap/cds-compiler 3.1.2 → 3.4.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 +101 -3
- package/bin/cdsc.js +4 -2
- package/doc/CHANGELOG_BETA.md +35 -0
- package/lib/api/main.js +153 -29
- package/lib/api/validate.js +8 -3
- package/lib/base/dictionaries.js +6 -6
- package/lib/base/error.js +2 -2
- package/lib/base/keywords.js +106 -24
- package/lib/base/message-registry.js +177 -79
- package/lib/base/messages.js +78 -57
- package/lib/base/model.js +2 -1
- package/lib/checks/actionsFunctions.js +1 -1
- package/lib/checks/annotationsOData.js +2 -2
- package/lib/checks/arrayOfs.js +15 -7
- package/lib/checks/cdsPersistence.js +1 -1
- package/lib/checks/checkForTypes.js +53 -0
- package/lib/checks/defaultValues.js +4 -2
- package/lib/checks/elements.js +81 -6
- package/lib/checks/foreignKeys.js +12 -13
- package/lib/checks/invalidTarget.js +10 -11
- package/lib/checks/managedInType.js +21 -15
- package/lib/checks/nullableKeys.js +1 -1
- package/lib/checks/onConditions.js +9 -9
- package/lib/checks/parameters.js +23 -0
- package/lib/checks/queryNoDbArtifacts.js +1 -1
- package/lib/checks/selectItems.js +1 -1
- package/lib/checks/sql-snippets.js +12 -10
- package/lib/checks/types.js +2 -2
- package/lib/checks/utils.js +17 -7
- package/lib/checks/validator.js +36 -14
- package/lib/compiler/assert-consistency.js +21 -13
- package/lib/compiler/builtins.js +8 -0
- package/lib/compiler/checks.js +57 -40
- package/lib/compiler/define.js +139 -69
- package/lib/compiler/extend.js +319 -50
- package/lib/compiler/finalize-parse-cdl.js +14 -9
- package/lib/compiler/kick-start.js +2 -35
- package/lib/compiler/populate.js +111 -68
- package/lib/compiler/propagator.js +5 -3
- package/lib/compiler/resolve.js +71 -108
- package/lib/compiler/shared.js +82 -54
- package/lib/compiler/tweak-assocs.js +26 -14
- package/lib/compiler/utils.js +13 -2
- package/lib/edm/annotations/genericTranslation.js +10 -7
- package/lib/edm/csn2edm.js +11 -11
- package/lib/edm/edm.js +17 -9
- package/lib/edm/edmPreprocessor.js +53 -30
- package/lib/edm/edmUtils.js +7 -2
- package/lib/gen/Dictionary.json +14 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +3 -2
- package/lib/gen/languageParser.js +4312 -4186
- package/lib/inspect/inspectModelStatistics.js +1 -1
- package/lib/inspect/inspectPropagation.js +23 -9
- package/lib/json/csnVersion.js +13 -13
- package/lib/json/from-csn.js +161 -172
- package/lib/json/to-csn.js +70 -10
- package/lib/language/.eslintrc.json +4 -0
- package/lib/language/antlrParser.js +8 -11
- package/lib/language/docCommentParser.js +1 -2
- package/lib/language/errorStrategy.js +54 -27
- package/lib/language/genericAntlrParser.js +140 -93
- package/lib/language/language.g4 +57 -33
- package/lib/language/multiLineStringParser.js +75 -63
- package/lib/main.d.ts +3 -6
- package/lib/main.js +1 -0
- package/lib/model/.eslintrc.json +13 -0
- package/lib/model/api.js +4 -2
- package/lib/model/csnRefs.js +78 -50
- package/lib/model/csnUtils.js +272 -222
- package/lib/model/enrichCsn.js +41 -31
- package/lib/model/revealInternalProperties.js +61 -57
- package/lib/model/sortViews.js +35 -31
- package/lib/modelCompare/compare.js +52 -18
- package/lib/modelCompare/filter.js +83 -0
- package/lib/optionProcessor.js +10 -1
- package/lib/render/manageConstraints.js +11 -7
- package/lib/render/toCdl.js +151 -106
- package/lib/render/toHdbcds.js +8 -6
- package/lib/render/toRename.js +4 -4
- package/lib/render/toSql.js +17 -7
- package/lib/render/utils/common.js +27 -9
- package/lib/render/utils/sql.js +5 -5
- package/lib/sql-identifier.js +7 -0
- package/lib/transform/db/applyTransformations.js +32 -3
- package/lib/transform/db/assertUnique.js +27 -38
- package/lib/transform/db/expansion.js +92 -41
- package/lib/transform/db/flattening.js +1 -1
- package/lib/transform/db/temporal.js +3 -1
- package/lib/transform/db/transformExists.js +8 -2
- package/lib/transform/db/views.js +42 -13
- package/lib/transform/draft/db.js +2 -2
- package/lib/transform/forOdataNew.js +10 -7
- package/lib/transform/{forHanaNew.js → forRelationalDB.js} +18 -12
- package/lib/transform/localized.js +29 -20
- package/lib/transform/odata/toFinalBaseType.js +8 -11
- package/lib/transform/odata/typesExposure.js +2 -1
- package/lib/transform/parseExpr.js +245 -0
- package/lib/transform/transformUtilsNew.js +122 -51
- package/lib/transform/translateAssocsToJoins.js +17 -16
- package/lib/utils/moduleResolve.js +5 -5
- package/lib/utils/objectUtils.js +3 -3
- package/lib/utils/term.js +5 -5
- package/package.json +2 -2
- package/share/messages/anno-duplicate-unrelated-layer.md +6 -6
- package/share/messages/check-proper-type-of.md +4 -4
- package/share/messages/check-proper-type.md +2 -2
- package/share/messages/duplicate-autoexposed.md +4 -4
- package/share/messages/extend-repeated-intralayer.md +4 -5
- package/share/messages/extend-unrelated-layer.md +4 -4
- package/share/messages/message-explanations.json +3 -1
- package/share/messages/redirected-to-ambiguous.md +7 -6
- package/share/messages/redirected-to-complex.md +63 -0
- package/share/messages/redirected-to-unrelated.md +6 -5
- package/share/messages/rewrite-not-supported.md +4 -4
- package/share/messages/{syntax-expected-integer.md → syntax-expecting-integer.md} +4 -4
- package/share/messages/wildcard-excluding-one.md +37 -0
package/lib/json/from-csn.js
CHANGED
|
@@ -68,10 +68,8 @@
|
|
|
68
68
|
* may not.
|
|
69
69
|
* @property {string} [xsnOp] Defines the operator to be used for XSN. Used for SET
|
|
70
70
|
* and SELECT. See queryTerm().
|
|
71
|
-
* @property {string
|
|
71
|
+
* @property {string} [vZeroFor] Marks the property as a CSN 0.1.0 property. It is
|
|
72
72
|
* replaced by this CSN 1.0 property (value of vZeroFor).
|
|
73
|
-
* "false" indicates that the property may be a v0.1 one
|
|
74
|
-
* which is handled specially, e.g. with "type:vZeroValue"
|
|
75
73
|
* @property {string} [vZeroIgnore] Marks the property as a CSN 0.1.0 property. The
|
|
76
74
|
* property is ignored and a warning may be issues about
|
|
77
75
|
* it.
|
|
@@ -117,13 +115,14 @@ const exprProperties = [
|
|
|
117
115
|
const xorGroups = {
|
|
118
116
|
// include CSN v0.1.0 properties here:
|
|
119
117
|
':type': [ 'target', 'elements', 'enum', 'items' ],
|
|
120
|
-
':expr': [
|
|
121
|
-
'ref', 'xpr', 'list', 'val', '#', 'func', 'SELECT', 'SET',
|
|
118
|
+
':expr': [ // see also xorException property in schema
|
|
119
|
+
'ref', 'xpr', 'list', 'val', '#', 'func', 'SELECT', 'SET', 'expand',
|
|
122
120
|
'=', 'path', 'value', 'op', // '='/'path' is CSN v0.1.0 here
|
|
123
121
|
],
|
|
124
122
|
':ext': [ 'annotate', 'extend' ], // TODO: better msg for test/negative/UnexpectedProperties.csn
|
|
125
123
|
':assoc': [ 'on', 'keys', 'foreignKeys', 'onCond' ], // 'foreignKeys'/'onCond' is CSN v0.1.0
|
|
126
|
-
|
|
124
|
+
// TODO - improve consequential errors: assume no name given with `join` or `inline`?
|
|
125
|
+
as: [ 'as', 'join', 'inline' ],
|
|
127
126
|
scope: [ 'param', 'global' ],
|
|
128
127
|
quantifier: [ 'some', 'any', 'distinct', 'all' ],
|
|
129
128
|
// quantifiers 'some' and 'any are 'xpr' token strings in CSN v1.0
|
|
@@ -137,7 +136,7 @@ const schemaClasses = {
|
|
|
137
136
|
condition: {
|
|
138
137
|
arrayOf: exprOrString,
|
|
139
138
|
type: condition,
|
|
140
|
-
msgId: 'syntax-
|
|
139
|
+
msgId: 'syntax-expecting-term',
|
|
141
140
|
// TODO: also specify requires here, and adapt onlyWith()
|
|
142
141
|
optional: exprProperties,
|
|
143
142
|
},
|
|
@@ -147,19 +146,20 @@ const schemaClasses = {
|
|
|
147
146
|
},
|
|
148
147
|
natnumOrStar: {
|
|
149
148
|
type: natnumOrStar,
|
|
150
|
-
msgId: 'syntax-
|
|
149
|
+
msgId: 'syntax-expecting-cardinality',
|
|
151
150
|
},
|
|
152
151
|
columns: {
|
|
153
152
|
arrayOf: selectItem,
|
|
154
|
-
msgId: 'syntax-
|
|
153
|
+
msgId: 'syntax-expecting-column',
|
|
155
154
|
defaultKind: '$column',
|
|
156
155
|
validKinds: [], // pseudo kind '$column'
|
|
157
156
|
// A column with only as+cast.type is a new association
|
|
158
|
-
requires: [ 'ref', '
|
|
157
|
+
requires: [ 'ref', 'cast', 'xpr', 'val', '#', 'func', 'list', 'SELECT', 'SET', 'expand' ],
|
|
159
158
|
schema: {
|
|
160
159
|
xpr: {
|
|
161
160
|
class: 'condition',
|
|
162
161
|
type: xprInValue,
|
|
162
|
+
xorException: 'func', // see xorGroup :expr
|
|
163
163
|
inKind: [ '$column' ],
|
|
164
164
|
inValue: true,
|
|
165
165
|
},
|
|
@@ -248,10 +248,12 @@ const schema = compileSchema( {
|
|
|
248
248
|
},
|
|
249
249
|
expand: {
|
|
250
250
|
class: 'columns',
|
|
251
|
-
|
|
251
|
+
xorException: 'ref', // see xorGroup :expr
|
|
252
|
+
inKind: [ '$column' ], // only valid in $column
|
|
252
253
|
},
|
|
253
254
|
inline: {
|
|
254
255
|
class: 'columns',
|
|
256
|
+
onlyWith: 'ref',
|
|
255
257
|
inKind: [ '$column' ], // only valid in $column
|
|
256
258
|
},
|
|
257
259
|
keys: {
|
|
@@ -292,17 +294,21 @@ const schema = compileSchema( {
|
|
|
292
294
|
// type properties (except: elements, enum, keys, on): ---------------------
|
|
293
295
|
type: {
|
|
294
296
|
type: artifactRef,
|
|
295
|
-
msgId: 'syntax-
|
|
297
|
+
msgId: 'syntax-expecting-reference',
|
|
296
298
|
optional: [ 'ref', 'global' ],
|
|
297
|
-
inKind: [ 'element', 'type', 'param', 'mixin', 'event', 'annotation' ],
|
|
299
|
+
inKind: [ 'element', 'type', 'param', 'mixin', 'event', 'annotation', 'extend' ],
|
|
298
300
|
},
|
|
299
301
|
targetAspect: {
|
|
300
302
|
type: artifactRef,
|
|
303
|
+
msgId: 'syntax-expecting-reference',
|
|
304
|
+
requires: 'elements',
|
|
301
305
|
optional: [ 'elements' ], // 'elements' for ad-hoc aspect compositions
|
|
302
306
|
inKind: [ 'element', 'type' ],
|
|
303
307
|
},
|
|
304
308
|
target: {
|
|
305
309
|
type: artifactRef,
|
|
310
|
+
msgId: 'syntax-expecting-reference',
|
|
311
|
+
requires: 'elements',
|
|
306
312
|
optional: [ 'elements' ], // 'elements' for ad-hoc COMPOSITION OF (gensrc style CSN)
|
|
307
313
|
inKind: [ 'element', 'type', 'mixin', 'param' ],
|
|
308
314
|
},
|
|
@@ -323,20 +329,20 @@ const schema = compileSchema( {
|
|
|
323
329
|
},
|
|
324
330
|
length: {
|
|
325
331
|
type: natnum,
|
|
326
|
-
inKind: [ 'element', 'type', 'param', 'annotation' ],
|
|
332
|
+
inKind: [ 'element', 'type', 'param', 'annotation', 'extend' ],
|
|
327
333
|
// we do not require a 'type', too - could be useful alone in a 'cast'
|
|
328
334
|
},
|
|
329
335
|
precision: {
|
|
330
336
|
type: natnum,
|
|
331
|
-
inKind: [ 'element', 'type', 'param', 'annotation' ],
|
|
337
|
+
inKind: [ 'element', 'type', 'param', 'annotation', 'extend' ],
|
|
332
338
|
},
|
|
333
339
|
scale: {
|
|
334
340
|
type: scalenum,
|
|
335
|
-
inKind: [ 'element', 'type', 'param', 'annotation' ],
|
|
341
|
+
inKind: [ 'element', 'type', 'param', 'annotation', 'extend' ],
|
|
336
342
|
},
|
|
337
343
|
srid: {
|
|
338
344
|
type: natnum,
|
|
339
|
-
inKind: [ 'element', 'type', 'param', 'annotation' ],
|
|
345
|
+
inKind: [ 'element', 'type', 'param', 'annotation' ], // no 'extend'!
|
|
340
346
|
},
|
|
341
347
|
srcmin: { // in 'cardinality'
|
|
342
348
|
type: renameTo( 'sourceMin', natnum ),
|
|
@@ -368,10 +374,11 @@ const schema = compileSchema( {
|
|
|
368
374
|
ref: {
|
|
369
375
|
arrayOf: refItem,
|
|
370
376
|
type: renameTo( 'path', arrayOf( refItem ) ),
|
|
371
|
-
msgId: 'syntax-
|
|
377
|
+
msgId: 'syntax-expecting-reference',
|
|
372
378
|
minLength: 1,
|
|
373
379
|
requires: 'id',
|
|
374
380
|
optional: [ 'id', 'args', 'cardinality', 'where' ],
|
|
381
|
+
xorException: 'expand', // see xorGroup :expr
|
|
375
382
|
inKind: [ '$column', 'key' ],
|
|
376
383
|
},
|
|
377
384
|
id: { // in 'ref' item
|
|
@@ -389,6 +396,7 @@ const schema = compileSchema( {
|
|
|
389
396
|
},
|
|
390
397
|
func: {
|
|
391
398
|
type: func,
|
|
399
|
+
xorException: 'xpr', // see xorGroup :expr
|
|
392
400
|
inKind: [ '$column' ],
|
|
393
401
|
},
|
|
394
402
|
args: {
|
|
@@ -405,6 +413,7 @@ const schema = compileSchema( {
|
|
|
405
413
|
xpr: {
|
|
406
414
|
class: 'condition',
|
|
407
415
|
type: xpr,
|
|
416
|
+
xorException: 'func', // see xorGroup :expr
|
|
408
417
|
// special treatment in $column
|
|
409
418
|
},
|
|
410
419
|
list: {
|
|
@@ -631,14 +640,13 @@ const schema = compileSchema( {
|
|
|
631
640
|
origin: { // old-style CSN
|
|
632
641
|
type: vZeroDelete, ignore: true,
|
|
633
642
|
},
|
|
634
|
-
source: { // CSN v0.1.0 query not supported
|
|
643
|
+
source: { // CSN v0.1.0 query not supported (is error)
|
|
635
644
|
type: ignore,
|
|
636
645
|
},
|
|
637
646
|
value: {
|
|
638
|
-
vZeroFor:
|
|
639
|
-
type:
|
|
640
|
-
|
|
641
|
-
inKind: [ '$column', 'enum' ],
|
|
647
|
+
vZeroFor: 'val', // CSN v0.1.0 property for `val` in enum def
|
|
648
|
+
type: annoValue,
|
|
649
|
+
// inKind: [ 'enum' ],
|
|
642
650
|
},
|
|
643
651
|
// ignored: ----------------------------------------------------------------
|
|
644
652
|
$location: { // special
|
|
@@ -747,6 +755,7 @@ function compileSchema( specs, proto = null) {
|
|
|
747
755
|
}
|
|
748
756
|
if (proto)
|
|
749
757
|
return r;
|
|
758
|
+
// Set property 'inValue' in main schema only:
|
|
750
759
|
for (const prop of exprProperties) {
|
|
751
760
|
if (r[prop].inValue === undefined)
|
|
752
761
|
r[prop].inValue = true;
|
|
@@ -772,8 +781,8 @@ function arrayOf( fn, filter = undefined ) {
|
|
|
772
781
|
} );
|
|
773
782
|
const minLength = spec.minLength || 0;
|
|
774
783
|
if (minLength > val.length) {
|
|
775
|
-
|
|
776
|
-
|
|
784
|
+
error( 'syntax-incomplete-array', location(true),
|
|
785
|
+
{ prop: spec.prop, n: minLength, '#': minLength === 1 ? 'one' : 'std' });
|
|
777
786
|
}
|
|
778
787
|
if (val.length)
|
|
779
788
|
++virtualLine; // [] in one JSON line
|
|
@@ -842,20 +851,8 @@ function object( obj, spec ) {
|
|
|
842
851
|
if (requires === undefined || requires === true) {
|
|
843
852
|
// console.log(csnProps,JSON.stringify(spec))
|
|
844
853
|
if (!relevantProps) {
|
|
845
|
-
error( 'syntax-
|
|
846
|
-
{
|
|
847
|
-
prop: spec.msgProp,
|
|
848
|
-
'#': (
|
|
849
|
-
// eslint-disable-next-line no-nested-ternary
|
|
850
|
-
!csnProps.length ? 'std'
|
|
851
|
-
: csnProps.length === 1 && csnProps[0] === 'as' ? 'as'
|
|
852
|
-
: 'relevant'),
|
|
853
|
-
},
|
|
854
|
-
{
|
|
855
|
-
std: 'Object in $(PROP) must have at least one property',
|
|
856
|
-
as: 'Object in $(PROP) must have at least one property other than \'as\'',
|
|
857
|
-
relevant: 'Object in $(PROP) must have at least one relevant property',
|
|
858
|
-
} );
|
|
854
|
+
error( 'syntax-incomplete-object', location(true),
|
|
855
|
+
{ '#': (obj.as != null ? 'as' : 'std'), prop: spec.msgProp, otherprop: 'as' } );
|
|
859
856
|
}
|
|
860
857
|
}
|
|
861
858
|
else if (requires) {
|
|
@@ -868,10 +865,10 @@ function object( obj, spec ) {
|
|
|
868
865
|
|
|
869
866
|
function vZeroDelete( o, spec ) { // for old-CSN property 'origin'
|
|
870
867
|
if (!csnVersionZero) {
|
|
871
|
-
warning( 'syntax-
|
|
872
|
-
'
|
|
868
|
+
warning( 'syntax-deprecated-property', location(true),
|
|
869
|
+
{ '#': 'zero', prop: spec.msgProp } );
|
|
873
870
|
}
|
|
874
|
-
|
|
871
|
+
ignore( o );
|
|
875
872
|
}
|
|
876
873
|
|
|
877
874
|
// Definitions, dictionaries and arrays of definitions (std signature) -------
|
|
@@ -881,7 +878,7 @@ function definition( def, spec, xsn, csn, name ) {
|
|
|
881
878
|
return {
|
|
882
879
|
kind: (inExtensions ? 'annotate' : spec.defaultKind),
|
|
883
880
|
name: {
|
|
884
|
-
id: '', path: [], absolute: name, location: location(),
|
|
881
|
+
id: '', path: [], absolute: name || '', location: location(),
|
|
885
882
|
},
|
|
886
883
|
location: location(),
|
|
887
884
|
};
|
|
@@ -914,7 +911,6 @@ function definition( def, spec, xsn, csn, name ) {
|
|
|
914
911
|
r.name.$inferred = 'as';
|
|
915
912
|
// TODO the following 'if' (if necessary) should be part of the core compiler
|
|
916
913
|
if (prop === 'definitions' || prop === 'vocabularies') { // as spec property
|
|
917
|
-
// xsn.name.path = name.split('.').map( id => ({ id, location: location() }) );
|
|
918
914
|
r.name = {
|
|
919
915
|
absolute: name,
|
|
920
916
|
id: name.substring( name.lastIndexOf('.') + 1 ),
|
|
@@ -953,7 +949,7 @@ function definition( def, spec, xsn, csn, name ) {
|
|
|
953
949
|
function dictionaryOf( elementFct ) {
|
|
954
950
|
return function dictionary( dict, spec ) {
|
|
955
951
|
if (!dict || typeof dict !== 'object' || Array.isArray( dict )) {
|
|
956
|
-
error( 'syntax-
|
|
952
|
+
error( 'syntax-expecting-object', location(true),
|
|
957
953
|
{ prop: spec.prop }); // spec.prop, not spec.msgProp!
|
|
958
954
|
return ignore( dict );
|
|
959
955
|
}
|
|
@@ -965,9 +961,8 @@ function dictionaryOf( elementFct ) {
|
|
|
965
961
|
++virtualLine;
|
|
966
962
|
for (const name of allNames) {
|
|
967
963
|
if (!name) {
|
|
968
|
-
warning( 'syntax-
|
|
969
|
-
{
|
|
970
|
-
'Property names in dictionary $(PROP) must not be empty' );
|
|
964
|
+
warning( 'syntax-invalid-name', location(true), // TODO: Error
|
|
965
|
+
{ '#': 'csn', parentprop: spec.prop } );
|
|
971
966
|
}
|
|
972
967
|
const val = elementFct( dict[name], spec, r, dict, name );
|
|
973
968
|
if (val !== undefined)
|
|
@@ -1042,9 +1037,11 @@ function validKind( val, spec, xsn ) {
|
|
|
1042
1037
|
if (val === xsn.kind) // has been set in definition - the same = ok!
|
|
1043
1038
|
return undefined; // already set in definition
|
|
1044
1039
|
if (val === 'view' && xsn.kind === 'entity') {
|
|
1045
|
-
warning( 'syntax-
|
|
1046
|
-
'
|
|
1040
|
+
warning( 'syntax-deprecated-value', location(true),
|
|
1041
|
+
{ '#': 'replace', prop: spec.msgProp, value: 'entity' } );
|
|
1047
1042
|
}
|
|
1043
|
+
// TODO: rather issue info at `abstract` and `$syntax`, i.e. current location is strange
|
|
1044
|
+
// change message id in a later change
|
|
1048
1045
|
else if ((val === 'entity' || val === 'type') && xsn.kind === 'aspect') {
|
|
1049
1046
|
info( 'syntax-aspect', location(true), { kind: 'aspect', '#': val },
|
|
1050
1047
|
{
|
|
@@ -1054,8 +1051,8 @@ function validKind( val, spec, xsn ) {
|
|
|
1054
1051
|
} );
|
|
1055
1052
|
}
|
|
1056
1053
|
else {
|
|
1057
|
-
error( 'syntax-
|
|
1058
|
-
'
|
|
1054
|
+
error( 'syntax-invalid-kind', location(true), { prop: spec.msgProp },
|
|
1055
|
+
'Invalid value for property $(PROP)' );
|
|
1059
1056
|
}
|
|
1060
1057
|
return ignore( val );
|
|
1061
1058
|
}
|
|
@@ -1063,12 +1060,16 @@ function validKind( val, spec, xsn ) {
|
|
|
1063
1060
|
function artifactRef( ref, spec ) {
|
|
1064
1061
|
if (!ref || typeof ref !== 'string')
|
|
1065
1062
|
return object( ref, spec );
|
|
1066
|
-
if (spec.prop !== 'type'
|
|
1063
|
+
if (spec.prop !== 'type')
|
|
1067
1064
|
return stringRef( ref, spec );
|
|
1068
|
-
// now the CSN v0.1.0 type of: 'Artifact..e1.e2'
|
|
1065
|
+
// now the CSN v0.1.0 type of: 'Artifact..e1.e2'; error if not csnVersionZero
|
|
1069
1066
|
const idx = ref.indexOf('..');
|
|
1070
1067
|
if (idx < 0)
|
|
1071
1068
|
return stringRef( ref, spec );
|
|
1069
|
+
if (!csnVersionZero) {
|
|
1070
|
+
warning( 'syntax-deprecated-value', location(true),
|
|
1071
|
+
{ '#': 'zero-replace', prop: spec.msgProp, value: '{ ref: […] }' } );
|
|
1072
|
+
}
|
|
1072
1073
|
const r = refSplit( ref.substring( idx + 2 ), spec.msgProp );
|
|
1073
1074
|
r.path.unshift( { id: ref.substring( 0, idx ), location: location() } );
|
|
1074
1075
|
return r;
|
|
@@ -1095,9 +1096,9 @@ function vZeroRef( name, spec, xsn ) {
|
|
|
1095
1096
|
if (!string( name, spec ))
|
|
1096
1097
|
return;
|
|
1097
1098
|
const path = name.split('.');
|
|
1098
|
-
if (!path.every( id => id)) {
|
|
1099
|
-
warning( 'syntax-
|
|
1100
|
-
'
|
|
1099
|
+
if (!path.every( id => id)) { // TODO: why just warning?
|
|
1100
|
+
warning( 'syntax-invalid-zero-ref', location(true), { prop: spec.msgProp },
|
|
1101
|
+
'Invalid string reference in property $(PROP)' );
|
|
1101
1102
|
}
|
|
1102
1103
|
xsn.path = path.map( id => ({ id, location: location() }) );
|
|
1103
1104
|
}
|
|
@@ -1107,18 +1108,17 @@ function vZeroRef( name, spec, xsn ) {
|
|
|
1107
1108
|
function boolOrNull( val, spec ) {
|
|
1108
1109
|
if ([ true, false, null ].includes( val ))
|
|
1109
1110
|
return { val, location: location() };
|
|
1110
|
-
warning( 'syntax-
|
|
1111
|
-
'
|
|
1111
|
+
warning( 'syntax-expecting-boolean', location(true), { prop: spec.msgProp },
|
|
1112
|
+
'Expecting boolean or null for property $(PROP)' );
|
|
1112
1113
|
ignore( val );
|
|
1113
1114
|
return { val: !!val, location: location() };
|
|
1114
1115
|
}
|
|
1115
1116
|
|
|
1116
1117
|
function string( val, spec ) {
|
|
1117
1118
|
if (typeof val === 'string' && val)
|
|
1118
|
-
// XSN TODO: do not require literal
|
|
1119
1119
|
return val;
|
|
1120
|
-
error( 'syntax-
|
|
1121
|
-
'
|
|
1120
|
+
error( 'syntax-expecting-string', location(true), { prop: spec.msgProp },
|
|
1121
|
+
'Expecting non-empty string for property $(PROP)' );
|
|
1122
1122
|
return ignore( val );
|
|
1123
1123
|
}
|
|
1124
1124
|
|
|
@@ -1126,8 +1126,8 @@ function stringVal( val, spec ) {
|
|
|
1126
1126
|
if (typeof val === 'string' && val)
|
|
1127
1127
|
// XSN TODO: do not require literal
|
|
1128
1128
|
return { val, literal: 'string', location: location() };
|
|
1129
|
-
error( 'syntax-
|
|
1130
|
-
'
|
|
1129
|
+
error( 'syntax-expecting-string', location(true), { prop: spec.msgProp },
|
|
1130
|
+
'Expecting non-empty string for property $(PROP)' );
|
|
1131
1131
|
return ignore( val );
|
|
1132
1132
|
}
|
|
1133
1133
|
|
|
@@ -1148,7 +1148,7 @@ function natnum( val, spec ) {
|
|
|
1148
1148
|
if (typeof val === 'number' && val >= 0)
|
|
1149
1149
|
// XSN TODO: do not require literal
|
|
1150
1150
|
return { val, literal: 'number', location: location() };
|
|
1151
|
-
error( spec.msgId || 'syntax-
|
|
1151
|
+
error( spec.msgId || 'syntax-expecting-natnum', location(true),
|
|
1152
1152
|
{ prop: spec.msgProp } );
|
|
1153
1153
|
return ignore( val );
|
|
1154
1154
|
}
|
|
@@ -1183,18 +1183,19 @@ function annoValue( val, spec ) {
|
|
|
1183
1183
|
/** @type {string|boolean} */
|
|
1184
1184
|
let seenEllipsis = false;
|
|
1185
1185
|
if (arrayLevelCount > 0) { // TODO: also inside structure (possible in CSN!)
|
|
1186
|
-
if (val.some( isEllipsis ))
|
|
1187
|
-
error( 'syntax-unexpected-ellipsis', location(true),
|
|
1186
|
+
if (val.some( isEllipsis )) { // remark: check is via parsing rules in CDL
|
|
1187
|
+
error( 'syntax-unexpected-ellipsis', location(true),
|
|
1188
|
+
{ '#': 'csn-nested', prop: '...' } );
|
|
1189
|
+
}
|
|
1188
1190
|
}
|
|
1189
1191
|
else {
|
|
1190
1192
|
for (const item of val) {
|
|
1191
|
-
if (seenEllipsis !== true) {
|
|
1193
|
+
if (seenEllipsis !== true) { // no `...` yet, or only `... up to`
|
|
1192
1194
|
seenEllipsis = isEllipsis( item ) || seenEllipsis;
|
|
1193
1195
|
}
|
|
1194
|
-
else if (isEllipsis( item )) { // with or without UP TO
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
'Expected no more than one $(CODE)' );
|
|
1196
|
+
else if (isEllipsis( item )) { // `...`with or without UP TO
|
|
1197
|
+
error( 'syntax-unexpected-ellipsis', location(true),
|
|
1198
|
+
{ '#': 'csn-duplicate', prop: '...', code: '{ "...": true }' } );
|
|
1198
1199
|
break;
|
|
1199
1200
|
}
|
|
1200
1201
|
}
|
|
@@ -1207,10 +1208,8 @@ function annoValue( val, spec ) {
|
|
|
1207
1208
|
};
|
|
1208
1209
|
arrayLevelCount--;
|
|
1209
1210
|
if (seenEllipsis === 'upTo') {
|
|
1210
|
-
error( 'syntax-
|
|
1211
|
-
{ code: '... up to', newcode: '...' }
|
|
1212
|
-
// TODO: should we be more CSN specific in the message?
|
|
1213
|
-
'Expecting an array item $(NEWCODE) after an item with $(CODE)' );
|
|
1211
|
+
error( 'syntax-missing-ellipsis', location(true), // at closing bracket
|
|
1212
|
+
{ code: '{ "...": ‹up to value› }', newcode: '{ "...": true }' } );
|
|
1214
1213
|
}
|
|
1215
1214
|
return retval;
|
|
1216
1215
|
}
|
|
@@ -1226,8 +1225,10 @@ function annoValue( val, spec ) {
|
|
|
1226
1225
|
}
|
|
1227
1226
|
else if (typeof val['='] === 'string') {
|
|
1228
1227
|
if (Object.keys( val ).length === 1) {
|
|
1229
|
-
virtualLine
|
|
1230
|
-
|
|
1228
|
+
++virtualLine;
|
|
1229
|
+
const r = refSplit( val['='], '=' );
|
|
1230
|
+
++virtualLine;
|
|
1231
|
+
return r;
|
|
1231
1232
|
}
|
|
1232
1233
|
}
|
|
1233
1234
|
else if (val['...'] && Object.keys( val ).length === 1) {
|
|
@@ -1276,26 +1277,29 @@ function value( val, spec, xsn ) { // for CSN property 'val'
|
|
|
1276
1277
|
xsn.literal = (val === null) ? 'null' : typeof val;
|
|
1277
1278
|
return val;
|
|
1278
1279
|
}
|
|
1279
|
-
error( 'syntax-
|
|
1280
|
+
error( 'syntax-expecting-scalar', location(true), { prop: spec.msgProp },
|
|
1280
1281
|
'Only scalar values are supported for property $(PROP)' );
|
|
1281
1282
|
return ignore( val );
|
|
1282
1283
|
}
|
|
1283
1284
|
|
|
1284
1285
|
function literal( lit, spec, xsn, csn ) {
|
|
1285
1286
|
// TODO: general: requires other property (here: 'val')
|
|
1287
|
+
if (!string( lit ))
|
|
1288
|
+
return undefined;
|
|
1286
1289
|
const type = (csn.val == null) ? 'null' : typeof csn.val;
|
|
1287
1290
|
if (lit === type) // also for 'object' which is an error for 'val'
|
|
1288
1291
|
return lit;
|
|
1289
|
-
|
|
1290
|
-
|
|
1292
|
+
const p = quotedLiteralPatterns[lit];
|
|
1293
|
+
if (p?.json_type === type) {
|
|
1294
|
+
// TODO: wrong position, we complain about the format here, that is in 'val',
|
|
1295
|
+
// TODO: make it then also more CSN-specific? Next change
|
|
1291
1296
|
if (p && p.test_fn && !p.test_fn(csn.val))
|
|
1292
1297
|
warning( 'syntax-invalid-literal', location(), { '#': p.test_variant } );
|
|
1293
1298
|
return lit;
|
|
1294
1299
|
}
|
|
1295
1300
|
if (lit === 'number' && type === 'string') // special case, not a quoted literal in CDL
|
|
1296
1301
|
return lit;
|
|
1297
|
-
error( 'syntax-
|
|
1298
|
-
'Expected valid string for property $(PROP)' );
|
|
1302
|
+
error( 'syntax-invalid-string', location(true), { prop: spec.msgProp } );
|
|
1299
1303
|
return ignore( lit );
|
|
1300
1304
|
}
|
|
1301
1305
|
|
|
@@ -1309,8 +1313,8 @@ function func( val, spec, xsn ) {
|
|
|
1309
1313
|
function xpr( exprs, spec, xsn, csn ) {
|
|
1310
1314
|
if (csn.func) {
|
|
1311
1315
|
if (!exprs.length) {
|
|
1312
|
-
|
|
1313
|
-
|
|
1316
|
+
error( 'syntax-incomplete-array', location(true),
|
|
1317
|
+
{ prop: 'xpr', siblingprop: 'func', '#': 'suffix' });
|
|
1314
1318
|
}
|
|
1315
1319
|
xsn.suffix = exprArgs( exprs, spec );
|
|
1316
1320
|
}
|
|
@@ -1342,9 +1346,9 @@ function args( exprs, spec ) {
|
|
|
1342
1346
|
return arrayOf( exprOrString )( exprs, spec );
|
|
1343
1347
|
}
|
|
1344
1348
|
else if (!exprs || typeof exprs !== 'object') {
|
|
1345
|
-
error( 'syntax-
|
|
1349
|
+
error( 'syntax-expecting-args', location(true),
|
|
1346
1350
|
{ prop: spec.prop }, // spec.prop, not spec.msgProp!
|
|
1347
|
-
'
|
|
1351
|
+
'Expecting array or object for property $(PROP)' );
|
|
1348
1352
|
return ignore( exprs );
|
|
1349
1353
|
}
|
|
1350
1354
|
const r = Object.create(null);
|
|
@@ -1362,16 +1366,24 @@ function args( exprs, spec ) {
|
|
|
1362
1366
|
}
|
|
1363
1367
|
|
|
1364
1368
|
function expr( e, spec ) {
|
|
1365
|
-
if (Array.isArray( e ) && e.length === 1) {
|
|
1366
|
-
|
|
1369
|
+
if (Array.isArray( e ) && e.length === 1) { // CSN v.0.1.0 way for parentheses
|
|
1370
|
+
const loc = location();
|
|
1371
|
+
if (e[0] && !e[0].op) // do not complain with 'op' (for which we complain)
|
|
1372
|
+
replaceZeroValue( spec, 'zero-parens' );
|
|
1367
1373
|
++virtualLine;
|
|
1368
1374
|
const r = expr( e[0], spec );
|
|
1375
|
+
if (!r)
|
|
1376
|
+
return r;
|
|
1377
|
+
if (r.$parens)
|
|
1378
|
+
r.$parens.push( loc );
|
|
1379
|
+
else
|
|
1380
|
+
r.$parens = [ loc ];
|
|
1369
1381
|
++virtualLine;
|
|
1370
|
-
return
|
|
1382
|
+
return r;
|
|
1371
1383
|
}
|
|
1372
1384
|
else if (e === null || [ 'string', 'number', 'boolean' ].includes( typeof e )) {
|
|
1373
1385
|
// && spec.optional.includes( 'val' )) ?
|
|
1374
|
-
replaceZeroValue( spec );
|
|
1386
|
+
replaceZeroValue( spec, 'zero-replace', '{ val: ‹value› }' );
|
|
1375
1387
|
return annoValue( e, spec );
|
|
1376
1388
|
}
|
|
1377
1389
|
return object( e, spec );
|
|
@@ -1402,20 +1414,6 @@ function condition( cond, spec ) {
|
|
|
1402
1414
|
};
|
|
1403
1415
|
}
|
|
1404
1416
|
|
|
1405
|
-
function vZeroValue( obj, spec, xsn ) {
|
|
1406
|
-
if (xsn.value) {
|
|
1407
|
-
// TODO: also "sign" xsn.value created by inValue to complain about both 'value' and 'ref' etc
|
|
1408
|
-
warning( 'syntax-unexpected-property', location(true), { prop: spec.msgProp },
|
|
1409
|
-
'Unexpected CSN property $(PROP)' );
|
|
1410
|
-
return undefined;
|
|
1411
|
-
}
|
|
1412
|
-
if (!csnVersionZero) {
|
|
1413
|
-
warning( 'syntax-zero-delete', location(true), { prop: spec.msgProp },
|
|
1414
|
-
'Delete/inline CSN v0.1.0 property $(PROP)' );
|
|
1415
|
-
}
|
|
1416
|
-
return expr( obj, spec );
|
|
1417
|
-
}
|
|
1418
|
-
|
|
1419
1417
|
// Queries (std signature) ---------------------------------------------------
|
|
1420
1418
|
|
|
1421
1419
|
function queryTerm( term, spec, xsn ) { // for CSN properties 'SELECT' and 'SET'
|
|
@@ -1457,17 +1455,16 @@ function excluding( array, spec, xsn ) {
|
|
|
1457
1455
|
xsn.excludingDict = r;
|
|
1458
1456
|
}
|
|
1459
1457
|
|
|
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
|
-
|
|
1466
1458
|
function duplicateExcluding( name, loc ) {
|
|
1467
|
-
error( 'duplicate-excluding', loc, { name, keyword: 'excluding' },
|
|
1459
|
+
error( 'syntax-duplicate-excluding', loc, { name, keyword: 'excluding' }, // TODO: also CDL
|
|
1468
1460
|
'Duplicate $(NAME) in the $(KEYWORD) clause' );
|
|
1469
1461
|
}
|
|
1470
1462
|
|
|
1463
|
+
function masked( val, spec ) {
|
|
1464
|
+
message( 'syntax-unsupported-masked', location(), { '#': 'csn', prop: 'masked' } );
|
|
1465
|
+
return boolOrNull( val, spec );
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1471
1468
|
function setOp( val, spec ) { // UNION, ...
|
|
1472
1469
|
// similar to string(), but without literal
|
|
1473
1470
|
return string( val, spec ) && { val, location: location() };
|
|
@@ -1483,9 +1480,10 @@ function join( val, spec, xsn ) {
|
|
|
1483
1480
|
|
|
1484
1481
|
function queryArgs( val, spec, xsn, csn ) {
|
|
1485
1482
|
if (Array.isArray( val ) && val.length > 1 && !csn.op) {
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1483
|
+
// Make it error 'syntax-missing-property#sibling' in v4:
|
|
1484
|
+
warning( 'syntax-deprecated-auto-union', location(true),
|
|
1485
|
+
{ siblingprop: 'args', prop: 'op' },
|
|
1486
|
+
'Object with property $(SIBLINGPROP) must also have a property $(PROP)' );
|
|
1489
1487
|
xsn.op = { val: 'union', location: location() };
|
|
1490
1488
|
}
|
|
1491
1489
|
return arrayOf( object )( val, spec ).map( q => q.query );
|
|
@@ -1502,9 +1500,9 @@ function i18nLang( val, spec, xsn, csn, langKey ) {
|
|
|
1502
1500
|
function translations( keyVal, spec, xsn, csn, textKey ) {
|
|
1503
1501
|
if (typeof keyVal === 'string') // allow empty string
|
|
1504
1502
|
return { val: keyVal, literal: 'string', location: location() };
|
|
1505
|
-
error( 'syntax-
|
|
1506
|
-
{ prop: textKey,
|
|
1507
|
-
'
|
|
1503
|
+
error( 'syntax-expecting-translation', location(true),
|
|
1504
|
+
{ prop: textKey, language: spec.prop },
|
|
1505
|
+
'Expecting string for text key $(PROP) of language $(LANGUAGE)' );
|
|
1508
1506
|
return ignore( keyVal );
|
|
1509
1507
|
}
|
|
1510
1508
|
|
|
@@ -1514,21 +1512,18 @@ function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
|
|
|
1514
1512
|
const p0 = schema[prop] ? prop : prop.charAt(0);
|
|
1515
1513
|
const s = (parentSpec.schema || schema)[p0];
|
|
1516
1514
|
if (!s || s.noPrefix && prop !== p0 ) {
|
|
1517
|
-
if (ourpropsRegex.test( prop ))
|
|
1518
|
-
// TODO v2: Warning only with --sloppy
|
|
1519
|
-
warning( 'syntax-unknown-property', location(true), { prop },
|
|
1520
|
-
'Unknown CSN property $(PROP)' );
|
|
1521
|
-
}
|
|
1522
|
-
else { // TODO v2: always (i.e. also with message) add to $extra
|
|
1515
|
+
if (!ourpropsRegex.test( prop ))
|
|
1523
1516
|
return { prop, type: extra };
|
|
1524
|
-
|
|
1517
|
+
// TODO v4: No warning with --sloppy
|
|
1518
|
+
warning( 'syntax-unknown-property', location(true), { prop },
|
|
1519
|
+
'Unknown CSN property $(PROP)' );
|
|
1520
|
+
return { type: ignore };
|
|
1525
1521
|
}
|
|
1526
1522
|
else if (!expected( p0, s )) {
|
|
1527
1523
|
if (s.ignore)
|
|
1528
1524
|
return { type: ignore };
|
|
1529
1525
|
if (s.vZeroIgnore && s.vZeroIgnore === csn[prop]) { // for "op": "call"
|
|
1530
|
-
warning( 'syntax-
|
|
1531
|
-
'Delete/inline CSN v0.1.0 property $(PROP)' );
|
|
1526
|
+
warning( 'syntax-deprecated-property', location(true), { '#': 'zero', prop } );
|
|
1532
1527
|
return { type: ignore };
|
|
1533
1528
|
}
|
|
1534
1529
|
const zero = s.vZeroFor;
|
|
@@ -1544,22 +1539,18 @@ function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
|
|
|
1544
1539
|
}
|
|
1545
1540
|
// eslint-disable-next-line no-nested-ternary
|
|
1546
1541
|
const variant = kind && s.inKind
|
|
1547
|
-
? ([ 'extend', 'annotate' ].includes(kind) ? kind : '
|
|
1548
|
-
: (parentSpec.msgProp ? '
|
|
1542
|
+
? ([ 'extend', 'annotate' ].includes(kind) ? kind : 'kind')
|
|
1543
|
+
: (parentSpec.msgProp ? 'prop' : 'top');
|
|
1549
1544
|
message( 'syntax-unexpected-property', location(true),
|
|
1550
1545
|
{
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
def: 'CSN property $(PROP) is not expected by a definition of kind $(KIND)',
|
|
1557
|
-
extend: 'CSN property $(PROP) is not expected by an extend in $(OTHERPROP)',
|
|
1558
|
-
annotate: 'CSN property $(PROP) is not expected by an annotate in $(OTHERPROP)',
|
|
1546
|
+
'#': variant,
|
|
1547
|
+
prop,
|
|
1548
|
+
parentprop:
|
|
1549
|
+
parentSpec.msgProp,
|
|
1550
|
+
kind,
|
|
1559
1551
|
} );
|
|
1560
|
-
// TODO: or still augment it? (but then also handle xorGroup)
|
|
1561
1552
|
}
|
|
1562
|
-
else if (checkAndSetXorGroup( s.xorGroup, prop, xor )) {
|
|
1553
|
+
else if (checkAndSetXorGroup( s.xorGroup, s.xorException, prop, xor )) {
|
|
1563
1554
|
onlyWith( s, s.onlyWith, csn, prop, xor, expected );
|
|
1564
1555
|
return s;
|
|
1565
1556
|
}
|
|
@@ -1604,37 +1595,34 @@ function onlyWith( spec, need, csn, prop, xor, expected ) {
|
|
|
1604
1595
|
need = allowed.find( p => !xor[schema[p].xorGroup] ) || allowed[0];
|
|
1605
1596
|
}
|
|
1606
1597
|
if (prop) {
|
|
1607
|
-
error( 'syntax-
|
|
1608
|
-
{
|
|
1609
|
-
'CSN property $(PROP) can only be used in combination with $(OTHERPROP)');
|
|
1598
|
+
error( 'syntax-missing-property', location(true), // location at $(PROP)
|
|
1599
|
+
{ '#': 'sibling', prop: need, siblingprop: prop } );
|
|
1610
1600
|
xor['no:req'] = prop;
|
|
1611
1601
|
}
|
|
1602
|
+
// TODO: does no:req work? check test3/NestedProjections/Basics/SyntaxErrorsCsn.err.csn
|
|
1612
1603
|
else if (!xor['no:req']) {
|
|
1613
|
-
error( 'syntax-
|
|
1614
|
-
{
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
extensions: 'Object in $(OTHERPROP) must have the property \'annotate\' or \'extend\'',
|
|
1604
|
+
error( 'syntax-missing-property', location(true), // TODO: re-check columns, expand, inline
|
|
1605
|
+
{
|
|
1606
|
+
'#': spec.prop,
|
|
1607
|
+
prop: need,
|
|
1608
|
+
parentprop: spec.msgProp,
|
|
1609
|
+
otherprop: 'annotate',
|
|
1620
1610
|
} );
|
|
1621
1611
|
}
|
|
1622
1612
|
return spec;
|
|
1623
1613
|
}
|
|
1624
1614
|
|
|
1625
|
-
function checkAndSetXorGroup( group, prop, xor ) {
|
|
1615
|
+
function checkAndSetXorGroup( group, exception, prop, xor ) {
|
|
1626
1616
|
if (!group)
|
|
1627
1617
|
return true;
|
|
1628
|
-
|
|
1618
|
+
const siblingprop = xor[group];
|
|
1619
|
+
if (!siblingprop) {
|
|
1629
1620
|
xor[group] = prop;
|
|
1630
1621
|
return true;
|
|
1631
1622
|
}
|
|
1632
|
-
if (
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
error( 'syntax-excluded-property', location(true),
|
|
1636
|
-
{ prop, otherprop: xor[group] },
|
|
1637
|
-
'CSN property $(PROP) can only be used alternatively to $(OTHERPROP)');
|
|
1623
|
+
if (siblingprop === exception)
|
|
1624
|
+
return true;
|
|
1625
|
+
message( 'syntax-unexpected-property', location(true), { '#': 'sibling', prop, siblingprop } );
|
|
1638
1626
|
return false;
|
|
1639
1627
|
}
|
|
1640
1628
|
|
|
@@ -1644,11 +1632,11 @@ function implicitName( ref ) {
|
|
|
1644
1632
|
return (typeof item === 'object') ? item && item.id : item;
|
|
1645
1633
|
}
|
|
1646
1634
|
|
|
1647
|
-
function replaceZeroProp(
|
|
1635
|
+
function replaceZeroProp( prop, otherprop ) {
|
|
1648
1636
|
if (csnVersionZero)
|
|
1649
1637
|
return;
|
|
1650
|
-
warning( 'syntax-
|
|
1651
|
-
'
|
|
1638
|
+
warning( 'syntax-deprecated-property', location(true),
|
|
1639
|
+
{ '#': 'zero-replace', prop, otherprop } );
|
|
1652
1640
|
}
|
|
1653
1641
|
|
|
1654
1642
|
// Other helper functions, locations -----------------------------------------
|
|
@@ -1656,15 +1644,15 @@ function replaceZeroProp( otherprop, prop ) {
|
|
|
1656
1644
|
function isArray( array, spec ) {
|
|
1657
1645
|
if (Array.isArray( array ))
|
|
1658
1646
|
return array;
|
|
1659
|
-
error( 'syntax-
|
|
1660
|
-
'
|
|
1647
|
+
error( 'syntax-expecting-array', location(true), { prop: spec.prop },
|
|
1648
|
+
'Expecting array for property $(PROP)' );
|
|
1661
1649
|
return ignore( array );
|
|
1662
1650
|
}
|
|
1663
1651
|
|
|
1664
1652
|
function isObject( obj, spec ) {
|
|
1665
1653
|
if (obj && typeof obj === 'object' && !Array.isArray( obj ))
|
|
1666
1654
|
return obj;
|
|
1667
|
-
error( spec.msgId || 'syntax-
|
|
1655
|
+
error( spec.msgId || 'syntax-expecting-object', location(true),
|
|
1668
1656
|
{ prop: spec.msgProp });
|
|
1669
1657
|
return ignore( obj );
|
|
1670
1658
|
}
|
|
@@ -1672,16 +1660,16 @@ function isObject( obj, spec ) {
|
|
|
1672
1660
|
function refSplit( name, prop ) {
|
|
1673
1661
|
const path = name.split('.');
|
|
1674
1662
|
if (!path.every( id => id)) {
|
|
1675
|
-
warning( 'syntax-
|
|
1676
|
-
'
|
|
1663
|
+
warning( 'syntax-expecting-name', location(true), { prop }, // TODO: re-check
|
|
1664
|
+
'Expecting correct name for property $(PROP)' );
|
|
1677
1665
|
}
|
|
1678
1666
|
return { path: path.map( id => ({ id, location: location() }) ), location: location() };
|
|
1679
1667
|
}
|
|
1680
1668
|
|
|
1681
|
-
function replaceZeroValue( spec ) {
|
|
1682
|
-
if (!csnVersionZero && spec.vZeroFor
|
|
1683
|
-
warning( 'syntax-
|
|
1684
|
-
'
|
|
1669
|
+
function replaceZeroValue( spec, msgid, otherprop ) {
|
|
1670
|
+
if (!csnVersionZero && !spec.vZeroFor) {
|
|
1671
|
+
warning( 'syntax-deprecated-value', location(true),
|
|
1672
|
+
{ '#': msgid, prop: spec.msgProp, otherprop } );
|
|
1685
1673
|
}
|
|
1686
1674
|
}
|
|
1687
1675
|
|
|
@@ -1710,7 +1698,7 @@ function pushLocation( obj ) {
|
|
|
1710
1698
|
else if (!loc || typeof loc !== 'string') {
|
|
1711
1699
|
if (loc)
|
|
1712
1700
|
dollarLocations.push( null ); // must match with popLocation()
|
|
1713
|
-
error( 'syntax-
|
|
1701
|
+
error( 'syntax-expecting-object', location(true), { prop: '$location' } );
|
|
1714
1702
|
}
|
|
1715
1703
|
// hidden feature: string $location
|
|
1716
1704
|
const m = /:(\d+)(?::(\d+))?$/.exec( loc ); // extra '^'s at end deliberately left out
|
|
@@ -1767,7 +1755,7 @@ function toXsn( csn, filename, options, messageFunctions ) {
|
|
|
1767
1755
|
({ message, error, warning, info } = messageFunctions);
|
|
1768
1756
|
|
|
1769
1757
|
if (csnVersionZero) {
|
|
1770
|
-
warning( 'syntax-csn-
|
|
1758
|
+
warning( 'syntax-deprecated-csn-version', location(true), {},
|
|
1771
1759
|
'Parsing CSN version 0.1.0' );
|
|
1772
1760
|
}
|
|
1773
1761
|
const r = object( csn, topLevelSpec );
|
|
@@ -1823,7 +1811,8 @@ function parse( source, filename = 'csn.json', options = {}, messageFunctions =
|
|
|
1823
1811
|
line,
|
|
1824
1812
|
col: column,
|
|
1825
1813
|
};
|
|
1826
|
-
messageFunctions.error( 'syntax-
|
|
1814
|
+
messageFunctions.error( 'syntax-invalid-json', loc, { msg },
|
|
1815
|
+
'Invalid JSON: $(MSG)' );
|
|
1827
1816
|
return xsn;
|
|
1828
1817
|
}
|
|
1829
1818
|
}
|