@sap/cds-compiler 3.0.0 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -9
- package/bin/cdsc.js +9 -16
- package/lib/api/main.js +92 -40
- package/lib/base/keywords.js +64 -1
- package/lib/base/message-registry.js +17 -1
- package/lib/base/messages.js +38 -28
- package/lib/base/optionProcessorHelper.js +53 -21
- package/lib/compiler/assert-consistency.js +1 -1
- package/lib/compiler/builtins.js +40 -1
- package/lib/compiler/define.js +4 -2
- package/lib/compiler/extend.js +4 -1
- package/lib/compiler/populate.js +3 -1
- package/lib/compiler/resolve.js +1 -4
- package/lib/compiler/shared.js +9 -0
- package/lib/compiler/utils.js +2 -2
- package/lib/edm/annotations/preprocessAnnotations.js +10 -11
- package/lib/edm/csn2edm.js +15 -14
- package/lib/edm/edm.js +13 -12
- package/lib/edm/edmPreprocessor.js +30 -33
- package/lib/edm/edmUtils.js +3 -39
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +3311 -3289
- package/lib/json/from-csn.js +17 -19
- package/lib/json/to-csn.js +3 -2
- package/lib/language/genericAntlrParser.js +42 -42
- package/lib/language/language.g4 +28 -17
- package/lib/model/csnRefs.js +1 -0
- package/lib/model/csnUtils.js +19 -8
- package/lib/model/revealInternalProperties.js +4 -1
- package/lib/optionProcessor.js +54 -38
- package/lib/render/toHdbcds.js +1 -1
- package/lib/render/toSql.js +7 -3
- package/lib/transform/forOdataNew.js +3 -3
- package/lib/transform/localized.js +15 -11
- package/lib/utils/file.js +28 -18
- package/package.json +2 -3
- package/share/messages/syntax-expected-integer.md +9 -8
package/lib/json/from-csn.js
CHANGED
|
@@ -88,6 +88,7 @@
|
|
|
88
88
|
*/
|
|
89
89
|
|
|
90
90
|
const { dictAdd } = require('../base/dictionaries');
|
|
91
|
+
const { quotedLiteralPatterns } = require('../compiler/builtins');
|
|
91
92
|
|
|
92
93
|
const $location = Symbol.for('cds.$location');
|
|
93
94
|
|
|
@@ -682,15 +683,6 @@ const topLevelSpec = {
|
|
|
682
683
|
schema,
|
|
683
684
|
};
|
|
684
685
|
|
|
685
|
-
const validLiteralsExtra = Object.assign( Object.create(null), {
|
|
686
|
-
// TODO: should we use quotedLiteralPatterns from genericAntlrParser?
|
|
687
|
-
number: 'string',
|
|
688
|
-
x: 'string',
|
|
689
|
-
time: 'string',
|
|
690
|
-
date: 'string',
|
|
691
|
-
timestamp: 'string',
|
|
692
|
-
} );
|
|
693
|
-
|
|
694
686
|
// Module variables, schema compilation, and functors ------------------------
|
|
695
687
|
|
|
696
688
|
/** @type {(id, location, textOrArguments, texts?) => void} */
|
|
@@ -1288,16 +1280,22 @@ function value( val, spec, xsn ) { // for CSN property 'val'
|
|
|
1288
1280
|
return ignore( val );
|
|
1289
1281
|
}
|
|
1290
1282
|
|
|
1291
|
-
function literal(
|
|
1283
|
+
function literal( lit, spec, xsn, csn ) {
|
|
1292
1284
|
// TODO: general: requires other property (here: 'val')
|
|
1293
1285
|
const type = (csn.val == null) ? 'null' : typeof csn.val;
|
|
1294
|
-
if (
|
|
1295
|
-
return
|
|
1296
|
-
if (typeof
|
|
1297
|
-
|
|
1286
|
+
if (lit === type) // also for 'object' which is an error for 'val'
|
|
1287
|
+
return lit;
|
|
1288
|
+
if (typeof lit === 'string' && quotedLiteralPatterns[lit]?.json_type === type) {
|
|
1289
|
+
const p = quotedLiteralPatterns[lit];
|
|
1290
|
+
if (p && (p.test_fn && !p.test_fn(csn.val) || p.test_re && !p.test_re.test(csn.val)))
|
|
1291
|
+
warning( 'syntax-invalid-literal', location(), { '#': p.test_variant } );
|
|
1292
|
+
return lit;
|
|
1293
|
+
}
|
|
1294
|
+
if (lit === 'number' && type === 'string') // special case, not a quoted literal in CDL
|
|
1295
|
+
return lit;
|
|
1298
1296
|
error( 'syntax-expected-valid', location(true), { prop: spec.msgProp },
|
|
1299
1297
|
'Expected valid string for property $(PROP)' );
|
|
1300
|
-
return ignore(
|
|
1298
|
+
return ignore( lit );
|
|
1301
1299
|
}
|
|
1302
1300
|
|
|
1303
1301
|
function func( val, spec, xsn ) {
|
|
@@ -1535,7 +1533,7 @@ function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
|
|
|
1535
1533
|
const zero = s.vZeroFor;
|
|
1536
1534
|
if (zero) { // (potential) CSN v0.1.0 property
|
|
1537
1535
|
const group = s.xorGroup;
|
|
1538
|
-
if (
|
|
1536
|
+
if (expected( zero, schema[zero] ) && !(group && xor[group])) {
|
|
1539
1537
|
replaceZeroProp( prop, zero );
|
|
1540
1538
|
if (group)
|
|
1541
1539
|
xor[group] = prop;
|
|
@@ -1555,7 +1553,7 @@ function getSpec( parentSpec, csn, prop, xor, expected, kind ) {
|
|
|
1555
1553
|
std: 'CSN property $(PROP) is not expected in $(OTHERPROP)',
|
|
1556
1554
|
top: 'CSN property $(PROP) is not expected top-level',
|
|
1557
1555
|
def: 'CSN property $(PROP) is not expected by a definition of kind $(KIND)',
|
|
1558
|
-
extend: 'CSN property $(PROP) is not expected by an extend in $(OTHERPROP)
|
|
1556
|
+
extend: 'CSN property $(PROP) is not expected by an extend in $(OTHERPROP)',
|
|
1559
1557
|
annotate: 'CSN property $(PROP) is not expected by an annotate in $(OTHERPROP)',
|
|
1560
1558
|
} );
|
|
1561
1559
|
// TODO: or still augment it? (but then also handle xorGroup)
|
|
@@ -1783,7 +1781,7 @@ function toXsn( csn, filename, options, messageFunctions ) {
|
|
|
1783
1781
|
}
|
|
1784
1782
|
|
|
1785
1783
|
|
|
1786
|
-
function augment( csn, filename = 'csn.json', options = {}, messageFunctions ) {
|
|
1784
|
+
function augment( csn, filename = 'csn.json', options = {}, messageFunctions = {} ) {
|
|
1787
1785
|
try {
|
|
1788
1786
|
return toXsn( csn, filename, options, messageFunctions );
|
|
1789
1787
|
}
|
|
@@ -1793,7 +1791,7 @@ function augment( csn, filename = 'csn.json', options = {}, messageFunctions ) {
|
|
|
1793
1791
|
}
|
|
1794
1792
|
}
|
|
1795
1793
|
|
|
1796
|
-
function parse( source, filename = 'csn.json', options = {}, messageFunctions ) {
|
|
1794
|
+
function parse( source, filename = 'csn.json', options = {}, messageFunctions = {} ) {
|
|
1797
1795
|
try {
|
|
1798
1796
|
return augment( JSON.parse(source), filename, options, messageFunctions );
|
|
1799
1797
|
}
|
package/lib/json/to-csn.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
const { locationString } = require('../base/messages');
|
|
15
15
|
const { isBetaEnabled, isDeprecatedEnabled } = require('../base/model');
|
|
16
|
+
const { pathName } = require('../compiler/utils');
|
|
16
17
|
|
|
17
18
|
const compilerVersion = require('../../package.json').version;
|
|
18
19
|
const creator = `CDS Compiler v${ compilerVersion }`;
|
|
@@ -1218,8 +1219,8 @@ function value( node ) {
|
|
|
1218
1219
|
if (node.$inferred && gensrcFlavor)
|
|
1219
1220
|
return undefined;
|
|
1220
1221
|
if (node.path) {
|
|
1221
|
-
const ref = node.path
|
|
1222
|
-
return extra( { '=': node.variant ? `${ ref }#${ node.variant.
|
|
1222
|
+
const ref = pathName( node.path );
|
|
1223
|
+
return extra( { '=': node.variant ? `${ ref }#${ pathName(node.variant.path) }` : ref }, node );
|
|
1223
1224
|
}
|
|
1224
1225
|
if (node.literal === 'enum')
|
|
1225
1226
|
return extra( { '#': node.sym.id }, node );
|
|
@@ -12,7 +12,8 @@ const { dictAdd, dictAddArray } = require('../base/dictionaries');
|
|
|
12
12
|
const locUtils = require('../base/location');
|
|
13
13
|
const { parseDocComment } = require('./docCommentParser');
|
|
14
14
|
const { parseMultiLineStringLiteral } = require('./multiLineStringParser');
|
|
15
|
-
const { functionsWithoutParens, specialFunctions } = require('../compiler/builtins');
|
|
15
|
+
const { functionsWithoutParens, specialFunctions, quotedLiteralPatterns } = require('../compiler/builtins');
|
|
16
|
+
const { pathName } = require("../compiler/utils");
|
|
16
17
|
|
|
17
18
|
const $location = Symbol.for('cds.$location');
|
|
18
19
|
|
|
@@ -62,6 +63,8 @@ Object.assign(GenericAntlrParser.prototype, {
|
|
|
62
63
|
info: function(...args) { return _message( this, 'info', ...args ); },
|
|
63
64
|
attachLocation,
|
|
64
65
|
assignAnnotation,
|
|
66
|
+
checkExtensionDict,
|
|
67
|
+
handleExtension,
|
|
65
68
|
startLocation,
|
|
66
69
|
tokenLocation,
|
|
67
70
|
valueWithTokenLocation,
|
|
@@ -113,40 +116,6 @@ Object.assign(GenericAntlrParser.prototype, {
|
|
|
113
116
|
parseMultiLineStringLiteral,
|
|
114
117
|
});
|
|
115
118
|
|
|
116
|
-
// Patterns for literal token tests and creation. The value is a map from the
|
|
117
|
-
// `prefix` argument of function `quotedliteral` to the following properties:
|
|
118
|
-
// - `test_msg`: error message which is issued if `test_fn` or `test_re` fail.
|
|
119
|
-
// - `test_fn`: function called with argument `value`, fails falsy return value
|
|
120
|
-
// - `test_re`: regular expression, fails if it does not match argument `value`
|
|
121
|
-
// - `unexpected_msg`: error message which is issued if `unexpected_char` matches
|
|
122
|
-
// - `unexpected_char`: regular expression matching an illegal character in `value`,
|
|
123
|
-
// the error location is only correct for a literal <prefix>'<value>'
|
|
124
|
-
// - `literal`: the value which is used instead of `prefix` in the AST
|
|
125
|
-
// TODO: we might do a range check (consider leap seconds, i.e. max value 60),
|
|
126
|
-
// but always allow Feb 29 (no leap year computation)
|
|
127
|
-
// TODO: make it a configurable error (syntax-invalid-literal)
|
|
128
|
-
// TODO: also use for CSN input
|
|
129
|
-
const quotedLiteralPatterns = {
|
|
130
|
-
x: {
|
|
131
|
-
test_variant: 'uneven-hex',
|
|
132
|
-
test_fn: (str => Number.isInteger(str.length / 2)),
|
|
133
|
-
unexpected_variant: 'invalid-hex',
|
|
134
|
-
unexpected_char: /[^0-9a-f]/i,
|
|
135
|
-
},
|
|
136
|
-
time: {
|
|
137
|
-
test_variant: 'time',
|
|
138
|
-
test_re: /^[0-9]{1,2}:[0-9]{1,2}(:[0-9]{1,2})?$/,
|
|
139
|
-
},
|
|
140
|
-
date: {
|
|
141
|
-
test_variant: 'date',
|
|
142
|
-
test_re: /^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}$/,
|
|
143
|
-
},
|
|
144
|
-
timestamp: {
|
|
145
|
-
test_variant: 'timestamp',
|
|
146
|
-
test_re: /^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}(:[0-9]{2}(\.[0-9]{1,7})?)?$/,
|
|
147
|
-
},
|
|
148
|
-
};
|
|
149
|
-
|
|
150
119
|
// Use the following function for language constructs which we (currently)
|
|
151
120
|
// just being able to parse, in able to run tests from HANA CDS. As soon as we
|
|
152
121
|
// create ASTs for the language construct and put it into a CSN, a
|
|
@@ -355,7 +324,8 @@ function assignAnnotation( art, anno, prefix = '', iHaveVariant ) {
|
|
|
355
324
|
const pathname = pathName( path );
|
|
356
325
|
let absolute = '';
|
|
357
326
|
if (name.variant) {
|
|
358
|
-
|
|
327
|
+
const variant = pathName( name.variant.path );
|
|
328
|
+
absolute = `${ prefix }${ pathname }#${ variant }`;
|
|
359
329
|
if (iHaveVariant) { // TODO: do we really care in the parser / core compiler?
|
|
360
330
|
this.error( 'anno-duplicate-variant', [ name.variant.location ],
|
|
361
331
|
{}, // TODO: params
|
|
@@ -382,7 +352,8 @@ function assignAnnotation( art, anno, prefix = '', iHaveVariant ) {
|
|
|
382
352
|
dictAddArray( art, prop, anno, (n, location, a) => {
|
|
383
353
|
this.error( 'syntax-duplicate-anno', [ location ], { anno: n },
|
|
384
354
|
'Duplicate assignment with $(ANNO)' );
|
|
385
|
-
a.$errorReported =
|
|
355
|
+
a.$errorReported = 'syntax-duplicate-anno';
|
|
356
|
+
// do not report again later as anno-duplicate-xyz
|
|
386
357
|
} );
|
|
387
358
|
}
|
|
388
359
|
if (!prefix) { // set deprecated $annnotations for cds-lsp
|
|
@@ -393,6 +364,36 @@ function assignAnnotation( art, anno, prefix = '', iHaveVariant ) {
|
|
|
393
364
|
}
|
|
394
365
|
}
|
|
395
366
|
|
|
367
|
+
function checkExtensionDict( dict ) {
|
|
368
|
+
for (const name in dict) {
|
|
369
|
+
const def = dict[name];
|
|
370
|
+
if (!def.$duplicates)
|
|
371
|
+
continue;
|
|
372
|
+
|
|
373
|
+
const numDefines = (def.kind === 'annotate')
|
|
374
|
+
? 0
|
|
375
|
+
: def.$duplicates.reduce( addOneForDefinition, addOneForDefinition( 0, def ) );
|
|
376
|
+
this.handleExtension( def, name, numDefines );
|
|
377
|
+
for (const dup of def.$duplicates)
|
|
378
|
+
this.handleExtension( dup, name, numDefines );
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function addOneForDefinition( count, ext ) {
|
|
383
|
+
return (ext.kind === 'extend') ? count : count + 1;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function handleExtension( ext, name, numDefines ) {
|
|
387
|
+
if (ext.kind === 'annotate')
|
|
388
|
+
this.warning( 'syntax-duplicate-annotate', [ ext.name.location ], { name } );
|
|
389
|
+
else if (ext.kind === 'extend')
|
|
390
|
+
this.error( 'syntax-duplicate-extend', [ ext.name.location ],
|
|
391
|
+
{ name, '#': (numDefines ? 'define' : 'extend') } );
|
|
392
|
+
else if (numDefines === 1)
|
|
393
|
+
ext.$errorReported = 'syntax-duplicate-extend'; // a definition, but not duplicate
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
|
|
396
397
|
/**
|
|
397
398
|
* Return start location of `token`, or the first token matched by the current
|
|
398
399
|
* rule if `token` is undefined
|
|
@@ -504,7 +505,7 @@ function surroundByParens( expr, open, close, asQuery = false ) {
|
|
|
504
505
|
}
|
|
505
506
|
|
|
506
507
|
function unaryOpForParens( query, val ) {
|
|
507
|
-
const parens = query
|
|
508
|
+
const parens = query?.$parens;
|
|
508
509
|
if (!parens)
|
|
509
510
|
return query;
|
|
510
511
|
const location = parens[parens.length - 1];
|
|
@@ -743,10 +744,6 @@ function quotedLiteral( token, literal ) {
|
|
|
743
744
|
}
|
|
744
745
|
}
|
|
745
746
|
|
|
746
|
-
function pathName( path, brokenName ) {
|
|
747
|
-
return (path && !path.broken) ? path.map( id => id.id ).join('.') : brokenName;
|
|
748
|
-
}
|
|
749
|
-
|
|
750
747
|
function pushIdent( path, ident, prefix ) {
|
|
751
748
|
if (!ident) {
|
|
752
749
|
path.broken = true;
|
|
@@ -981,6 +978,9 @@ function handleComposition( cardinality, isComposition ) {
|
|
|
981
978
|
}
|
|
982
979
|
|
|
983
980
|
function associationInSelectItem( art ) {
|
|
981
|
+
if (!art.value) // e.g. `expand` without value (for new structures)
|
|
982
|
+
return;
|
|
983
|
+
|
|
984
984
|
const isPath = art.value.path && art.value.path.length
|
|
985
985
|
const isIdentifier = isPath && art.value.path.length === 1;
|
|
986
986
|
if (isIdentifier) {
|
package/lib/language/language.g4
CHANGED
|
@@ -398,6 +398,7 @@ artifactDef[ outer, defOnly = false ] locals[ art = {} ] // cannot use `parent`
|
|
|
398
398
|
this.error( 'syntax-extend-context', $annotate,
|
|
399
399
|
{ code: 'ANNOTATE artifact', kind: defOnly },
|
|
400
400
|
'No $(CODE) within $(KIND) extensions' );
|
|
401
|
+
if (!$outer.extensions) $outer.extensions = [];
|
|
401
402
|
this.meltKeywordToIdentifier();
|
|
402
403
|
}
|
|
403
404
|
annotateArtifact[ $art, $outer ] // not kind-specific
|
|
@@ -793,6 +794,7 @@ extendArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
|
|
|
793
794
|
'{' { $art.elements = this.createDict(); }
|
|
794
795
|
elementDefOrExtend[ $art ]*
|
|
795
796
|
'}' { this.finalizeDictOrArray( $art.elements ); }
|
|
797
|
+
{ this.checkExtensionDict( $art.elements ); }
|
|
796
798
|
optionalSemi
|
|
797
799
|
|
|
|
798
800
|
requiredSemi
|
|
@@ -809,6 +811,7 @@ extendArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
|
|
|
809
811
|
'{' { $art.elements = this.createDict(); }
|
|
810
812
|
elementDefOrExtend[ $art ]*
|
|
811
813
|
'}' { this.finalizeDictOrArray( $art.elements ); }
|
|
814
|
+
{ this.checkExtensionDict( $art.elements ); }
|
|
812
815
|
optionalSemi
|
|
813
816
|
|
|
|
814
817
|
requiredSemi
|
|
@@ -834,17 +837,18 @@ extendArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
|
|
|
834
837
|
|
|
|
835
838
|
{ this.disallowElementExtension( $elemName, $outer, 'actions' ); }
|
|
836
839
|
ACTIONS '{' { $art.actions = this.createDict(); }
|
|
837
|
-
actionFunctionDef[ $art ]*
|
|
840
|
+
actionFunctionDef[ $art ]* // TODO: no EXTEND in actions? (ok, would just allow annos)
|
|
838
841
|
'}' { this.finalizeDictOrArray( $art.actions ); }
|
|
839
842
|
optionalSemi
|
|
840
843
|
|
|
|
841
844
|
ELEMENTS '{' { $art.elements = this.createDict(); }
|
|
842
845
|
elementDefOrExtend[ $art ]*
|
|
843
846
|
'}' { this.finalizeDictOrArray( $art.elements ); }
|
|
847
|
+
{ this.checkExtensionDict( $art.elements ); }
|
|
844
848
|
optionalSemi
|
|
845
849
|
|
|
|
846
850
|
ENUM '{' { $art.enum = this.createDict(); }
|
|
847
|
-
enumSymbolDef[ $art ]*
|
|
851
|
+
enumSymbolDef[ $art ]* // TODO: no EXTEND in enum? (ok, would just allow annos)
|
|
848
852
|
'}' { this.finalizeDictOrArray( $art.enum ); }
|
|
849
853
|
optionalSemi
|
|
850
854
|
)
|
|
@@ -862,6 +866,7 @@ extendWithOptElements[ art ]
|
|
|
862
866
|
'{' { $art.elements = this.createDict(); }
|
|
863
867
|
elementDefOrExtend[ $art ]*
|
|
864
868
|
'}' { this.finalizeDictOrArray( $art.elements ); }
|
|
869
|
+
{ this.checkExtensionDict( $art.elements ); }
|
|
865
870
|
optionalSemi
|
|
866
871
|
|
|
|
867
872
|
requiredSemi
|
|
@@ -873,6 +878,7 @@ extendWithOptElements[ art ]
|
|
|
873
878
|
'{' { $art.elements = this.createDict(); }
|
|
874
879
|
elementDefOrExtend[ $art ]*
|
|
875
880
|
'}' { this.finalizeDictOrArray( $art.elements ); }
|
|
881
|
+
{ this.checkExtensionDict( $art.elements ); }
|
|
876
882
|
optionalSemi
|
|
877
883
|
|
|
|
878
884
|
requiredSemi
|
|
@@ -892,11 +898,13 @@ annotateArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
|
|
|
892
898
|
'{' { $art.elements = this.createDict(); }
|
|
893
899
|
annotateElement[ $art ]*
|
|
894
900
|
'}' { this.finalizeDictOrArray( $art.elements ); }
|
|
901
|
+
{ this.checkExtensionDict( $art.elements ); }
|
|
895
902
|
(
|
|
896
903
|
ACTIONS
|
|
897
904
|
'{' { $art.actions = this.createDict(); }
|
|
898
905
|
annotateAction[ $art ]*
|
|
899
906
|
'}' { this.finalizeDictOrArray( $art.actions ); }
|
|
907
|
+
{ this.checkExtensionDict( $art.actions ); }
|
|
900
908
|
)?
|
|
901
909
|
optionalSemi
|
|
902
910
|
|
|
|
@@ -904,6 +912,7 @@ annotateArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
|
|
|
904
912
|
'{' { $art.actions = this.createDict(); }
|
|
905
913
|
annotateAction[ $art ]*
|
|
906
914
|
'}' { this.finalizeDictOrArray( $art.actions ); }
|
|
915
|
+
{ this.checkExtensionDict( $art.actions ); }
|
|
907
916
|
optionalSemi
|
|
908
917
|
|
|
|
909
918
|
'(' { $art.params = this.createDict(); }
|
|
@@ -912,11 +921,13 @@ annotateArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
|
|
|
912
921
|
annotateParam[ $art ]
|
|
913
922
|
)*
|
|
914
923
|
')' { this.finalizeDictOrArray( $art.params ); }
|
|
924
|
+
{ this.checkExtensionDict( $art.params ); }
|
|
915
925
|
(
|
|
916
926
|
RETURNS { $art['$'+'syntax'] = 'returns'; }
|
|
917
927
|
'{' { $art.elements = this.createDict(); }
|
|
918
928
|
annotateElement[ $art ]*
|
|
919
929
|
'}' { this.finalizeDictOrArray( $art.elements ); }
|
|
930
|
+
{ this.checkExtensionDict( $art.elements ); }
|
|
920
931
|
optionalSemi
|
|
921
932
|
|
|
|
922
933
|
requiredSemi
|
|
@@ -926,6 +937,7 @@ annotateArtifact[ art, outer ] locals[ name = {}, elemName = {} ]
|
|
|
926
937
|
'{' { $art.elements = this.createDict(); }
|
|
927
938
|
annotateElement[ $art ]*
|
|
928
939
|
'}' { this.finalizeDictOrArray( $art.elements ); }
|
|
940
|
+
{ this.checkExtensionDict( $art.elements ); }
|
|
929
941
|
optionalSemi
|
|
930
942
|
|
|
931
943
|
|
|
|
@@ -946,6 +958,7 @@ annotateElement[ outer ] locals[ art = {} ]
|
|
|
946
958
|
'{' { $art.elements = this.createDict(); }
|
|
947
959
|
annotateElement[ $art ]*
|
|
948
960
|
'}' { this.finalizeDictOrArray( $art.elements ); }
|
|
961
|
+
{ this.checkExtensionDict( $art.elements ); }
|
|
949
962
|
optionalSemi
|
|
950
963
|
|
|
|
951
964
|
requiredSemi
|
|
@@ -968,11 +981,13 @@ annotateAction [ outer ] locals [ art = {} ]
|
|
|
968
981
|
annotateParam[ $art ]
|
|
969
982
|
)*
|
|
970
983
|
')' { this.finalizeDictOrArray( $art.params ); }
|
|
984
|
+
{ this.checkExtensionDict( $art.params ); }
|
|
971
985
|
)?
|
|
972
986
|
(
|
|
973
987
|
RETURNS '{' { $art.elements = this.createDict(); }
|
|
974
988
|
annotateElement[ $art ]*
|
|
975
989
|
'}' { this.finalizeDictOrArray( $art.elements ); }
|
|
990
|
+
{ this.checkExtensionDict( $art.elements ); }
|
|
976
991
|
optionalSemi
|
|
977
992
|
|
|
|
978
993
|
requiredSemi
|
|
@@ -1831,7 +1846,7 @@ typeNamedArg[ art ] locals[ arg = '' ]
|
|
|
1831
1846
|
:
|
|
1832
1847
|
name=ident['paramname']
|
|
1833
1848
|
':'
|
|
1834
|
-
{ if (this.checkTypeFacet( $art, $name.id ))
|
|
1849
|
+
{ if ($name.id && this.checkTypeFacet( $art, $name.id ))
|
|
1835
1850
|
$arg = $name.id.id;
|
|
1836
1851
|
}
|
|
1837
1852
|
(
|
|
@@ -1868,10 +1883,10 @@ queryExpression returns[ query ] // QLSubqueryComplex, SubqueryComplex
|
|
|
1868
1883
|
| op=MINUS q=DISTINCT?
|
|
1869
1884
|
)
|
|
1870
1885
|
qt=queryTerm
|
|
1871
|
-
{ $query = this.leftAssocBinaryOp( $query, $op, $q, $qt.query );; $ctx.q = null; }
|
|
1886
|
+
{ if ($qt.query) $query = this.leftAssocBinaryOp( $query, $op, $q, $qt.query );; $ctx.q = null; }
|
|
1872
1887
|
)*
|
|
1873
|
-
( ob=orderByClause[ $query ] { $query = $ob.query; } ) ?
|
|
1874
|
-
( lc=limitClause[ $query ] { $query = $lc.query; } ) ?
|
|
1888
|
+
( ob=orderByClause[ $query ] { if ($ob.query) $query = $ob.query; } ) ?
|
|
1889
|
+
( lc=limitClause[ $query ] { if ($lc.query) $query = $lc.query; } ) ?
|
|
1875
1890
|
;
|
|
1876
1891
|
|
|
1877
1892
|
orderByClause[ inQuery ] returns [ query ]
|
|
@@ -2075,7 +2090,7 @@ tableExpression returns[ table ] // TableOrJoin
|
|
|
2075
2090
|
ON cond=condition { $table.on = $cond.cond; }
|
|
2076
2091
|
|
|
|
2077
2092
|
crj=CROSS jn=JOIN tt=tableTerm
|
|
2078
|
-
{ $table = this.leftAssocBinaryOp( $table, $jn, $crj, $tt.table, 'join' ); }
|
|
2093
|
+
{ if (!$table) { $table = {}; } $table = this.leftAssocBinaryOp( $table, $jn, $crj, $tt.table, 'join' ); }
|
|
2079
2094
|
)*
|
|
2080
2095
|
;
|
|
2081
2096
|
|
|
@@ -2257,9 +2272,11 @@ conditionTerm returns [ cond ]
|
|
|
2257
2272
|
|
|
|
2258
2273
|
{ $cond = { args: [ $expr.expr ] }; }
|
|
2259
2274
|
NOT predicate[ $cond, true ]
|
|
2275
|
+
{ if (!$cond.op) $cond = null; } // predicate failed to parse, avoid subseqential errors
|
|
2260
2276
|
|
|
|
2261
2277
|
{ $cond = { args: [ $expr.expr ] }; }
|
|
2262
2278
|
predicate[ $cond, false ]
|
|
2279
|
+
{ if (!$cond.op) $cond = null; } // predicate failed to parse, avoid subseqential errors
|
|
2263
2280
|
)? // optional: for conditions in parentheses
|
|
2264
2281
|
;
|
|
2265
2282
|
|
|
@@ -2687,10 +2704,7 @@ annoValueBase[ assignment ] locals [ seenEllipsis = false ]
|
|
|
2687
2704
|
flattenedValue[ assignment ] locals[ val = { name: {} } ]
|
|
2688
2705
|
:
|
|
2689
2706
|
at='@'? annotationPath[ $val.name, 'name', $at ]
|
|
2690
|
-
(
|
|
2691
|
-
'#' { this.meltKeywordToIdentifier(); }
|
|
2692
|
-
variant=ident['variant'] { $val.name.variant = $variant.id; }
|
|
2693
|
-
)?
|
|
2707
|
+
( annotationPathVariant[ $val.name ] )?
|
|
2694
2708
|
(
|
|
2695
2709
|
':' { this.meltKeywordToIdentifier(true); } // allow path as anno value start with reserved
|
|
2696
2710
|
annoValue[ $val ]
|
|
@@ -2739,10 +2753,7 @@ annoSubValue returns[ val = {} ]
|
|
|
2739
2753
|
{ Object.assign( $val, this.numberLiteral( $num, $plus||$min ) ); }
|
|
2740
2754
|
|
|
|
2741
2755
|
at='@'? annotationPath[ $val, 'ref', $at ]
|
|
2742
|
-
(
|
|
2743
|
-
'#' { this.meltKeywordToIdentifier(); }
|
|
2744
|
-
variant=ident['variant'] { $val.variant = $variant.id; }
|
|
2745
|
-
)?
|
|
2756
|
+
( annotationPathVariant[ $val ] )?
|
|
2746
2757
|
;
|
|
2747
2758
|
|
|
2748
2759
|
literalValue returns[ val ] locals[ tok ]
|
|
@@ -2800,12 +2811,12 @@ annotationPath[ art, category, headat = null ] locals[ _sync = 'nop' ]
|
|
|
2800
2811
|
)*
|
|
2801
2812
|
;
|
|
2802
2813
|
|
|
2803
|
-
annotationPathVariant[ art ]
|
|
2814
|
+
annotationPathVariant[ art ] locals[ variant = {} ]
|
|
2804
2815
|
@after { this.attachLocation($art); }
|
|
2805
2816
|
:
|
|
2806
2817
|
// TODO: warning for space after '#'
|
|
2807
2818
|
'#' { this.meltKeywordToIdentifier(); }
|
|
2808
|
-
variant
|
|
2819
|
+
simplePath[ $variant, 'variant' ] { $art.variant = $variant; }
|
|
2809
2820
|
;
|
|
2810
2821
|
|
|
2811
2822
|
// Identifier and non-reserved keywords --------------------------------------
|
package/lib/model/csnRefs.js
CHANGED
package/lib/model/csnUtils.js
CHANGED
|
@@ -1056,7 +1056,7 @@ function isValidMappingDialectCombi(sqlDialect, sqlMapping) {
|
|
|
1056
1056
|
*/
|
|
1057
1057
|
// eslint-disable-next-line no-unused-vars
|
|
1058
1058
|
function getElementDatabaseNameOf(elemName, sqlMapping, sqlDialect='plain') {
|
|
1059
|
-
isValidMappingDialectCombi(
|
|
1059
|
+
isValidMappingDialectCombi(sqlDialect, sqlMapping)
|
|
1060
1060
|
if (sqlMapping === 'hdbcds') {
|
|
1061
1061
|
return elemName;
|
|
1062
1062
|
}
|
|
@@ -1280,19 +1280,30 @@ function copyAnnotationsAndDoc(fromNode, toNode, overwrite = false) {
|
|
|
1280
1280
|
* @todo Does _not_ apply param/action/... annotations.
|
|
1281
1281
|
*
|
|
1282
1282
|
* @param {CSN.Model} csn
|
|
1283
|
-
* @param {{
|
|
1283
|
+
* @param {{notFound?: (name: string, index: number) => void, override?: boolean, filter?: (name: string) => boolean}} config
|
|
1284
|
+
* notFound: Function that is called if the referenced definition can't be found.
|
|
1285
|
+
* Second argument is index in `csn.extensions` array.
|
|
1286
|
+
* override: Whether to ignore existing annotations.
|
|
1287
|
+
* filter: Positive filter. If it returns true, annotations for the referenced artifact
|
|
1288
|
+
* will be applied.
|
|
1289
|
+
* @todo Improve to also apply element annotations
|
|
1284
1290
|
*/
|
|
1285
1291
|
function applyAnnotationsFromExtensions(csn, config) {
|
|
1286
1292
|
if (!csn.extensions)
|
|
1287
1293
|
return;
|
|
1288
1294
|
|
|
1289
1295
|
const filter = config.filter || ((_name) => true);
|
|
1290
|
-
for (
|
|
1296
|
+
for (let i = 0; i < csn.extensions.length; ++i) {
|
|
1297
|
+
const ext = csn.extensions[i];
|
|
1291
1298
|
const name = ext.annotate || ext.extend;
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1299
|
+
if (name && filter(name)) {
|
|
1300
|
+
const def = csn.definitions[name];
|
|
1301
|
+
if (def) {
|
|
1302
|
+
copyAnnotationsAndDoc(ext, def, config.override);
|
|
1303
|
+
applyAnnotationsToElements(ext, def);
|
|
1304
|
+
} else if (config.notFound) {
|
|
1305
|
+
config.notFound(name, i);
|
|
1306
|
+
}
|
|
1296
1307
|
}
|
|
1297
1308
|
}
|
|
1298
1309
|
|
|
@@ -1309,7 +1320,7 @@ function applyAnnotationsFromExtensions(csn, config) {
|
|
|
1309
1320
|
forEach(ext.elements, (key, sourceElem) => {
|
|
1310
1321
|
const targetElem = def.elements[key];
|
|
1311
1322
|
if (targetElem) {
|
|
1312
|
-
copyAnnotationsAndDoc(sourceElem, targetElem, config.
|
|
1323
|
+
copyAnnotationsAndDoc(sourceElem, targetElem, config.override);
|
|
1313
1324
|
applyAnnotationsToElements(sourceElem, targetElem);
|
|
1314
1325
|
}
|
|
1315
1326
|
});
|
|
@@ -131,7 +131,10 @@ function revealInternalProperties( model, nameOrPath ) {
|
|
|
131
131
|
|
|
132
132
|
path = path.split('/');
|
|
133
133
|
if (path.length === 1) {
|
|
134
|
-
|
|
134
|
+
const def = xsn.definitions?.[path[0]] || xsn.vocabularies?.[path[0]];
|
|
135
|
+
if (!def)
|
|
136
|
+
throw new Error(`reveal xsn: Unknown definition: “${path[0]}”`)
|
|
137
|
+
return reveal( def );
|
|
135
138
|
}
|
|
136
139
|
|
|
137
140
|
// with the code below, we might miss the right transformer function
|