@sap/cds-compiler 3.5.4 → 3.6.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 +65 -2
- package/bin/cdsc.js +14 -6
- package/doc/CHANGELOG_ARCHIVE.md +10 -10
- package/doc/CHANGELOG_DEPRECATED.md +2 -2
- package/lib/api/main.js +32 -55
- package/lib/api/options.js +3 -2
- package/lib/api/validate.js +5 -0
- package/lib/base/message-registry.js +104 -32
- package/lib/base/messages.js +277 -212
- package/lib/base/optionProcessorHelper.js +9 -2
- package/lib/base/shuffle.js +50 -0
- package/lib/checks/actionsFunctions.js +37 -20
- package/lib/checks/foreignKeys.js +13 -6
- package/lib/checks/nonexpandableStructured.js +1 -2
- package/lib/checks/onConditions.js +21 -19
- package/lib/checks/parameters.js +1 -1
- package/lib/checks/queryNoDbArtifacts.js +2 -0
- package/lib/checks/types.js +16 -22
- package/lib/compiler/assert-consistency.js +31 -28
- package/lib/compiler/builtins.js +20 -4
- package/lib/compiler/checks.js +72 -63
- package/lib/compiler/define.js +396 -314
- package/lib/compiler/extend.js +55 -49
- package/lib/compiler/index.js +5 -0
- package/lib/compiler/populate.js +28 -11
- package/lib/compiler/propagator.js +2 -1
- package/lib/compiler/resolve.js +28 -13
- package/lib/compiler/shared.js +15 -10
- package/lib/compiler/utils.js +7 -7
- package/lib/edm/annotations/genericTranslation.js +51 -46
- package/lib/edm/annotations/preprocessAnnotations.js +37 -40
- package/lib/edm/csn2edm.js +69 -21
- package/lib/edm/edm.js +2 -2
- package/lib/edm/edmInboundChecks.js +6 -8
- package/lib/edm/edmPreprocessor.js +88 -80
- package/lib/edm/edmUtils.js +6 -15
- package/lib/gen/Dictionary.json +81 -13
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +2 -1
- package/lib/gen/languageParser.js +4680 -4484
- package/lib/inspect/inspectModelStatistics.js +2 -1
- package/lib/inspect/inspectPropagation.js +2 -1
- package/lib/json/from-csn.js +131 -78
- package/lib/json/to-csn.js +39 -23
- package/lib/language/antlrParser.js +0 -3
- package/lib/language/docCommentParser.js +7 -3
- package/lib/language/errorStrategy.js +3 -2
- package/lib/language/genericAntlrParser.js +96 -41
- package/lib/language/language.g4 +112 -128
- package/lib/language/multiLineStringParser.js +2 -1
- package/lib/main.d.ts +115 -2
- package/lib/main.js +16 -3
- package/lib/model/csnRefs.js +32 -4
- package/lib/model/csnUtils.js +109 -179
- package/lib/model/enrichCsn.js +13 -8
- package/lib/model/revealInternalProperties.js +4 -3
- package/lib/optionProcessor.js +22 -3
- package/lib/render/manageConstraints.js +11 -15
- package/lib/render/toCdl.js +144 -47
- package/lib/render/toHdbcds.js +22 -22
- package/lib/render/toRename.js +3 -4
- package/lib/render/toSql.js +31 -22
- package/lib/render/utils/delta.js +3 -1
- package/lib/render/utils/sql.js +2 -14
- package/lib/transform/db/associations.js +6 -6
- package/lib/transform/db/cdsPersistence.js +3 -3
- package/lib/transform/db/constraints.js +4 -6
- package/lib/transform/db/expansion.js +4 -4
- package/lib/transform/db/flattening.js +12 -15
- package/lib/transform/db/temporal.js +4 -3
- package/lib/transform/db/transformExists.js +13 -7
- package/lib/transform/draft/db.js +7 -7
- package/lib/transform/forOdataNew.js +15 -4
- package/lib/transform/forRelationalDB.js +59 -41
- package/lib/transform/odata/toFinalBaseType.js +106 -82
- package/lib/transform/odata/typesExposure.js +26 -17
- package/lib/transform/odata/utils.js +1 -1
- package/lib/transform/parseExpr.js +1 -1
- package/lib/transform/transformUtilsNew.js +33 -10
- package/lib/transform/translateAssocsToJoins.js +8 -7
- package/lib/transform/universalCsn/coreComputed.js +7 -5
- package/lib/transform/universalCsn/universalCsnEnricher.js +12 -4
- package/lib/utils/timetrace.js +2 -2
- package/package.json +1 -2
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { forEach } = require('../utils/objectUtils');
|
|
4
4
|
const { term } = require('../utils/term');
|
|
5
|
+
const { CompilerAssertion } = require('../base/error');
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Return a string representation of the inspected results.
|
|
@@ -70,7 +71,7 @@ function countDefinitionKinds( xsn ) {
|
|
|
70
71
|
else if (result[def.kind] !== undefined)
|
|
71
72
|
++result[def.kind];
|
|
72
73
|
else
|
|
73
|
-
throw new
|
|
74
|
+
throw new CompilerAssertion(`Unhandled kind: ${ def.kind } for ${ name }`);
|
|
74
75
|
});
|
|
75
76
|
return result;
|
|
76
77
|
}
|
|
@@ -4,6 +4,7 @@ const { createMessageFunctions } = require('../base/messages');
|
|
|
4
4
|
const { locationString } = require('../base/location');
|
|
5
5
|
const { findArtifact, stringRefToPath } = require('./inspectUtils');
|
|
6
6
|
const { term } = require('../utils/term');
|
|
7
|
+
const { CompilerAssertion } = require('../base/error');
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* @param {XSN.Model} xsn
|
|
@@ -97,7 +98,7 @@ function _inspectAnnotations( artifactXsn ) {
|
|
|
97
98
|
}
|
|
98
99
|
// fallthrough
|
|
99
100
|
default:
|
|
100
|
-
throw new
|
|
101
|
+
throw new CompilerAssertion(`inspect anno: Unhandled Case: ${ annoXsn.$priority }`);
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
maxAnnoLength = Math.max(maxAnnoLength, anno.length);
|
package/lib/json/from-csn.js
CHANGED
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
* dictionary key by default.
|
|
34
34
|
* @property {string} [msgProp] Display name of the property. compileSchema() sets it to
|
|
35
35
|
* the dictionary key (+ optional '[]') by default.
|
|
36
|
-
* @property {string}
|
|
36
|
+
* @property {string} [msgVariant] Use this message variant instead of the default one.
|
|
37
37
|
* Allows more precise and detailed error messages.
|
|
38
38
|
* @property {string|string[]|false} [requires] If the value is a string, then the given sub-
|
|
39
39
|
* property is required. If 'undefined', then at
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
* @property {boolean} [inValue] Puts the value into an XSN property "value",
|
|
64
64
|
* e.g. { value: ... }
|
|
65
65
|
* @property {string} [xorGroup] Corresponding xor group. It references a value of
|
|
66
|
-
*
|
|
66
|
+
* xorGroups. If set then only one property of of the
|
|
67
67
|
* xorGroup may be set, e.g. if target is set, elements
|
|
68
68
|
* may not.
|
|
69
69
|
* @property {string} [xsnOp] Defines the operator to be used for XSN. Used for SET
|
|
@@ -89,6 +89,7 @@
|
|
|
89
89
|
|
|
90
90
|
const { dictAdd } = require('../base/dictionaries');
|
|
91
91
|
const { quotedLiteralPatterns } = require('../compiler/builtins');
|
|
92
|
+
const { CompilerAssertion } = require('../base/error');
|
|
92
93
|
|
|
93
94
|
const $location = Symbol.for('cds.$location');
|
|
94
95
|
|
|
@@ -97,7 +98,7 @@ let inExtensions = null;
|
|
|
97
98
|
let vocabInDefinitions = null; // must be reset!
|
|
98
99
|
|
|
99
100
|
// CSN property names reserved for CAP
|
|
100
|
-
const ourpropsRegex = /^[_
|
|
101
|
+
const ourpropsRegex = /^(?:[_$=#@][a-zA-Z]*[0-9]*|[a-zA-Z]+[0-9]*)$/;
|
|
101
102
|
|
|
102
103
|
// Sync with definition in to-csn.js:
|
|
103
104
|
const typeProperties = [
|
|
@@ -120,7 +121,7 @@ const xorGroups = {
|
|
|
120
121
|
':expr': [ // see also xorException property in schema
|
|
121
122
|
'ref', 'xpr', 'list', 'val', '#', 'func', 'SELECT', 'SET', 'expand',
|
|
122
123
|
'=', 'path', 'value', 'op', // '='/'path' is CSN v0.1.0 here
|
|
123
|
-
],
|
|
124
|
+
], // also set xorGroupTwo ':col' for 'expand' and 'inline'
|
|
124
125
|
':ext': [ 'annotate', 'extend' ], // TODO: better msg for test/negative/UnexpectedProperties.csn
|
|
125
126
|
':assoc': [ 'on', 'keys', 'foreignKeys', 'onCond' ], // 'foreignKeys'/'onCond' is CSN v0.1.0
|
|
126
127
|
// TODO - improve consequential errors: assume no name given with `join` or `inline`?
|
|
@@ -138,7 +139,7 @@ const schemaClasses = {
|
|
|
138
139
|
condition: {
|
|
139
140
|
arrayOf: exprOrString,
|
|
140
141
|
type: condition,
|
|
141
|
-
|
|
142
|
+
msgVariant: 'or-string', // for 'syntax-expecting-object'
|
|
142
143
|
// TODO: also specify requires here, and adapt onlyWith()
|
|
143
144
|
optional: exprProperties,
|
|
144
145
|
},
|
|
@@ -148,11 +149,11 @@ const schemaClasses = {
|
|
|
148
149
|
},
|
|
149
150
|
natnumOrStar: {
|
|
150
151
|
type: natnumOrStar,
|
|
151
|
-
|
|
152
|
+
msgVariant: 'or-asterisk', // for 'syntax-expecting-unsigned-int'
|
|
152
153
|
},
|
|
153
154
|
columns: {
|
|
154
155
|
arrayOf: selectItem,
|
|
155
|
-
|
|
156
|
+
msgVariant: 'or-asterisk', // for 'syntax-expecting-object'
|
|
156
157
|
defaultKind: '$column',
|
|
157
158
|
validKinds: [], // pseudo kind '$column'
|
|
158
159
|
// A column with only as+cast.type is a new association
|
|
@@ -251,10 +252,12 @@ const schema = compileSchema( {
|
|
|
251
252
|
expand: {
|
|
252
253
|
class: 'columns',
|
|
253
254
|
xorException: 'ref', // see xorGroup :expr
|
|
255
|
+
xorGroupTwo: ':col',
|
|
254
256
|
inKind: [ '$column' ], // only valid in $column
|
|
255
257
|
},
|
|
256
258
|
inline: {
|
|
257
259
|
class: 'columns',
|
|
260
|
+
xorGroupTwo: ':col',
|
|
258
261
|
onlyWith: 'ref',
|
|
259
262
|
inKind: [ '$column' ], // only valid in $column
|
|
260
263
|
},
|
|
@@ -296,20 +299,20 @@ const schema = compileSchema( {
|
|
|
296
299
|
// type properties (except: elements, enum, keys, on): ---------------------
|
|
297
300
|
type: {
|
|
298
301
|
type: artifactRef,
|
|
299
|
-
|
|
302
|
+
msgVariant: 'or-object', // for 'syntax-expecting-string',
|
|
300
303
|
optional: [ 'ref', 'global' ],
|
|
301
304
|
inKind: [ 'element', 'type', 'param', 'mixin', 'event', 'annotation', 'extend' ],
|
|
302
305
|
},
|
|
303
306
|
targetAspect: {
|
|
304
307
|
type: artifactRef,
|
|
305
|
-
|
|
308
|
+
msgVariant: 'or-object', // for 'syntax-expecting-string',
|
|
306
309
|
requires: 'elements',
|
|
307
310
|
optional: [ 'elements' ], // 'elements' for ad-hoc aspect compositions
|
|
308
311
|
inKind: [ 'element', 'type' ],
|
|
309
312
|
},
|
|
310
313
|
target: {
|
|
311
314
|
type: artifactRef,
|
|
312
|
-
|
|
315
|
+
msgVariant: 'or-object', // for 'syntax-expecting-string',
|
|
313
316
|
requires: 'elements',
|
|
314
317
|
optional: [ 'elements' ], // 'elements' for ad-hoc COMPOSITION OF (gensrc style CSN)
|
|
315
318
|
inKind: [ 'element', 'type', 'mixin', 'param' ],
|
|
@@ -376,7 +379,7 @@ const schema = compileSchema( {
|
|
|
376
379
|
ref: {
|
|
377
380
|
arrayOf: refItem,
|
|
378
381
|
type: renameTo( 'path', arrayOf( refItem ) ),
|
|
379
|
-
|
|
382
|
+
msgVariant: 'or-object', // for 'syntax-expecting-string',
|
|
380
383
|
minLength: 1,
|
|
381
384
|
requires: 'id',
|
|
382
385
|
optional: [ 'id', 'args', 'cardinality', 'where' ],
|
|
@@ -424,20 +427,21 @@ const schema = compileSchema( {
|
|
|
424
427
|
},
|
|
425
428
|
val: {
|
|
426
429
|
type: value,
|
|
427
|
-
inKind: [ '$column', 'enum'
|
|
430
|
+
inKind: [ '$column', 'enum' ],
|
|
431
|
+
// see also extra handling for 'element' in extension, see definition()
|
|
428
432
|
},
|
|
429
433
|
literal: {
|
|
430
434
|
type: literal,
|
|
431
435
|
onlyWith: 'val',
|
|
432
|
-
inKind: [ '$column', 'enum' ],
|
|
436
|
+
inKind: [ '$column', 'enum' ], // 'element' sometimes in extension
|
|
433
437
|
},
|
|
434
438
|
'#': {
|
|
435
439
|
noPrefix: true, // schema spec for '#', not for '#whatever'
|
|
436
440
|
type: symbol,
|
|
437
441
|
// Note: We emit a warning if '#' is used in enums. Because the compiler
|
|
438
442
|
// can generate CSN like this, we need to be able to parse it.
|
|
439
|
-
|
|
440
|
-
|
|
443
|
+
inKind: [ '$column', 'enum' ],
|
|
444
|
+
// see also extra handling for 'element' in extension, see definition()
|
|
441
445
|
},
|
|
442
446
|
path: { // in CSN v0.1.0 'foreignKeys'
|
|
443
447
|
vZeroFor: 'ref',
|
|
@@ -446,6 +450,7 @@ const schema = compileSchema( {
|
|
|
446
450
|
type: vZeroRef,
|
|
447
451
|
},
|
|
448
452
|
'=': { // v0.1.0 { "=": "A.B" } for v1.0 { "ref": ["A", "B"] }
|
|
453
|
+
noPrefix: true, // schema spec for '=', not for '=whatever'
|
|
449
454
|
vZeroFor: 'ref',
|
|
450
455
|
inKind: [], // still used in annotation assignments...
|
|
451
456
|
type: vZeroRef, // ...see property '@' / function annotation()
|
|
@@ -579,10 +584,12 @@ const schema = compileSchema( {
|
|
|
579
584
|
// miscellaneous properties in definitions: --------------------------------
|
|
580
585
|
doc: {
|
|
581
586
|
type: stringValOrNull,
|
|
587
|
+
msgVariant: 'or-null', // for 'syntax-expecting-string'
|
|
582
588
|
inKind: () => true, // allowed in all definitions (including columns and extensions)
|
|
583
589
|
},
|
|
584
590
|
'@': { // for all properties starting with '@'
|
|
585
|
-
|
|
591
|
+
noPrefix: false, // just '@' is no CSN property
|
|
592
|
+
prop: '@‹anno›', // which property name do messages use for annotation assignments?
|
|
586
593
|
type: annotation,
|
|
587
594
|
inKind: () => true, // allowed in all definitions (including columns and extensions)
|
|
588
595
|
},
|
|
@@ -646,9 +653,10 @@ const schema = compileSchema( {
|
|
|
646
653
|
type: ignore,
|
|
647
654
|
},
|
|
648
655
|
value: {
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
//
|
|
656
|
+
class: 'expression', // calculated elements
|
|
657
|
+
vZeroFor: 'val', // CSN v0.1.0 property for `val` in enum def
|
|
658
|
+
// type: annoValue,
|
|
659
|
+
inKind: [ 'element' ],
|
|
652
660
|
},
|
|
653
661
|
// ignored: ----------------------------------------------------------------
|
|
654
662
|
$location: { // special
|
|
@@ -679,8 +687,16 @@ const schema = compileSchema( {
|
|
|
679
687
|
$generated: {
|
|
680
688
|
type: string,
|
|
681
689
|
},
|
|
682
|
-
$: {
|
|
683
|
-
|
|
690
|
+
$: {
|
|
691
|
+
noPrefix: false, // just '$' is no CSN property
|
|
692
|
+
type: ignore,
|
|
693
|
+
ignore: true,
|
|
694
|
+
}, // including $origin
|
|
695
|
+
_: {
|
|
696
|
+
noPrefix: false, // just '_' is no CSN property
|
|
697
|
+
type: ignore,
|
|
698
|
+
ignore: true,
|
|
699
|
+
},
|
|
684
700
|
} );
|
|
685
701
|
|
|
686
702
|
const topLevelSpec = {
|
|
@@ -745,7 +761,7 @@ function compileSchema( specs, proto = null ) {
|
|
|
745
761
|
else if (s.dictionaryOf)
|
|
746
762
|
s.type = dictionaryOf( s.dictionaryOf );
|
|
747
763
|
else
|
|
748
|
-
throw new
|
|
764
|
+
throw new CompilerAssertion( `Missing type specification for property "${ p }"` );
|
|
749
765
|
}
|
|
750
766
|
}
|
|
751
767
|
// Set property 'xorGroup' in main and sub schema:
|
|
@@ -814,6 +830,7 @@ function extra( node, spec, xsn ) {
|
|
|
814
830
|
if (!xsn.$extra)
|
|
815
831
|
xsn.$extra = Object.create(null);
|
|
816
832
|
xsn.$extra[spec.prop] = node;
|
|
833
|
+
return ignore( node );
|
|
817
834
|
}
|
|
818
835
|
|
|
819
836
|
function eventualCast( obj, spec, xsn ) {
|
|
@@ -887,13 +904,22 @@ function definition( def, spec, xsn, csn, name ) {
|
|
|
887
904
|
}
|
|
888
905
|
pushLocation( def );
|
|
889
906
|
const savedInExtensions = inExtensions;
|
|
890
|
-
|
|
907
|
+
let kind = calculateKind( def, spec ); // might set inExtensions
|
|
891
908
|
const r = (kind === '$column') ? { location: location() } : { location: location(), kind };
|
|
892
909
|
const xor = {};
|
|
893
910
|
const { prop } = spec;
|
|
894
911
|
const kind0 = (spec.validKinds.length || spec.prop === 'extensions') && kind;
|
|
895
912
|
const csnProps = Object.keys( def );
|
|
896
913
|
|
|
914
|
+
// If we have `extend … with { name = 3 }`, it could mean adding an element or an enum.
|
|
915
|
+
// We use `elements: { name: { val: 3 } }` to represent this ambiguity.
|
|
916
|
+
if (savedInExtensions === '' && prop === 'elements' && !def.value &&
|
|
917
|
+
(def.val !== undefined || def['#'] !== undefined) &&
|
|
918
|
+
def.virtual === undefined && def.key === undefined && def.masked === undefined &&
|
|
919
|
+
def.type === undefined && def.elements === undefined) {
|
|
920
|
+
r.$syntax = 'enum';
|
|
921
|
+
kind = 'enum'; // for function expected()
|
|
922
|
+
}
|
|
897
923
|
if (csnProps.length) {
|
|
898
924
|
const valueName = (prop === 'keys' || prop === 'foreignKeys' ? 'targetElement' : 'value');
|
|
899
925
|
// the next is basically object() + the inValue handling
|
|
@@ -964,7 +990,7 @@ function dictionaryOf( elementFct ) {
|
|
|
964
990
|
for (const name of allNames) {
|
|
965
991
|
if (!name) {
|
|
966
992
|
message( 'syntax-invalid-name', location(true),
|
|
967
|
-
{ '#': '
|
|
993
|
+
{ '#': 'dict', parentprop: spec.prop } );
|
|
968
994
|
}
|
|
969
995
|
const val = elementFct( dict[name], spec, r, dict, name );
|
|
970
996
|
if (val !== undefined)
|
|
@@ -992,6 +1018,7 @@ function keys( array, spec, xsn ) {
|
|
|
992
1018
|
xsn.foreignKeys = r;
|
|
993
1019
|
}
|
|
994
1020
|
|
|
1021
|
+
// Use with spec.msgVariant: 'or-asterisk'
|
|
995
1022
|
function selectItem( def, spec, xsn, csn ) {
|
|
996
1023
|
if (def === '*') // compile() will complain about repeated '*'s
|
|
997
1024
|
return { val: '*', location: location() };
|
|
@@ -1083,9 +1110,14 @@ function validKind( val, spec, xsn ) {
|
|
|
1083
1110
|
return ignore( val );
|
|
1084
1111
|
}
|
|
1085
1112
|
|
|
1113
|
+
// Use with spec.msgVariant: 'or-object'
|
|
1086
1114
|
function artifactRef( ref, spec ) {
|
|
1087
|
-
if (!ref || typeof ref !== 'string')
|
|
1088
|
-
|
|
1115
|
+
if (!ref || typeof ref !== 'string') {
|
|
1116
|
+
if (ref && typeof ref === 'object' && !Array.isArray( ref ))
|
|
1117
|
+
return object( ref, spec );
|
|
1118
|
+
// use error message 'syntax-expecting-string' (string more likely than object):
|
|
1119
|
+
return string( ref, spec );
|
|
1120
|
+
}
|
|
1089
1121
|
if (spec.prop !== 'type')
|
|
1090
1122
|
return stringRef( ref, spec );
|
|
1091
1123
|
// now the CSN v0.1.0 type of: 'Artifact..e1.e2'; error if not csnVersionZero
|
|
@@ -1096,7 +1128,7 @@ function artifactRef( ref, spec ) {
|
|
|
1096
1128
|
warning( 'syntax-deprecated-value', location(true),
|
|
1097
1129
|
{ '#': 'zero-replace', prop: spec.msgProp, value: '{ ref: […] }' } );
|
|
1098
1130
|
}
|
|
1099
|
-
const r = refSplit( ref.substring( idx + 2 ),
|
|
1131
|
+
const r = refSplit( ref.substring( idx + 2 ), 'type' );
|
|
1100
1132
|
r.path.unshift( { id: ref.substring( 0, idx ), location: location() } );
|
|
1101
1133
|
return r;
|
|
1102
1134
|
}
|
|
@@ -1106,10 +1138,14 @@ function stringRef( ref, spec ) {
|
|
|
1106
1138
|
{ path: [ { id: ref, location: location() } ], location: location() };
|
|
1107
1139
|
}
|
|
1108
1140
|
|
|
1141
|
+
// with spec.msgVariant: 'or-object'
|
|
1109
1142
|
function refItem( item, spec ) {
|
|
1110
1143
|
if (typeof item === 'string' && item)
|
|
1111
1144
|
return { id: item, location: location() };
|
|
1112
|
-
|
|
1145
|
+
if (item && typeof item === 'object' && !Array.isArray( item ))
|
|
1146
|
+
return object( item, spec );
|
|
1147
|
+
// use error message 'syntax-expecting-string' (string more likely than object):
|
|
1148
|
+
return string( item, spec );
|
|
1113
1149
|
}
|
|
1114
1150
|
|
|
1115
1151
|
function asScope( scope, spec, xsn ) {
|
|
@@ -1143,8 +1179,8 @@ function boolOrNull( val, spec ) {
|
|
|
1143
1179
|
function string( val, spec ) {
|
|
1144
1180
|
if (typeof val === 'string' && val)
|
|
1145
1181
|
return val;
|
|
1146
|
-
error( 'syntax-expecting-string', location(true),
|
|
1147
|
-
'
|
|
1182
|
+
error( 'syntax-expecting-string', location(true),
|
|
1183
|
+
{ '#': spec.msgVariant, prop: spec.msgProp } );
|
|
1148
1184
|
return ignore( val );
|
|
1149
1185
|
}
|
|
1150
1186
|
|
|
@@ -1175,14 +1211,12 @@ function natnum( val, spec ) {
|
|
|
1175
1211
|
// XSN TODO: do not require literal
|
|
1176
1212
|
return { val, literal: 'number', location: location() };
|
|
1177
1213
|
const loc = location(true);
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
else
|
|
1181
|
-
error( 'syntax-expecting-unsigned-int', loc, { '#': 'csn', prop: spec.msgProp } );
|
|
1214
|
+
error( 'syntax-expecting-unsigned-int', loc,
|
|
1215
|
+
{ '#': spec.msgVariant || 'csn', prop: spec.msgProp, op: '*' } );
|
|
1182
1216
|
return ignore( val );
|
|
1183
1217
|
}
|
|
1184
1218
|
|
|
1185
|
-
// Use with spec.
|
|
1219
|
+
// Use with spec.msgVariant !
|
|
1186
1220
|
function natnumOrStar( val, spec ) {
|
|
1187
1221
|
return (val === '*')
|
|
1188
1222
|
? { val, literal: 'string', location: location() }
|
|
@@ -1196,7 +1230,14 @@ function symbol( id, spec, xsn ) { // for CSN property '#'
|
|
|
1196
1230
|
xsn.sym = { id, location: location() };
|
|
1197
1231
|
}
|
|
1198
1232
|
|
|
1199
|
-
|
|
1233
|
+
/**
|
|
1234
|
+
* returns:
|
|
1235
|
+
* - false = no "...",
|
|
1236
|
+
* - true = "..." without UP TO,
|
|
1237
|
+
* - 'upTo' = "..." with UP TO
|
|
1238
|
+
*
|
|
1239
|
+
* @returns {string|boolean}
|
|
1240
|
+
*/
|
|
1200
1241
|
function isEllipsis( val ) {
|
|
1201
1242
|
return val && typeof val === 'object' && '...' in val && Object.keys(val).length === 1 &&
|
|
1202
1243
|
(val['...'] === true || 'upTo');
|
|
@@ -1244,12 +1285,11 @@ function annoValue( val, spec ) {
|
|
|
1244
1285
|
}
|
|
1245
1286
|
if (typeof val['#'] === 'string') {
|
|
1246
1287
|
if (Object.keys( val ).length === 1) {
|
|
1247
|
-
virtualLine
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
};
|
|
1288
|
+
++virtualLine;
|
|
1289
|
+
const xsn = { location: location() };
|
|
1290
|
+
symbol( val['#'], schema['#'], xsn );
|
|
1291
|
+
++virtualLine;
|
|
1292
|
+
return xsn;
|
|
1253
1293
|
}
|
|
1254
1294
|
}
|
|
1255
1295
|
else if (typeof val['='] === 'string') {
|
|
@@ -1287,7 +1327,7 @@ function annotation( val, spec, xsn, csn, name ) {
|
|
|
1287
1327
|
const absolute = (xsn ? name.substring(1) : name);
|
|
1288
1328
|
// TODO: really care about variant (qualifier parts)?
|
|
1289
1329
|
const variantIndex = absolute.indexOf('#') + 1 || absolute.length;
|
|
1290
|
-
const n = refSplit( absolute.substring( 0, variantIndex ),
|
|
1330
|
+
const n = refSplit( absolute.substring( 0, variantIndex ), !xsn && '{}' );
|
|
1291
1331
|
if (!n)
|
|
1292
1332
|
return undefined;
|
|
1293
1333
|
n.absolute = absolute;
|
|
@@ -1300,35 +1340,50 @@ function annotation( val, spec, xsn, csn, name ) {
|
|
|
1300
1340
|
|
|
1301
1341
|
// Expressions, conditions (std signature) -----------------------------------
|
|
1302
1342
|
|
|
1303
|
-
function value( val, spec, xsn ) { // for CSN property 'val'
|
|
1304
|
-
if (
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
return val;
|
|
1343
|
+
function value( val, spec, xsn, csn ) { // for CSN property 'val'
|
|
1344
|
+
if (val && typeof val === 'object') {
|
|
1345
|
+
error( 'syntax-expecting-scalar', location(true), { prop: spec.msgProp },
|
|
1346
|
+
'Expecting scalar values for property $(PROP)' );
|
|
1347
|
+
return ignore( val );
|
|
1308
1348
|
}
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1349
|
+
if (!xsn.literal) // might be overwritten; only set if literal type is valid
|
|
1350
|
+
xsn.literal = (val === null) ? 'null' : typeof val;
|
|
1351
|
+
|
|
1352
|
+
const valType = (val == null) ? val === null && 'null' : typeof val;
|
|
1353
|
+
const pattern = typeof csn.literal === 'string' && quotedLiteralPatterns[csn.literal];
|
|
1354
|
+
if (pattern && valType &&
|
|
1355
|
+
(valType === pattern.json_type || valType === pattern.secondary_json_type)) {
|
|
1356
|
+
if (pattern.test_fn && !pattern.test_fn( val )) {
|
|
1357
|
+
warning( 'syntax-invalid-literal', location(),
|
|
1358
|
+
{ '#': pattern.test_variant, prop: spec.msgProp } );
|
|
1359
|
+
}
|
|
1360
|
+
if (pattern.unexpected_char && pattern.unexpected_char.test( val ))
|
|
1361
|
+
warning( 'syntax-invalid-literal', location(), { '#': pattern.unexpected_variant } );
|
|
1362
|
+
}
|
|
1363
|
+
return val;
|
|
1312
1364
|
}
|
|
1313
1365
|
|
|
1314
1366
|
function literal( lit, spec, xsn, csn ) {
|
|
1315
|
-
|
|
1316
|
-
if (!string( lit ))
|
|
1367
|
+
if (!string( lit, spec ))
|
|
1317
1368
|
return undefined;
|
|
1318
|
-
const
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1369
|
+
const valType = (csn.val == null) ? csn.val === null && 'null' : typeof csn.val;
|
|
1370
|
+
const pattern = quotedLiteralPatterns[lit];
|
|
1371
|
+
if (!pattern) {
|
|
1372
|
+
error( 'syntax-invalid-string', location(true), { prop: spec.msgProp } );
|
|
1373
|
+
}
|
|
1374
|
+
else if (valType &&
|
|
1375
|
+
valType !== pattern.json_type && valType !== pattern.secondary_json_type) {
|
|
1376
|
+
warning( 'syntax-invalid-literal', location(), {
|
|
1377
|
+
// 'literal' value can be different to 'string' with JSON string type:
|
|
1378
|
+
'#': (valType === 'string') ? 'typeof' : 'expecting',
|
|
1379
|
+
otherprop: 'val',
|
|
1380
|
+
rawvalue: lit,
|
|
1381
|
+
op: valType,
|
|
1382
|
+
} );
|
|
1328
1383
|
}
|
|
1329
|
-
|
|
1384
|
+
else {
|
|
1330
1385
|
return lit;
|
|
1331
|
-
|
|
1386
|
+
}
|
|
1332
1387
|
return ignore( lit );
|
|
1333
1388
|
}
|
|
1334
1389
|
|
|
@@ -1430,6 +1485,7 @@ function expr( e, spec ) {
|
|
|
1430
1485
|
return object( e, spec );
|
|
1431
1486
|
}
|
|
1432
1487
|
|
|
1488
|
+
// with spec.msgVariant: 'or-string'
|
|
1433
1489
|
function exprOrString( val, spec ) {
|
|
1434
1490
|
return (typeof val === 'string' && !csnVersionZero)
|
|
1435
1491
|
? { val, literal: 'token', location: location() }
|
|
@@ -1555,8 +1611,8 @@ function translations( keyVal, spec, xsn, csn, textKey ) {
|
|
|
1555
1611
|
function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
|
|
1556
1612
|
const p0 = schema[prop] ? prop : prop.charAt(0);
|
|
1557
1613
|
const s = (parentSpec.schema || schema)[p0];
|
|
1558
|
-
if (!s || s.noPrefix
|
|
1559
|
-
if (!ourpropsRegex.test( prop ))
|
|
1614
|
+
if (!s || s.noPrefix === (prop !== p0) ) {
|
|
1615
|
+
if (prop && !ourpropsRegex.test( prop ))
|
|
1560
1616
|
return { prop, type: extra };
|
|
1561
1617
|
// TODO v4: No warning with --sloppy
|
|
1562
1618
|
warning( 'syntax-unknown-property', location(true), { prop },
|
|
@@ -1594,7 +1650,8 @@ function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
|
|
|
1594
1650
|
kind,
|
|
1595
1651
|
} );
|
|
1596
1652
|
}
|
|
1597
|
-
else if (checkAndSetXorGroup( s.xorGroup, s.xorException, prop, xor )
|
|
1653
|
+
else if (checkAndSetXorGroup( s.xorGroup, s.xorException, prop, xor ) &&
|
|
1654
|
+
checkAndSetXorGroup( s.xorGroupTwo, s.xorException, prop, xor ) ) {
|
|
1598
1655
|
onlyWith( s, s.onlyWith, csn, prop, xor, expected );
|
|
1599
1656
|
return s;
|
|
1600
1657
|
}
|
|
@@ -1697,26 +1754,22 @@ function isObject( obj, spec ) {
|
|
|
1697
1754
|
if (obj && typeof obj === 'object' && !Array.isArray( obj ))
|
|
1698
1755
|
return obj;
|
|
1699
1756
|
const loc = location(true);
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
else
|
|
1703
|
-
error( 'syntax-expecting-object', loc, { prop: spec.msgProp });
|
|
1757
|
+
error( 'syntax-expecting-object', loc,
|
|
1758
|
+
{ '#': spec.msgVariant || 'std', prop: spec.msgProp, op: '*' });
|
|
1704
1759
|
return ignore( obj );
|
|
1705
1760
|
}
|
|
1706
1761
|
|
|
1707
1762
|
function refSplit( name, prop ) {
|
|
1708
1763
|
const path = name.split('.');
|
|
1709
|
-
if (!path.every( id => id))
|
|
1710
|
-
|
|
1711
|
-
'Expecting correct name for property $(PROP)' );
|
|
1712
|
-
}
|
|
1764
|
+
if (prop && (prop === '{}' || prop === '#' ? !name : !path.every( id => id)))
|
|
1765
|
+
message( 'syntax-invalid-name', location(true), { '#': prop, prop } );
|
|
1713
1766
|
return { path: path.map( id => ({ id, location: location() }) ), location: location() };
|
|
1714
1767
|
}
|
|
1715
1768
|
|
|
1716
|
-
function replaceZeroValue( spec,
|
|
1769
|
+
function replaceZeroValue( spec, msgVariant, otherprop ) {
|
|
1717
1770
|
if (!csnVersionZero && !spec.vZeroFor) {
|
|
1718
1771
|
warning( 'syntax-deprecated-value', location(true),
|
|
1719
|
-
{ '#':
|
|
1772
|
+
{ '#': msgVariant, prop: spec.msgProp, otherprop } );
|
|
1720
1773
|
}
|
|
1721
1774
|
}
|
|
1722
1775
|
|