@sap/cds-compiler 6.4.2 → 6.4.6
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 +55 -5
- package/lib/base/message-registry.js +2 -2
- package/lib/checks/existsExpressionsOnlyForeignKeys.js +16 -10
- package/lib/checks/existsMustEndInAssoc.js +1 -1
- package/lib/checks/existsMustNotStartWithDollarSelf.js +31 -0
- package/lib/checks/validator.js +4 -2
- package/lib/compiler/assert-consistency.js +2 -2
- package/lib/compiler/builtins.js +5 -6
- package/lib/compiler/shared.js +127 -109
- package/lib/compiler/tweak-assocs.js +1 -1
- package/lib/compiler/xpr-rewrite.js +111 -139
- package/lib/gen/CdlGrammar.checksum +1 -1
- package/lib/gen/CdlParser.js +3 -2
- package/lib/parsers/AstBuildingParser.js +1 -1
- package/lib/transform/db/assocsToQueries/transformExists.js +3 -10
- package/lib/transform/db/assocsToQueries/utils.js +0 -5
- package/lib/transform/localized.js +13 -20
- package/package.json +3 -3
package/lib/compiler/shared.js
CHANGED
|
@@ -49,6 +49,13 @@ function fns( model ) {
|
|
|
49
49
|
dynamic: modelDefinitions,
|
|
50
50
|
notFound: undefinedDefinition,
|
|
51
51
|
},
|
|
52
|
+
// scope:'global': for cds.Association and auto-redirected targets
|
|
53
|
+
$global: {
|
|
54
|
+
isMainRef: 'all',
|
|
55
|
+
lexical: null,
|
|
56
|
+
dynamic: modelDefinitions,
|
|
57
|
+
notFound: undefinedDefinition,
|
|
58
|
+
},
|
|
52
59
|
// only used for the main annotate/extend statements, not inner ones:
|
|
53
60
|
annotate: {
|
|
54
61
|
isMainRef: 'all',
|
|
@@ -85,7 +92,7 @@ function fns( model ) {
|
|
|
85
92
|
accept: acceptEntity,
|
|
86
93
|
noDep: true,
|
|
87
94
|
// special `scope`s for auto-redirections:
|
|
88
|
-
global: () =>
|
|
95
|
+
global: () => '$global',
|
|
89
96
|
},
|
|
90
97
|
targetAspect: {
|
|
91
98
|
isMainRef: 'no-autoexposed',
|
|
@@ -102,6 +109,7 @@ function fns( model ) {
|
|
|
102
109
|
notFound: undefinedDefinition,
|
|
103
110
|
accept: acceptQuerySource,
|
|
104
111
|
noDep: '', // dependency special for from
|
|
112
|
+
args: () => 'from-args',
|
|
105
113
|
},
|
|
106
114
|
type: {
|
|
107
115
|
isMainRef: 'no-autoexposed',
|
|
@@ -112,11 +120,11 @@ function fns( model ) {
|
|
|
112
120
|
accept: acceptTypeOrElement,
|
|
113
121
|
// special `scope`s for CDL parser - TYPE OF (TODO generated?), cds.Association:
|
|
114
122
|
typeOf: typeOfSemantics,
|
|
115
|
-
global: () =>
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
123
|
+
global: () => '$global', // TODO: do we need `navigation: staticTarget`?
|
|
124
|
+
},
|
|
125
|
+
$typeOf: {
|
|
126
|
+
dynamic: typeOfParentDict,
|
|
127
|
+
navigation: staticTarget,
|
|
120
128
|
},
|
|
121
129
|
// element references without lexical scope (except $self/$projection): -----
|
|
122
130
|
targetElement: {
|
|
@@ -125,22 +133,24 @@ function fns( model ) {
|
|
|
125
133
|
dynamic: targetElements,
|
|
126
134
|
navigation: targetNavigation,
|
|
127
135
|
notFound: undefinedTargetElement,
|
|
128
|
-
param:
|
|
136
|
+
param: () => '$scopePar',
|
|
129
137
|
},
|
|
130
138
|
filter: {
|
|
131
139
|
lexical: justDollarAliases,
|
|
132
140
|
dollar: true,
|
|
133
141
|
dynamic: targetElements,
|
|
134
142
|
notFound: undefinedTargetElement,
|
|
135
|
-
param:
|
|
143
|
+
param: () => '$scopePar',
|
|
144
|
+
nestedColumn: () => 'filter',
|
|
136
145
|
},
|
|
137
|
-
'calc-filter': {
|
|
146
|
+
'calc-filter': { // TODO: what is so special about this?
|
|
138
147
|
lexical: justDollarAliases,
|
|
139
148
|
dollar: true,
|
|
140
149
|
dynamic: targetElements,
|
|
141
150
|
navigation: calcElemNavigation,
|
|
142
151
|
notFound: undefinedTargetElement,
|
|
143
152
|
param: paramUnsupported,
|
|
153
|
+
filter: () => 'calc-filter',
|
|
144
154
|
},
|
|
145
155
|
default: {
|
|
146
156
|
lexical: null,
|
|
@@ -154,7 +164,7 @@ function fns( model ) {
|
|
|
154
164
|
dollar: true,
|
|
155
165
|
dynamic: () => Object.create( null ),
|
|
156
166
|
notFound: undefinedVariable,
|
|
157
|
-
param:
|
|
167
|
+
param: () => '$scopePar',
|
|
158
168
|
},
|
|
159
169
|
'limit-offset': 'limit-rows',
|
|
160
170
|
// general element / variable references --------------------------------------
|
|
@@ -164,7 +174,7 @@ function fns( model ) {
|
|
|
164
174
|
dynamic: combinedSourcesOrParentElements,
|
|
165
175
|
notFound: undefinedSourceElement,
|
|
166
176
|
check: checkRefInQuery,
|
|
167
|
-
param:
|
|
177
|
+
param: () => '$scopePar',
|
|
168
178
|
},
|
|
169
179
|
having: 'where',
|
|
170
180
|
groupBy: 'where',
|
|
@@ -174,22 +184,15 @@ function fns( model ) {
|
|
|
174
184
|
dynamic: combinedSourcesOrParentElements,
|
|
175
185
|
notFound: undefinedSourceElement,
|
|
176
186
|
check: checkColumnRef,
|
|
177
|
-
param:
|
|
178
|
-
nestedColumn: () =>
|
|
179
|
-
lexical: justDollarAliases,
|
|
180
|
-
dollar: true,
|
|
181
|
-
dynamic: nestedElements,
|
|
182
|
-
notFound: undefinedNestedElement,
|
|
183
|
-
check: checkColumnRef,
|
|
184
|
-
param: paramSemantics,
|
|
185
|
-
}),
|
|
187
|
+
param: () => '$scopePar',
|
|
188
|
+
nestedColumn: () => '$srcRefInNestedColumn',
|
|
186
189
|
},
|
|
187
190
|
'from-args': {
|
|
188
191
|
lexical: null,
|
|
189
192
|
dollar: true,
|
|
190
193
|
dynamic: () => Object.create( null ),
|
|
191
194
|
notFound: undefinedVariable,
|
|
192
|
-
param:
|
|
195
|
+
param: () => '$scopePar',
|
|
193
196
|
},
|
|
194
197
|
calc: {
|
|
195
198
|
lexical: justDollarAliases,
|
|
@@ -198,6 +201,7 @@ function fns( model ) {
|
|
|
198
201
|
navigation: calcElemNavigation,
|
|
199
202
|
notFound: undefinedParentElement,
|
|
200
203
|
param: paramUnsupported,
|
|
204
|
+
filter: () => 'calc-filter',
|
|
201
205
|
},
|
|
202
206
|
'join-on': {
|
|
203
207
|
lexical: tableAliasesAndSelf,
|
|
@@ -205,7 +209,7 @@ function fns( model ) {
|
|
|
205
209
|
dynamic: combinedSourcesOrParentElements,
|
|
206
210
|
rejectRoot: rejectOwnExceptVisibleAliases,
|
|
207
211
|
notFound: undefinedSourceElement,
|
|
208
|
-
param:
|
|
212
|
+
param: () => '$scopePar',
|
|
209
213
|
},
|
|
210
214
|
on: { // unmanaged assoc: outside query, redirected or new assoc in column
|
|
211
215
|
lexical: justDollarAliases,
|
|
@@ -216,15 +220,8 @@ function fns( model ) {
|
|
|
216
220
|
accept: acceptElemOrVarOrSelf,
|
|
217
221
|
check: checkAssocOn,
|
|
218
222
|
param: paramUnsupported,
|
|
219
|
-
nestedColumn: () => ({ // in expand and inline
|
|
220
|
-
lexical: justDollarAliases,
|
|
221
|
-
dollar: true,
|
|
222
|
-
dynamic: parentElements,
|
|
223
|
-
navigation: assocOnNavigation,
|
|
224
|
-
notFound: undefinedParentElement,
|
|
225
|
-
rewriteProjectionToSelf: true,
|
|
226
|
-
}),
|
|
227
223
|
rewriteProjectionToSelf: true,
|
|
224
|
+
nestedColumn: () => '$projRefInNestedColumn',
|
|
228
225
|
},
|
|
229
226
|
'mixin-on': {
|
|
230
227
|
lexical: tableAliasesAndSelf,
|
|
@@ -234,7 +231,7 @@ function fns( model ) {
|
|
|
234
231
|
notFound: undefinedSourceElement,
|
|
235
232
|
accept: acceptElemOrVarOrSelf,
|
|
236
233
|
check: checkAssocOn,
|
|
237
|
-
param:
|
|
234
|
+
param: () => '$scopePar', // TODO: check that assocs containing param in ON is not published
|
|
238
235
|
},
|
|
239
236
|
'orderBy-ref': {
|
|
240
237
|
lexical: tableAliasesAndSelf,
|
|
@@ -242,7 +239,7 @@ function fns( model ) {
|
|
|
242
239
|
dynamic: parentElements,
|
|
243
240
|
notFound: undefinedOrderByElement,
|
|
244
241
|
check: checkOrderByRef,
|
|
245
|
-
param:
|
|
242
|
+
param: () => '$scopePar',
|
|
246
243
|
},
|
|
247
244
|
'orderBy-expr': {
|
|
248
245
|
lexical: tableAliasesAndSelf,
|
|
@@ -250,7 +247,7 @@ function fns( model ) {
|
|
|
250
247
|
dynamic: combinedSourcesOrParentElements,
|
|
251
248
|
notFound: undefinedSourceElement,
|
|
252
249
|
check: checkRefInQuery,
|
|
253
|
-
param:
|
|
250
|
+
param: () => '$scopePar',
|
|
254
251
|
},
|
|
255
252
|
'orderBy-set-ref': {
|
|
256
253
|
lexical: tableAliasesAndSelf, // TODO: reject own tab aliases
|
|
@@ -259,7 +256,7 @@ function fns( model ) {
|
|
|
259
256
|
rejectRoot: rejectOwnAliasesAndMixins,
|
|
260
257
|
notFound: undefinedParentElement,
|
|
261
258
|
check: checkOrderByRef,
|
|
262
|
-
param:
|
|
259
|
+
param: () => '$scopePar',
|
|
263
260
|
},
|
|
264
261
|
'orderBy-set-expr': {
|
|
265
262
|
lexical: tableAliasesAndSelf, // TODO: reject own tab aliases
|
|
@@ -268,7 +265,7 @@ function fns( model ) {
|
|
|
268
265
|
rejectRoot: rejectAllOwn,
|
|
269
266
|
notFound: undefinedVariable,
|
|
270
267
|
check: checkRefInQuery,
|
|
271
|
-
param:
|
|
268
|
+
param: () => '$scopePar',
|
|
272
269
|
},
|
|
273
270
|
annotation: { // annotation assignments
|
|
274
271
|
lexical: justDollarAliases,
|
|
@@ -277,19 +274,14 @@ function fns( model ) {
|
|
|
277
274
|
navigation: assocOnNavigation,
|
|
278
275
|
noDep: true,
|
|
279
276
|
notFound: undefinedParentElement,
|
|
277
|
+
accept: acceptElemOrAnyVar,
|
|
278
|
+
variableFilter: (dict => dict),
|
|
280
279
|
messageMap: {
|
|
281
280
|
'ref-undefined-element': 'anno-undefined-element',
|
|
282
281
|
'ref-undefined-param': 'anno-undefined-param',
|
|
283
282
|
},
|
|
284
|
-
param:
|
|
285
|
-
nestedColumn: () =>
|
|
286
|
-
lexical: justDollarAliases,
|
|
287
|
-
dollar: true,
|
|
288
|
-
dynamic: parentElements,
|
|
289
|
-
navigation: assocOnNavigation,
|
|
290
|
-
notFound: undefinedParentElement,
|
|
291
|
-
rewriteProjectionToSelf: true,
|
|
292
|
-
}),
|
|
283
|
+
param: () => '$annotationScopePar',
|
|
284
|
+
nestedColumn: () => '$projRefInNestedColumn',
|
|
293
285
|
},
|
|
294
286
|
// TODO: introduce some kind of inheritance
|
|
295
287
|
// used by xpr-rewrite.js to resolve rewritten path roots.
|
|
@@ -300,17 +292,36 @@ function fns( model ) {
|
|
|
300
292
|
navigation: assocOnNavigation,
|
|
301
293
|
noDep: true,
|
|
302
294
|
notFound: null, // no error, just falsy links
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
295
|
+
accept: acceptElemOrAnyVar,
|
|
296
|
+
param: () => '$scopePar',
|
|
297
|
+
nestedColumn: () => '$projRefInNestedColumn',
|
|
298
|
+
},
|
|
299
|
+
$scopePar: {
|
|
300
|
+
dynamic: artifactParams,
|
|
301
|
+
notFound: undefinedParam,
|
|
302
|
+
},
|
|
303
|
+
$annotationScopePar: {
|
|
304
|
+
messageMap: {
|
|
305
|
+
'ref-undefined-element': 'anno-undefined-element',
|
|
306
|
+
'ref-undefined-param': 'anno-undefined-param',
|
|
307
|
+
},
|
|
308
|
+
dynamic: artifactParams,
|
|
309
|
+
notFound: undefinedParam,
|
|
310
|
+
},
|
|
311
|
+
// for `nestedColumn`, these two will be merged with base semantics:
|
|
312
|
+
$projRefInNestedColumn: { // for assoc-`on` and annotations
|
|
313
|
+
lexical: justDollarAliases,
|
|
314
|
+
dynamic: parentElements,
|
|
315
|
+
navigation: assocOnNavigation, // like std `environment`, but no dependency
|
|
316
|
+
rewriteProjectionToSelf: true,
|
|
317
|
+
},
|
|
318
|
+
$srcRefInNestedColumn: { // for column refs
|
|
319
|
+
lexical: justDollarAliases,
|
|
320
|
+
dollar: true,
|
|
321
|
+
dynamic: nestedElements,
|
|
322
|
+
navigation: environment,
|
|
323
|
+
notFound: undefinedNestedElement,
|
|
312
324
|
},
|
|
313
|
-
//
|
|
314
325
|
};
|
|
315
326
|
|
|
316
327
|
Object.assign( model.$functions, {
|
|
@@ -389,16 +400,13 @@ function fns( model ) {
|
|
|
389
400
|
const exit = callback( step, exprCtx, user );
|
|
390
401
|
if (exit === traverseExpr.STOP)
|
|
391
402
|
return true;
|
|
392
|
-
if (step.where && exit !== traverseExpr.SKIP
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
: 'filter' ),
|
|
398
|
-
step, callback ) === traverseExpr.STOP)
|
|
399
|
-
return true;
|
|
403
|
+
if (step.where && exit !== traverseExpr.SKIP) {
|
|
404
|
+
const ctx = referenceSemantics[exprCtx].filter?.() || 'filter';
|
|
405
|
+
if (traverseExpr( step.where, ctx, step, callback ) === traverseExpr.STOP)
|
|
406
|
+
return true;
|
|
407
|
+
}
|
|
400
408
|
if (step.args) {
|
|
401
|
-
const ctx = (
|
|
409
|
+
const ctx = referenceSemantics[exprCtx].args?.() || exprCtx;
|
|
402
410
|
const args = Array.isArray( step.args ) ? step.args : Object.values( step.args );
|
|
403
411
|
// TODO: there should be no array `args` on path item
|
|
404
412
|
for (const arg of args) {
|
|
@@ -412,7 +420,7 @@ function fns( model ) {
|
|
|
412
420
|
// Special expression traversal function for `resolveExpr`. Let's see
|
|
413
421
|
// later whether we can use this version as the general one.
|
|
414
422
|
// If we continue to have separate ones, remove the STOP stuff – it is not
|
|
415
|
-
// needed for `resolveExpr
|
|
423
|
+
// needed for `resolveExpr`; SKIP is used, though.
|
|
416
424
|
|
|
417
425
|
function traverseTypedExpr( expr, exprCtx, user, type, callback ) {
|
|
418
426
|
if (!expr || typeof expr === 'string') // parse error or keywords in {xpr:...}
|
|
@@ -565,16 +573,13 @@ function fns( model ) {
|
|
|
565
573
|
const exit = callback( step, exprCtx, user, null );
|
|
566
574
|
if (exit === traverseExpr.STOP)
|
|
567
575
|
return true;
|
|
568
|
-
if (step.where && exit !== traverseExpr.SKIP
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
: 'filter' ),
|
|
574
|
-
step, null, callback ) === traverseExpr.STOP)
|
|
575
|
-
return true;
|
|
576
|
+
if (step.where && exit !== traverseExpr.SKIP) {
|
|
577
|
+
const ctx = referenceSemantics[exprCtx].filter?.() || 'filter';
|
|
578
|
+
if (traverseTypedExpr( step.where, ctx, step, null, callback ) === traverseExpr.STOP)
|
|
579
|
+
return true;
|
|
580
|
+
}
|
|
576
581
|
if (step.args) {
|
|
577
|
-
const ctx = (
|
|
582
|
+
const ctx = referenceSemantics[exprCtx].args?.() || exprCtx;
|
|
578
583
|
const args = Array.isArray( step.args ) ? step.args : Object.values( step.args );
|
|
579
584
|
// TODO: there should be no array `args` on path item
|
|
580
585
|
for (const arg of args) {
|
|
@@ -637,7 +642,6 @@ function fns( model ) {
|
|
|
637
642
|
|
|
638
643
|
const s = referenceSemantics[expected];
|
|
639
644
|
const semantics = (typeof s === 'string') ? referenceSemantics[s] : s;
|
|
640
|
-
semantics.name = expected;
|
|
641
645
|
|
|
642
646
|
const r = getPathRoot( ref, semantics, origUser );
|
|
643
647
|
const root = r && acceptPathRoot( r, ref, semantics, origUser );
|
|
@@ -778,19 +782,26 @@ function fns( model ) {
|
|
|
778
782
|
ruser = ruser._outer._outer;
|
|
779
783
|
}
|
|
780
784
|
|
|
781
|
-
// Handle expand/inline
|
|
785
|
+
// Handle expand/inline before `type of`, :param, global (internally for CDL):
|
|
782
786
|
if (user._columnParent && !semantics.isMainRef) { // in expand/inline
|
|
783
|
-
const
|
|
784
|
-
|
|
785
|
-
|
|
787
|
+
const func = semantics.nestedColumn;
|
|
788
|
+
if (!func)
|
|
789
|
+
throw new CompilerAssertion( 'Unexpected ref context in nested column' );
|
|
790
|
+
const ctx = func();
|
|
791
|
+
semantics = (typeof ctx === 'string')
|
|
792
|
+
? ({ ...semantics, ...referenceSemantics[ctx] })
|
|
793
|
+
: ctx;
|
|
786
794
|
}
|
|
787
795
|
if (typeof scope === 'string') { // typeOf, param, global
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
796
|
+
const func = semantics[scope] || scope === 'param' && paramUnsupported;
|
|
797
|
+
// 'param' is a user scope → useful default (error msg ref-unexpected-param)
|
|
798
|
+
// 'global' and 'typeOf' are internal scopes of the compiler → dump if not provided
|
|
799
|
+
if (!func)
|
|
800
|
+
throw new CompilerAssertion( `Unexpected scope ${ scope }, no handler defined in context` );
|
|
801
|
+
const ctx = func( ruser, path, location, semantics );
|
|
802
|
+
semantics = (typeof ctx === 'string') ? referenceSemantics[ctx] : ctx;
|
|
803
|
+
if (!semantics)
|
|
792
804
|
return setArtifactLink( head, null );
|
|
793
|
-
}
|
|
794
805
|
}
|
|
795
806
|
const valid = [];
|
|
796
807
|
|
|
@@ -825,7 +836,8 @@ function fns( model ) {
|
|
|
825
836
|
valid.push( dynamicDict );
|
|
826
837
|
}
|
|
827
838
|
else {
|
|
828
|
-
|
|
839
|
+
const filterFn = semantics.variableFilter || removeRestrictedVariables;
|
|
840
|
+
valid.push( filterFn( model.$magicVariables.elements ),
|
|
829
841
|
removeDollarNames( dynamicDict ) );
|
|
830
842
|
}
|
|
831
843
|
// TODO: streamline function arguments (probably: user, path, semantics )
|
|
@@ -1020,11 +1032,17 @@ function fns( model ) {
|
|
|
1020
1032
|
return art;
|
|
1021
1033
|
}
|
|
1022
1034
|
case 'builtin': {
|
|
1035
|
+
// TODO: use properties in builtins
|
|
1023
1036
|
if (art.name.id === '$at') {
|
|
1024
1037
|
message( 'ref-deprecated-variable', [ head.location, user ],
|
|
1025
1038
|
{ code: '$at', newcode: '$valid' },
|
|
1026
1039
|
'$(CODE) is deprecated; use $(NEWCODE) instead' );
|
|
1027
1040
|
}
|
|
1041
|
+
else if (art.$restricted && semantics.accept !== acceptElemOrAnyVar) {
|
|
1042
|
+
error( 'ref-unexpected-var', [ head.location, user ],
|
|
1043
|
+
{ '#': 'annotation', name: head.id } );
|
|
1044
|
+
return null; // no further error on `unknown` for $draft.unknown
|
|
1045
|
+
}
|
|
1028
1046
|
return art;
|
|
1029
1047
|
}
|
|
1030
1048
|
default:
|
|
@@ -1059,20 +1077,12 @@ function fns( model ) {
|
|
|
1059
1077
|
while (struct.kind === 'element')
|
|
1060
1078
|
struct = struct._parent;
|
|
1061
1079
|
if (struct === user._main && struct.kind !== 'annotation')
|
|
1062
|
-
return
|
|
1080
|
+
return '$typeOf';
|
|
1063
1081
|
error( 'type-unexpected-typeof', [ head.location, user ],
|
|
1064
1082
|
{ keyword: 'type of', '#': struct.kind } );
|
|
1065
1083
|
return false;
|
|
1066
1084
|
}
|
|
1067
1085
|
|
|
1068
|
-
function paramSemantics( _user, _path, _loction, semantics ) {
|
|
1069
|
-
return {
|
|
1070
|
-
messageMap: semantics.messageMap,
|
|
1071
|
-
dynamic: artifactParams,
|
|
1072
|
-
notFound: undefinedParam,
|
|
1073
|
-
};
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
1086
|
function paramUnsupported( user, _path, location ) {
|
|
1077
1087
|
error( 'ref-unexpected-scope', [ location, user ], // TODO: ref-unexpected-param
|
|
1078
1088
|
// why an extra text for calculated elements? or separate for all?
|
|
@@ -1430,8 +1440,7 @@ function fns( model ) {
|
|
|
1430
1440
|
while ((head = head?._parent) && head.kind === 'builtin')
|
|
1431
1441
|
id = `${ head.name.id }.${ id }`;
|
|
1432
1442
|
const msgId = (art.$uncheckedElements) ? 'ref-unknown-var' : 'ref-undefined-var';
|
|
1433
|
-
signalNotFound( msgId, [ item.location, user ],
|
|
1434
|
-
removeInvalidMagicVariables( valid, semantics ), { id }, semantics );
|
|
1443
|
+
signalNotFound( msgId, [ item.location, user ], valid, { id }, semantics );
|
|
1435
1444
|
}
|
|
1436
1445
|
else if (art.kind === 'aspect' && !art.name) { // anonymous target aspect - TODO: still?
|
|
1437
1446
|
signalNotFound( 'ref-undefined-element', [ item.location, user ], valid,
|
|
@@ -1513,16 +1522,17 @@ function fns( model ) {
|
|
|
1513
1522
|
: acceptElemOrVar( art, user, ref );
|
|
1514
1523
|
}
|
|
1515
1524
|
|
|
1516
|
-
function acceptElemOrVar( art, user, ref
|
|
1525
|
+
function acceptElemOrVar( art, user, ref ) {
|
|
1526
|
+
if (art.kind !== 'builtin' || !art.$restricted)
|
|
1527
|
+
return acceptElemOrAnyVar( art, user, ref );
|
|
1528
|
+
error( 'ref-unexpected-var', [ ref.location, user ],
|
|
1529
|
+
{ '#': 'annotation', name: pathName( ref.path ) } );
|
|
1530
|
+
return null;
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
function acceptElemOrAnyVar( art, user, ref ) {
|
|
1517
1534
|
const { path } = ref;
|
|
1518
1535
|
if (art.kind === 'builtin') {
|
|
1519
|
-
if (art.$onlyInExprCtx && !art.$onlyInExprCtx.includes(semantics.name)) {
|
|
1520
|
-
error( 'ref-unexpected-var', [ ref.location, user ], {
|
|
1521
|
-
'#': art.$onlyInExprCtx[0], name: pathName( path ),
|
|
1522
|
-
});
|
|
1523
|
-
return null;
|
|
1524
|
-
}
|
|
1525
|
-
|
|
1526
1536
|
if (user.expand || user.inline) {
|
|
1527
1537
|
const location = (user.expand || user.inline)[$location];
|
|
1528
1538
|
const code = (user.expand) ? '{ ‹expand› }' : '.{ ‹inline› }';
|
|
@@ -2035,7 +2045,8 @@ function fns( model ) {
|
|
|
2035
2045
|
const err = message( semantics?.messageMap?.[msgId] || msgId, location, textParams );
|
|
2036
2046
|
if (valid) {
|
|
2037
2047
|
const user = Array.isArray( location ) && location[1];
|
|
2038
|
-
|
|
2048
|
+
// TODO: see TODO missing param `viaCdl` in attachAndEmitValidNames:
|
|
2049
|
+
err.validNames = (user && definedViaCdl( user ));
|
|
2039
2050
|
valid.reverse();
|
|
2040
2051
|
attachAndEmitValidNames( err, ...valid );
|
|
2041
2052
|
}
|
|
@@ -2076,6 +2087,8 @@ function fns( model ) {
|
|
|
2076
2087
|
const valid = Object.assign( Object.create( null ), ...validDicts );
|
|
2077
2088
|
msg.validNames = Object.create( null );
|
|
2078
2089
|
for (const name of Object.keys( valid )) {
|
|
2090
|
+
if (!name)
|
|
2091
|
+
continue;
|
|
2079
2092
|
const art = valid[name];
|
|
2080
2093
|
// ignore internal types such as cds.Association, ignore names with dot for
|
|
2081
2094
|
// CDL references to main artifacts:
|
|
@@ -2100,14 +2113,19 @@ function fns( model ) {
|
|
|
2100
2113
|
}
|
|
2101
2114
|
}
|
|
2102
2115
|
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2116
|
+
/**
|
|
2117
|
+
* Filter out restricted variables from a dictionary of variables.
|
|
2118
|
+
* Variables with the `$restricted` property set to true are excluded.
|
|
2119
|
+
*
|
|
2120
|
+
* @param {object} variables - Dictionary of variable objects
|
|
2121
|
+
* @returns {object} New dictionary with restricted variables removed
|
|
2122
|
+
*/
|
|
2123
|
+
function removeRestrictedVariables( variables ) {
|
|
2124
|
+
// TODO: we could also do something with `deprecated`, $requiresBetaFlag, …
|
|
2107
2125
|
const valid = Object.create(null);
|
|
2108
2126
|
for (const name in variables) {
|
|
2109
2127
|
const variable = variables[name];
|
|
2110
|
-
if (!variable.$
|
|
2128
|
+
if (!variable.$restricted)
|
|
2111
2129
|
valid[name] = variable;
|
|
2112
2130
|
}
|
|
2113
2131
|
return valid;
|
|
@@ -457,7 +457,7 @@ function tweakAssocs( model ) {
|
|
|
457
457
|
return;
|
|
458
458
|
|
|
459
459
|
if (elem._parent?.kind === 'element') {
|
|
460
|
-
//
|
|
460
|
+
// unmanaged association as sub element not supported yet
|
|
461
461
|
// TODO: Only report once for multi-include chains, see
|
|
462
462
|
// Associations/SubElements/UnmanagedInSubElement.err.cds
|
|
463
463
|
error( 'type-unsupported-rewrite', [ elem.location, elem ], { '#': 'sub-element' } );
|