@sap/cds-compiler 5.5.0 → 5.6.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 +17 -1
- package/bin/cdsse.js +3 -0
- package/lib/base/message-registry.js +2 -0
- package/lib/checks/cdsMap.js +27 -0
- package/lib/checks/validator.js +3 -1
- package/lib/compiler/builtins.js +2 -0
- package/lib/compiler/define.js +1 -0
- package/lib/edm/annotations/vocabularyDefinitions.js +6 -0
- package/lib/gen/BaseParser.js +115 -76
- package/lib/gen/CdlParser.js +1106 -1104
- package/lib/gen/Dictionary.json +185 -6
- package/lib/model/cloneCsn.js +1 -5
- package/lib/parsers/AstBuildingParser.js +94 -50
- package/lib/parsers/CdlGrammar.g4 +55 -29
- package/lib/transform/db/expansion.js +3 -0
- package/lib/transform/forOdata.js +1 -1
- package/lib/transform/odata/createForeignKeys.js +92 -9
- package/lib/utils/objectUtils.js +13 -0
- package/package.json +1 -1
package/lib/gen/Dictionary.json
CHANGED
|
@@ -1114,6 +1114,13 @@
|
|
|
1114
1114
|
],
|
|
1115
1115
|
"$experimental": true
|
|
1116
1116
|
},
|
|
1117
|
+
"Common.WebSocketChannel": {
|
|
1118
|
+
"Type": "Edm.String",
|
|
1119
|
+
"AppliesTo": [
|
|
1120
|
+
"EntityContainer"
|
|
1121
|
+
],
|
|
1122
|
+
"$experimental": true
|
|
1123
|
+
},
|
|
1117
1124
|
"Communication.Contact": {
|
|
1118
1125
|
"Type": "Communication.ContactType",
|
|
1119
1126
|
"AppliesTo": [
|
|
@@ -1463,6 +1470,61 @@
|
|
|
1463
1470
|
"EntitySet"
|
|
1464
1471
|
]
|
|
1465
1472
|
},
|
|
1473
|
+
"EntityRelationship.entityType": {
|
|
1474
|
+
"Type": "Edm.String",
|
|
1475
|
+
"AppliesTo": [
|
|
1476
|
+
"EntityType"
|
|
1477
|
+
],
|
|
1478
|
+
"$experimental": true
|
|
1479
|
+
},
|
|
1480
|
+
"EntityRelationship.propertyType": {
|
|
1481
|
+
"Type": "Edm.String",
|
|
1482
|
+
"AppliesTo": [
|
|
1483
|
+
"Property"
|
|
1484
|
+
],
|
|
1485
|
+
"$experimental": true
|
|
1486
|
+
},
|
|
1487
|
+
"EntityRelationship.entityIds": {
|
|
1488
|
+
"Type": "Collection(EntityRelationship.entityId)",
|
|
1489
|
+
"AppliesTo": [
|
|
1490
|
+
"EntityType"
|
|
1491
|
+
],
|
|
1492
|
+
"$experimental": true
|
|
1493
|
+
},
|
|
1494
|
+
"EntityRelationship.reference": {
|
|
1495
|
+
"Type": "EntityRelationship.singleReference",
|
|
1496
|
+
"AppliesTo": [
|
|
1497
|
+
"Property"
|
|
1498
|
+
]
|
|
1499
|
+
},
|
|
1500
|
+
"EntityRelationship.compositeReferences": {
|
|
1501
|
+
"Type": "Collection(EntityRelationship.compositeReference)",
|
|
1502
|
+
"AppliesTo": [
|
|
1503
|
+
"EntityType"
|
|
1504
|
+
],
|
|
1505
|
+
"$experimental": true
|
|
1506
|
+
},
|
|
1507
|
+
"EntityRelationship.temporalIds": {
|
|
1508
|
+
"Type": "Collection(EntityRelationship.temporalId)",
|
|
1509
|
+
"AppliesTo": [
|
|
1510
|
+
"EntityType"
|
|
1511
|
+
],
|
|
1512
|
+
"$experimental": true
|
|
1513
|
+
},
|
|
1514
|
+
"EntityRelationship.temporalReferences": {
|
|
1515
|
+
"Type": "Collection(EntityRelationship.temporalReference)",
|
|
1516
|
+
"AppliesTo": [
|
|
1517
|
+
"EntityType"
|
|
1518
|
+
],
|
|
1519
|
+
"$experimental": true
|
|
1520
|
+
},
|
|
1521
|
+
"EntityRelationship.referencesWithConstantIds": {
|
|
1522
|
+
"Type": "Collection(EntityRelationship.referencesWithConstantId)",
|
|
1523
|
+
"AppliesTo": [
|
|
1524
|
+
"EntityType"
|
|
1525
|
+
],
|
|
1526
|
+
"$experimental": true
|
|
1527
|
+
},
|
|
1466
1528
|
"Graph.traceId": {
|
|
1467
1529
|
"Type": "Edm.String",
|
|
1468
1530
|
"$experimental": true
|
|
@@ -1719,6 +1781,7 @@
|
|
|
1719
1781
|
"EntityType",
|
|
1720
1782
|
"Action",
|
|
1721
1783
|
"Function",
|
|
1784
|
+
"ActionImport",
|
|
1722
1785
|
"FunctionImport"
|
|
1723
1786
|
]
|
|
1724
1787
|
},
|
|
@@ -1783,7 +1846,8 @@
|
|
|
1783
1846
|
"Type": "Collection(UI.CriticalityLabelType)",
|
|
1784
1847
|
"AppliesTo": [
|
|
1785
1848
|
"Property",
|
|
1786
|
-
"EntityType"
|
|
1849
|
+
"EntityType",
|
|
1850
|
+
"TypeDefinition"
|
|
1787
1851
|
],
|
|
1788
1852
|
"$experimental": true
|
|
1789
1853
|
},
|
|
@@ -1823,6 +1887,16 @@
|
|
|
1823
1887
|
"EntityType"
|
|
1824
1888
|
]
|
|
1825
1889
|
},
|
|
1890
|
+
"UI.OperationParameterFacets": {
|
|
1891
|
+
"Type": "Collection(UI.ReferenceFacet)",
|
|
1892
|
+
"AppliesTo": [
|
|
1893
|
+
"Action",
|
|
1894
|
+
"Function",
|
|
1895
|
+
"ActionImport",
|
|
1896
|
+
"FunctionImport"
|
|
1897
|
+
],
|
|
1898
|
+
"$experimental": true
|
|
1899
|
+
},
|
|
1826
1900
|
"UI.SelectionPresentationVariant": {
|
|
1827
1901
|
"Type": "UI.SelectionPresentationVariantType",
|
|
1828
1902
|
"AppliesTo": [
|
|
@@ -1878,14 +1952,16 @@
|
|
|
1878
1952
|
"Type": "Core.Tag",
|
|
1879
1953
|
"AppliesTo": [
|
|
1880
1954
|
"Property",
|
|
1881
|
-
"Term"
|
|
1955
|
+
"Term",
|
|
1956
|
+
"TypeDefinition"
|
|
1882
1957
|
]
|
|
1883
1958
|
},
|
|
1884
1959
|
"UI.IsImage": {
|
|
1885
1960
|
"Type": "Core.Tag",
|
|
1886
1961
|
"AppliesTo": [
|
|
1887
1962
|
"Property",
|
|
1888
|
-
"EntityType"
|
|
1963
|
+
"EntityType",
|
|
1964
|
+
"TypeDefinition"
|
|
1889
1965
|
],
|
|
1890
1966
|
"$experimental": true
|
|
1891
1967
|
},
|
|
@@ -1894,7 +1970,8 @@
|
|
|
1894
1970
|
"AppliesTo": [
|
|
1895
1971
|
"Property",
|
|
1896
1972
|
"PropertyValue",
|
|
1897
|
-
"Parameter"
|
|
1973
|
+
"Parameter",
|
|
1974
|
+
"TypeDefinition"
|
|
1898
1975
|
]
|
|
1899
1976
|
},
|
|
1900
1977
|
"UI.Placeholder": {
|
|
@@ -2070,7 +2147,8 @@
|
|
|
2070
2147
|
"Type": "UI.RecommendationListType",
|
|
2071
2148
|
"AppliesTo": [
|
|
2072
2149
|
"Property",
|
|
2073
|
-
"Parameter"
|
|
2150
|
+
"Parameter",
|
|
2151
|
+
"TypeDefinition"
|
|
2074
2152
|
]
|
|
2075
2153
|
},
|
|
2076
2154
|
"UI.Recommendations": {
|
|
@@ -2089,7 +2167,8 @@
|
|
|
2089
2167
|
"UI.DoNotCheckScaleOfMeasuredQuantity": {
|
|
2090
2168
|
"Type": "Edm.Boolean",
|
|
2091
2169
|
"AppliesTo": [
|
|
2092
|
-
"Property"
|
|
2170
|
+
"Property",
|
|
2171
|
+
"TypeDefinition"
|
|
2093
2172
|
],
|
|
2094
2173
|
"$experimental": true
|
|
2095
2174
|
},
|
|
@@ -3301,6 +3380,7 @@
|
|
|
3301
3380
|
"Properties": {
|
|
3302
3381
|
"SourceProperties": "Collection(Edm.PropertyPath)",
|
|
3303
3382
|
"SourceEntities": "Collection(Edm.NavigationPropertyPath)",
|
|
3383
|
+
"SourceEvents": "Collection(Edm.String)",
|
|
3304
3384
|
"TargetProperties": "Collection(Edm.String)",
|
|
3305
3385
|
"TargetEntities": "Collection(Edm.NavigationPropertyPath)",
|
|
3306
3386
|
"EffectTypes": "Common.EffectType",
|
|
@@ -3777,6 +3857,105 @@
|
|
|
3777
3857
|
"DELETE"
|
|
3778
3858
|
]
|
|
3779
3859
|
},
|
|
3860
|
+
"EntityRelationship.singleReference": {
|
|
3861
|
+
"$kind": "ComplexType",
|
|
3862
|
+
"Properties": {
|
|
3863
|
+
"name": "Edm.String",
|
|
3864
|
+
"referencedEntityType": "EntityRelationship.entityTypeID",
|
|
3865
|
+
"referencedPropertyType": "EntityRelationship.propertyTypeID"
|
|
3866
|
+
}
|
|
3867
|
+
},
|
|
3868
|
+
"EntityRelationship.entityId": {
|
|
3869
|
+
"$kind": "ComplexType",
|
|
3870
|
+
"Properties": {
|
|
3871
|
+
"name": "Edm.String",
|
|
3872
|
+
"description": "Edm.String",
|
|
3873
|
+
"propertyTypes": "Collection(EntityRelationship.propertyTypeID)"
|
|
3874
|
+
}
|
|
3875
|
+
},
|
|
3876
|
+
"EntityRelationship.compositeReference": {
|
|
3877
|
+
"$kind": "ComplexType",
|
|
3878
|
+
"Properties": {
|
|
3879
|
+
"name": "Edm.String",
|
|
3880
|
+
"referencedEntityType": "EntityRelationship.entityTypeID",
|
|
3881
|
+
"referencedPropertyType": "Collection(EntityRelationship.referencedPropertyType)"
|
|
3882
|
+
}
|
|
3883
|
+
},
|
|
3884
|
+
"EntityRelationship.referencedPropertyType": {
|
|
3885
|
+
"$kind": "ComplexType",
|
|
3886
|
+
"Properties": {
|
|
3887
|
+
"referencedPropertyType": "EntityRelationship.propertyTypeID",
|
|
3888
|
+
"localPropertyName": "Edm.PropertyPath"
|
|
3889
|
+
}
|
|
3890
|
+
},
|
|
3891
|
+
"EntityRelationship.temporalId": {
|
|
3892
|
+
"$kind": "ComplexType",
|
|
3893
|
+
"Properties": {
|
|
3894
|
+
"name": "Edm.String",
|
|
3895
|
+
"description": "Edm.String",
|
|
3896
|
+
"propertyTypes": "Collection(EntityRelationship.propertyTypeID)",
|
|
3897
|
+
"temporalIntervalType": "EntityRelationship.temporalIntervalTypeEnum",
|
|
3898
|
+
"temporalType": "EntityRelationship.temporalTypeEnum",
|
|
3899
|
+
"temporalIntervalStartProperty": "Edm.PropertyPath",
|
|
3900
|
+
"temporalIntervalEndProperty": "Edm.PropertyPath"
|
|
3901
|
+
}
|
|
3902
|
+
},
|
|
3903
|
+
"EntityRelationship.temporalReference": {
|
|
3904
|
+
"$kind": "ComplexType",
|
|
3905
|
+
"Properties": {
|
|
3906
|
+
"name": "Edm.String",
|
|
3907
|
+
"referencedEntityType": "EntityRelationship.entityTypeID",
|
|
3908
|
+
"referencedPropertyType": "Collection(EntityRelationship.referencedPropertyType)",
|
|
3909
|
+
"category": "EntityRelationship.temporalCategoryEnum",
|
|
3910
|
+
"selectionDateProperty": "Edm.PropertyPath"
|
|
3911
|
+
}
|
|
3912
|
+
},
|
|
3913
|
+
"EntityRelationship.referenceWithConstantId": {
|
|
3914
|
+
"$kind": "ComplexType",
|
|
3915
|
+
"Properties": {
|
|
3916
|
+
"name": "Edm.String",
|
|
3917
|
+
"referencedEntityType": "EntityRelationship.entityTypeID",
|
|
3918
|
+
"referencedPropertyType": "Collection(EntityRelationship.referencedPropertyTypeWithConstantId)"
|
|
3919
|
+
}
|
|
3920
|
+
},
|
|
3921
|
+
"EntityRelationship.referencedPropertyTypeWithConstantId": {
|
|
3922
|
+
"$kind": "ComplexType",
|
|
3923
|
+
"Properties": {
|
|
3924
|
+
"referencedPropertyType": "EntityRelationship.propertyTypeID",
|
|
3925
|
+
"localPropertyName": "Edm.PropertyPath",
|
|
3926
|
+
"constantValue": "Edm.String"
|
|
3927
|
+
}
|
|
3928
|
+
},
|
|
3929
|
+
"EntityRelationship.temporalIntervalTypeEnum": {
|
|
3930
|
+
"$kind": "EnumType",
|
|
3931
|
+
"Members": [
|
|
3932
|
+
"CLOSED_CLOSED",
|
|
3933
|
+
"OPEN_OPEN",
|
|
3934
|
+
"OPEN_CLOSED",
|
|
3935
|
+
"CLOSED_OPEN"
|
|
3936
|
+
]
|
|
3937
|
+
},
|
|
3938
|
+
"EntityRelationship.temporalTypeEnum": {
|
|
3939
|
+
"$kind": "EnumType",
|
|
3940
|
+
"Members": [
|
|
3941
|
+
"DATE",
|
|
3942
|
+
"DATETIME"
|
|
3943
|
+
]
|
|
3944
|
+
},
|
|
3945
|
+
"EntityRelationship.temporalCategoryEnum": {
|
|
3946
|
+
"$kind": "EnumType",
|
|
3947
|
+
"Members": [
|
|
3948
|
+
"TEMPORAL_DATE"
|
|
3949
|
+
]
|
|
3950
|
+
},
|
|
3951
|
+
"EntityRelationship.propertyTypeID": {
|
|
3952
|
+
"$kind": "TypeDefinition",
|
|
3953
|
+
"UnderlyingType": "Edm.String"
|
|
3954
|
+
},
|
|
3955
|
+
"EntityRelationship.entityTypeID": {
|
|
3956
|
+
"$kind": "TypeDefinition",
|
|
3957
|
+
"UnderlyingType": "Edm.String"
|
|
3958
|
+
},
|
|
3780
3959
|
"Graph.DetailsType": {
|
|
3781
3960
|
"$kind": "ComplexType",
|
|
3782
3961
|
"Properties": {
|
package/lib/model/cloneCsn.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { csnPropertyOrder } = require('../json/to-csn');
|
|
4
4
|
const { ModelError } = require('../base/error');
|
|
5
|
-
const { setHidden } = require('../utils/objectUtils');
|
|
5
|
+
const { setHidden, hasNonEnumerable } = require('../utils/objectUtils');
|
|
6
6
|
const { isAnnotationExpression } = require('../base/builtins');
|
|
7
7
|
|
|
8
8
|
const csnDictionaries = {
|
|
@@ -110,10 +110,6 @@ function cloneCsn( csn, options, sort ) {
|
|
|
110
110
|
return r;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
function hasNonEnumerable( object, property ) {
|
|
114
|
-
return Object.prototype.hasOwnProperty.call( object, property ) &&
|
|
115
|
-
!Object.prototype.propertyIsEnumerable.call( object, property );
|
|
116
|
-
}
|
|
117
113
|
|
|
118
114
|
/**
|
|
119
115
|
* Deeply clone the given CSN dictionary and return it.
|
|
@@ -40,6 +40,8 @@ const PRECEDENCE_OF_IN_PREDICATE = 10;
|
|
|
40
40
|
const PRECEDENCE_OF_EQUAL = 10;
|
|
41
41
|
|
|
42
42
|
class AstBuildingParser extends BaseParser {
|
|
43
|
+
leanConditions = { afterBrace: true };
|
|
44
|
+
|
|
43
45
|
constructor( lexer, keywords, table, options, messageFunctions ) {
|
|
44
46
|
super( lexer, keywords, table ); // lexer has file
|
|
45
47
|
this.options = options;
|
|
@@ -71,11 +73,14 @@ class AstBuildingParser extends BaseParser {
|
|
|
71
73
|
}
|
|
72
74
|
|
|
73
75
|
expectingArray() {
|
|
76
|
+
const savedState = this.s;
|
|
77
|
+
this.s = this.errorState;
|
|
74
78
|
let array = this.expectingArray_();
|
|
79
|
+
this.s = savedState;
|
|
75
80
|
// compatibility: replace true+false by Boolean - TODO: delete
|
|
76
81
|
if (array.includes( 'true' ))
|
|
77
82
|
array = [ 'Boolean', ...array.filter( n => n !== 'true' && n !== 'false' ) ];
|
|
78
|
-
return array.map( antlrName )
|
|
83
|
+
return array.map( tok => this.antlrName( tok ) )
|
|
79
84
|
.sort( (a, b) => (tokenPrecedence(a) < tokenPrecedence(b) ? -1 : 1) );
|
|
80
85
|
}
|
|
81
86
|
|
|
@@ -83,7 +88,7 @@ class AstBuildingParser extends BaseParser {
|
|
|
83
88
|
const token = this.la();
|
|
84
89
|
const expecting = this.expectingArray();
|
|
85
90
|
const err = this.error( 'syntax-unexpected-token', token,
|
|
86
|
-
{ offending: antlrName( token ), expecting } );
|
|
91
|
+
{ offending: this.antlrName( token ), expecting } );
|
|
87
92
|
// No 'unwanted' variant, no 'syntax-missing-token'
|
|
88
93
|
err.expectedTokens = expecting;
|
|
89
94
|
}
|
|
@@ -209,6 +214,16 @@ class AstBuildingParser extends BaseParser {
|
|
|
209
214
|
return next !== '*' && next !== '{';
|
|
210
215
|
}
|
|
211
216
|
|
|
217
|
+
notAfterEntityArgOrFilter( mode ) {
|
|
218
|
+
if (mode !== 'M')
|
|
219
|
+
return true;
|
|
220
|
+
const { type } = this.lb();
|
|
221
|
+
if (type !== ')' && type !== ']')
|
|
222
|
+
return true;
|
|
223
|
+
const { followState } = this.stack.at( -1 );
|
|
224
|
+
return !this.table[followState][':'];
|
|
225
|
+
}
|
|
226
|
+
|
|
212
227
|
// <prec=10, postfix=once> + test that the next token is not `null`; TODO: code
|
|
213
228
|
// completion for `… default 3 not ~;` → currently just `null` but hey
|
|
214
229
|
isNegatedRelation( _test, prec ) {
|
|
@@ -250,6 +265,23 @@ class AstBuildingParser extends BaseParser {
|
|
|
250
265
|
return !this.dynamic_.inBlock;
|
|
251
266
|
}
|
|
252
267
|
|
|
268
|
+
/**
|
|
269
|
+
* Restrictions according to the expression of a select column.
|
|
270
|
+
* Currently only to restrict it to a single `Id` for published associations.
|
|
271
|
+
*/
|
|
272
|
+
columnExpr( mode, arg ) {
|
|
273
|
+
if (mode)
|
|
274
|
+
return this.columnExpr$;
|
|
275
|
+
// TODO: should we use (text of) syntax-unexpected-assoc somewhere ?
|
|
276
|
+
if (arg)
|
|
277
|
+
this.columnExpr$ = this.tokenIdx;
|
|
278
|
+
else if (this.columnExpr$ !== this.tokenIdx - 1 ||
|
|
279
|
+
this.lb().type !== 'Id' ||
|
|
280
|
+
[ 'true', 'false', 'null' ].includes( this.lb().keyword ) )
|
|
281
|
+
this.columnExpr$ = null;
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
|
|
253
285
|
/**
|
|
254
286
|
* Prepare element restrictions and check validility of final anno assignments.
|
|
255
287
|
*
|
|
@@ -318,17 +350,36 @@ class AstBuildingParser extends BaseParser {
|
|
|
318
350
|
return true;
|
|
319
351
|
}
|
|
320
352
|
|
|
321
|
-
|
|
322
|
-
this.
|
|
353
|
+
noRepeatedCardinality( mode ) {
|
|
354
|
+
if (this.tokens[this.tokenIdx - 2]?.type !== ']')
|
|
355
|
+
return true;
|
|
356
|
+
if (mode === 'M')
|
|
357
|
+
return false;
|
|
358
|
+
// currently just warning if same cardinality provided twice
|
|
359
|
+
const same = { one: '1', many: '*' }[this.la().keyword];
|
|
360
|
+
return this.tokens[this.tokenIdx - 3]?.text === same;
|
|
323
361
|
}
|
|
324
362
|
|
|
325
363
|
/**
|
|
326
364
|
* `;` between statements is optional only after a `}` (ex braces of structure
|
|
327
|
-
* values for annotations).
|
|
365
|
+
* values for annotations and foreign key specifications).
|
|
366
|
+
*
|
|
367
|
+
* Beware: mentioned in leanConditions, i.e. executed in predictions!
|
|
328
368
|
*/
|
|
329
369
|
afterBrace( test ) {
|
|
330
370
|
if (!test)
|
|
331
371
|
this.afterBrace$ = this.tokenIdx;
|
|
372
|
+
// TODO TOOL: the following test belongs to the BaseParser.js:
|
|
373
|
+
if (this.conditionTokenIdx === this.tokenIdx && // tested on same
|
|
374
|
+
this.conditionStackLength == null && // after error recover
|
|
375
|
+
test !== 'M')
|
|
376
|
+
return true;
|
|
377
|
+
// Strange optional `;` after PROJECTION ON source: the rule exit prediction
|
|
378
|
+
// for fromRefWithOptAlias etc now checks C(afterBrace):
|
|
379
|
+
if (test === 'E' && this.afterBrace$ > 0 &&
|
|
380
|
+
this.tokens[this.afterBrace$ - 1]?.keyword === 'projection' &&
|
|
381
|
+
this.tokens[this.afterBrace$].keyword === 'on')
|
|
382
|
+
return true;
|
|
332
383
|
return this.afterBrace$ === this.tokenIdx;
|
|
333
384
|
}
|
|
334
385
|
|
|
@@ -355,8 +406,11 @@ class AstBuildingParser extends BaseParser {
|
|
|
355
406
|
const { arrayAnno } = this.dynamic_;
|
|
356
407
|
if (!arrayAnno[0])
|
|
357
408
|
return false;
|
|
358
|
-
|
|
359
|
-
|
|
409
|
+
arrayAnno[0] = this.tokens[this.tokenIdx + 1]?.keyword;
|
|
410
|
+
}
|
|
411
|
+
else if (arg === 'bracket') {
|
|
412
|
+
// closing bracket not allowed if last `...` in array is with `up to
|
|
413
|
+
return typeof this.dynamic_.arrayAnno[0] !== 'string';
|
|
360
414
|
}
|
|
361
415
|
else { // orNotEmpty
|
|
362
416
|
return this.dynamic_.arrayAnno || this.lb().type !== '{';
|
|
@@ -788,16 +842,20 @@ class AstBuildingParser extends BaseParser {
|
|
|
788
842
|
}
|
|
789
843
|
}
|
|
790
844
|
|
|
845
|
+
// TODO: can we remove `;`/EOF from the expected-set for `annotate Foo with ⎀`?
|
|
791
846
|
checkWith( keyword ) {
|
|
792
847
|
if (this.lb() !== keyword)
|
|
793
848
|
return;
|
|
794
849
|
const tok = this.la();
|
|
795
|
-
|
|
796
|
-
|
|
850
|
+
const docTokenIndex = this.docCommentIndex &&
|
|
851
|
+
this.docComments[this.docCommentIndex - 1].location.tokenIndex;
|
|
852
|
+
if (docTokenIndex < tok.location.tokenIndex &&
|
|
853
|
+
docTokenIndex > this.lb().location.tokenIndex)
|
|
797
854
|
return;
|
|
798
|
-
|
|
855
|
+
// filter out what comes after current rule (no generic way necessary):
|
|
856
|
+
const expecting = this.expectingArray().filter( t => t !== '<EOF>' && t !== '\'}\'' );
|
|
799
857
|
const msg = this.warning( 'syntax-unexpected-semicolon', tok,
|
|
800
|
-
{ offending: antlrName( tok ), expecting, keyword: 'with' },
|
|
858
|
+
{ offending: this.antlrName( tok ), expecting, keyword: 'with' },
|
|
801
859
|
// eslint-disable-next-line @stylistic/js/max-len
|
|
802
860
|
'Unexpected $(OFFENDING), expecting $(EXPECTING) - ignored previous $(KEYWORD)' );
|
|
803
861
|
msg.expectedTokens = expecting;
|
|
@@ -832,7 +890,7 @@ class AstBuildingParser extends BaseParser {
|
|
|
832
890
|
// TODO: `literal` needed?
|
|
833
891
|
if (art.cardinality) {
|
|
834
892
|
this.reportDuplicateClause( 'cardinality', targetMax, art.cardinality.targetMax,
|
|
835
|
-
card.keyword
|
|
893
|
+
card.keyword );
|
|
836
894
|
}
|
|
837
895
|
else {
|
|
838
896
|
art.cardinality = { targetMax, location: targetMax.location };
|
|
@@ -840,15 +898,16 @@ class AstBuildingParser extends BaseParser {
|
|
|
840
898
|
return target;
|
|
841
899
|
}
|
|
842
900
|
|
|
901
|
+
// TODO: as condition
|
|
843
902
|
reportExpandInline( column, isInline ) {
|
|
844
|
-
|
|
903
|
+
// called before matching `{`
|
|
845
904
|
if (column.value && !column.value.path) {
|
|
846
|
-
const token = this.la();
|
|
847
905
|
// improve error location when using "inline" `.{…}` after ref (arguments and
|
|
848
906
|
// filters not covered, not worth the effort); after an expression where
|
|
849
907
|
// the last token is an identifier, not the `.` is wrong, but the `{`:
|
|
850
|
-
|
|
851
|
-
|
|
908
|
+
const token = (isInline && this.tokens[this.tokenIdx - 2].type !== 'Id')
|
|
909
|
+
? this.lb()
|
|
910
|
+
: this.la();
|
|
852
911
|
this.error( 'syntax-unexpected-nested-proj', token,
|
|
853
912
|
{ code: isInline ? '.{ ‹inline› }' : '{ ‹expand› }' },
|
|
854
913
|
'Unexpected $(CODE); nested projections can only be used after a reference' );
|
|
@@ -857,18 +916,9 @@ class AstBuildingParser extends BaseParser {
|
|
|
857
916
|
// - no errors for refs inside expand/inline, but for refs in sibling expr
|
|
858
917
|
// - think about: reference to these (sub) elements from other view
|
|
859
918
|
}
|
|
860
|
-
if (isInline && name) {
|
|
861
|
-
const alias = this.tokens[this.tokenIdx - 2];
|
|
862
|
-
const location = (isInline === true)
|
|
863
|
-
? alias.location
|
|
864
|
-
: this.combineLocation( isInline, alias );
|
|
865
|
-
this.error( 'syntax-unexpected-alias', location, { code: '.{ ‹inline› }' },
|
|
866
|
-
'Unexpected alias name before $(CODE)' );
|
|
867
|
-
// continuation semantics: ignore AS
|
|
868
|
-
}
|
|
869
919
|
}
|
|
870
920
|
|
|
871
|
-
reportDuplicateClause( prop, erroneous, chosen, code
|
|
921
|
+
reportDuplicateClause( prop, erroneous, chosen, code ) {
|
|
872
922
|
// probably easier for message linters not to use (?:) for the message id...?
|
|
873
923
|
const args = {
|
|
874
924
|
'#': prop,
|
|
@@ -880,11 +930,7 @@ class AstBuildingParser extends BaseParser {
|
|
|
880
930
|
// TODO v6: duplicate clause = error, independently whether it is the same
|
|
881
931
|
this.warning( 'syntax-duplicate-equal-clause', erroneous.location, args );
|
|
882
932
|
}
|
|
883
|
-
|
|
884
|
-
if (literalValIfNotEq)
|
|
885
|
-
args.code = chosen.val;
|
|
886
|
-
this.message( 'syntax-duplicate-clause', erroneous.location, args );
|
|
887
|
-
}
|
|
933
|
+
// TODO extra msg text 'syntax-duplicate-clause' for noRepeatedCardinality()
|
|
888
934
|
}
|
|
889
935
|
|
|
890
936
|
setTypeFacet( art, name, value ) {
|
|
@@ -1083,20 +1129,16 @@ class AstBuildingParser extends BaseParser {
|
|
|
1083
1129
|
};
|
|
1084
1130
|
}
|
|
1085
1131
|
|
|
1132
|
+
// TODO: as condition
|
|
1086
1133
|
associationInSelectItem( art ) {
|
|
1134
|
+
if (art.name)
|
|
1135
|
+
return;
|
|
1087
1136
|
this.classifyImplicitName( 'ItemAssoc', art.value );
|
|
1088
1137
|
const path = art.value?.path;
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
if (path.length === 1 && !name.args && !name.cardinality && !name.where) {
|
|
1093
|
-
art.name = name;
|
|
1094
|
-
delete art.value;
|
|
1095
|
-
return;
|
|
1096
|
-
}
|
|
1138
|
+
if (path?.length) {
|
|
1139
|
+
art.name = path.at( -1 ); // usually length 1, but make it also work during error recovery
|
|
1140
|
+
delete art.value;
|
|
1097
1141
|
}
|
|
1098
|
-
this.error( 'syntax-unexpected-assoc', this.la(), {},
|
|
1099
|
-
'Unexpected association definition in select item' );
|
|
1100
1142
|
}
|
|
1101
1143
|
|
|
1102
1144
|
// must be in action directly after having parsed '{', '(`, or a keyword before
|
|
@@ -1287,6 +1329,17 @@ class AstBuildingParser extends BaseParser {
|
|
|
1287
1329
|
parent, 'elements', kind, seg );
|
|
1288
1330
|
}
|
|
1289
1331
|
}
|
|
1332
|
+
|
|
1333
|
+
// For compatibility with ANTLR-based parser:
|
|
1334
|
+
antlrName( type ) {
|
|
1335
|
+
if (typeof type !== 'string') {
|
|
1336
|
+
type = (!type.parsedAs && this.keywords[type.keyword ?? ''] != null ||
|
|
1337
|
+
type.parsedAs === 'keyword') && type.keyword || type.type;
|
|
1338
|
+
}
|
|
1339
|
+
if (/^[A-Z]+/.test( type ))// eslint-disable-next-line no-nested-ternary
|
|
1340
|
+
return (type === 'Id') ? 'Identifier' : (type === 'EOF') ? '<EOF>' : type;
|
|
1341
|
+
return (/^[a-z]+/.test( type )) ? type.toUpperCase() : `'${ type }'`;
|
|
1342
|
+
}
|
|
1290
1343
|
}
|
|
1291
1344
|
|
|
1292
1345
|
function addOneForDefinition( count, ext ) {
|
|
@@ -1309,15 +1362,6 @@ function relevantDigits( val ) {
|
|
|
1309
1362
|
}
|
|
1310
1363
|
|
|
1311
1364
|
|
|
1312
|
-
// For compatibility with ANTLR-based parser:
|
|
1313
|
-
function antlrName( type ) {
|
|
1314
|
-
if (typeof type !== 'string')
|
|
1315
|
-
type = (!type.parsedAs || type.parsedAs === 'keyword') && type.keyword || type.type;
|
|
1316
|
-
if (/^[A-Z]+/.test( type ))// eslint-disable-next-line no-nested-ternary
|
|
1317
|
-
return (type === 'Id') ? 'Identifier' : (type === 'EOF') ? '<EOF>' : type;
|
|
1318
|
-
return (/^[a-z]+/.test( type )) ? type.toUpperCase() : `'${ type }'`;
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
1365
|
// Used for sorting in messages (TODO: make it part of messages.js?)
|
|
1322
1366
|
const token1sort = {
|
|
1323
1367
|
// 0: Identifier, Number, ...
|