@sap/cds-compiler 4.9.2 → 5.0.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 +74 -0
- package/bin/cds_remove_invalid_whitespace.js +2 -1
- package/bin/cdsc.js +15 -11
- package/bin/cdshi.js +1 -0
- package/doc/CHANGELOG_BETA.md +7 -0
- package/lib/api/main.js +7 -19
- package/lib/api/options.js +5 -11
- package/lib/api/trace.js +0 -1
- package/lib/base/builtins.js +1 -0
- package/lib/base/location.js +4 -1
- package/lib/base/message-registry.js +29 -29
- package/lib/base/messages.js +22 -26
- package/lib/base/model.js +0 -2
- package/lib/base/node-helpers.js +0 -1
- package/lib/checks/enricher.js +1 -5
- package/lib/checks/structuredAnnoExpressions.js +30 -0
- package/lib/checks/validator.js +8 -0
- package/lib/compiler/assert-consistency.js +4 -1
- package/lib/compiler/base.js +1 -1
- package/lib/compiler/builtins.js +18 -2
- package/lib/compiler/checks.js +2 -5
- package/lib/compiler/define.js +7 -7
- package/lib/compiler/extend.js +68 -33
- package/lib/compiler/generate.js +1 -1
- package/lib/compiler/index.js +23 -6
- package/lib/compiler/lsp-api.js +501 -2
- package/lib/compiler/populate.js +2 -2
- package/lib/compiler/propagator.js +1 -4
- package/lib/compiler/resolve.js +2 -15
- package/lib/compiler/shared.js +112 -31
- package/lib/compiler/tweak-assocs.js +2 -16
- package/lib/compiler/utils.js +2 -1
- package/lib/compiler/xsn-model.js +4 -0
- package/lib/edm/annotations/genericTranslation.js +95 -42
- package/lib/edm/csn2edm.js +16 -4
- package/lib/edm/edm.js +2 -3
- package/lib/edm/edmAnnoPreprocessor.js +1 -2
- package/lib/edm/edmPreprocessor.js +1 -7
- package/lib/gen/Dictionary.json +29 -2
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +2 -1
- package/lib/gen/languageParser.js +4995 -4817
- package/lib/json/csnVersion.js +1 -1
- package/lib/json/from-csn.js +4 -7
- package/lib/json/to-csn.js +23 -12
- package/lib/language/antlrParser.js +2 -2
- package/lib/language/errorStrategy.js +0 -1
- package/lib/language/genericAntlrParser.js +35 -12
- package/lib/language/multiLineStringParser.js +3 -2
- package/lib/language/textUtils.js +1 -0
- package/lib/main.d.ts +28 -9
- package/lib/main.js +7 -4
- package/lib/model/csnRefs.js +20 -4
- package/lib/model/csnUtils.js +0 -2
- package/lib/model/revealInternalProperties.js +1 -1
- package/lib/modelCompare/compare.js +1 -1
- package/lib/optionProcessor.js +28 -9
- package/lib/render/manageConstraints.js +1 -1
- package/lib/render/toCdl.js +36 -7
- package/lib/render/toSql.js +1 -0
- package/lib/render/utils/common.js +12 -9
- package/lib/render/utils/stringEscapes.js +1 -0
- package/lib/transform/db/applyTransformations.js +13 -8
- package/lib/transform/db/associations.js +62 -54
- package/lib/transform/db/constraints.js +23 -25
- package/lib/transform/db/expansion.js +1 -6
- package/lib/transform/db/flattening.js +89 -111
- package/lib/transform/db/temporal.js +3 -4
- package/lib/transform/db/views.js +0 -1
- package/lib/transform/draft/odata.js +51 -3
- package/lib/transform/effective/annotations.js +3 -2
- package/lib/transform/effective/flattening.js +135 -0
- package/lib/transform/effective/main.js +6 -6
- package/lib/transform/effective/types.js +13 -9
- package/lib/transform/forOdata.js +0 -2
- package/lib/transform/forRelationalDB.js +0 -19
- package/lib/transform/localized.js +7 -8
- package/lib/transform/odata/flattening.js +39 -31
- package/lib/transform/odata/typesExposure.js +5 -17
- package/lib/transform/transformUtils.js +1 -1
- package/lib/transform/translateAssocsToJoins.js +21 -3
- package/lib/utils/file.js +13 -7
- package/lib/utils/moduleResolve.js +59 -8
- package/lib/utils/term.js +3 -2
- package/package.json +7 -3
- package/share/messages/message-explanations.json +2 -0
- package/share/messages/type-unexpected-foreign-keys.md +52 -0
- package/share/messages/type-unexpected-on-condition.md +52 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { isEdmPropertyRendered, transformExpression } = require('../../model/csnUtils');
|
|
4
|
-
const { isBuiltinType } = require('../../base/builtins');
|
|
4
|
+
const { isBuiltinType, isMagicVariable } = require('../../base/builtins');
|
|
5
5
|
const edmUtils = require('../edmUtils.js');
|
|
6
6
|
const oDataDictionary = require('../../gen/Dictionary.json');
|
|
7
7
|
const preprocessAnnotations = require('./preprocessAnnotations.js');
|
|
@@ -60,6 +60,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
60
60
|
if (defName.startsWith(`${serviceName}.`))
|
|
61
61
|
assignParameterAnnotations(def);
|
|
62
62
|
});
|
|
63
|
+
|
|
63
64
|
// Crawl over the csn and trigger the annotation translation for all kinds
|
|
64
65
|
// of annotated things.
|
|
65
66
|
// Note: only works for single service
|
|
@@ -103,6 +104,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
103
104
|
const scopeCheck = {
|
|
104
105
|
ref: (elemref, prop, xpr, path) => {
|
|
105
106
|
if (scopeCheck.scope === 'param' &&
|
|
107
|
+
!isMagicVariable(xpr[0]) &&
|
|
106
108
|
(!elemref.param ||
|
|
107
109
|
(xpr[0].id || xpr[0]) === '$self' && !def.elements.$self)) {
|
|
108
110
|
error('odata-anno-xpr-ref', path, { anno: scopeCheck.anno, elemref, '#': 'notaparam' });
|
|
@@ -221,13 +223,16 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
221
223
|
|
|
222
224
|
function handleDefinition( defName, def, location ) {
|
|
223
225
|
// definition bound annotations
|
|
224
|
-
handleAnnotations(defName, def, location);
|
|
226
|
+
handleAnnotations(defName, def, { location });
|
|
225
227
|
// definition bound element annotations
|
|
226
228
|
if (def.$elementsAnnoProxies) {
|
|
227
229
|
Object.entries(def.$elementsAnnoProxies).forEach(([ elemPath, element ]) => {
|
|
228
230
|
const edmTargetName = `${defName}/${elemPath}`;
|
|
229
|
-
handleAnnotations(edmTargetName, element,
|
|
230
|
-
|
|
231
|
+
handleAnnotations(edmTargetName, element,
|
|
232
|
+
{
|
|
233
|
+
location: element.$path,
|
|
234
|
+
csnPath: [ ...location, '$elementsAnnoProxies', elemPath ],
|
|
235
|
+
});
|
|
231
236
|
});
|
|
232
237
|
}
|
|
233
238
|
// element bound annotations
|
|
@@ -235,7 +240,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
235
240
|
Object.entries(def.elements).forEach(([ elemName, element ]) => {
|
|
236
241
|
const edmTargetName = `${defName}/${elemName}`;
|
|
237
242
|
const eLocation = [ ...location, 'elements', elemName ];
|
|
238
|
-
handleAnnotations(edmTargetName, element, eLocation);
|
|
243
|
+
handleAnnotations(edmTargetName, element, { location: eLocation });
|
|
239
244
|
});
|
|
240
245
|
}
|
|
241
246
|
// bound actions
|
|
@@ -261,6 +266,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
261
266
|
const entityName = nameParts.pop();
|
|
262
267
|
|
|
263
268
|
Object.entries(cObject.actions).forEach(([ n, action ]) => {
|
|
269
|
+
setProp(action, '$isBound', true);
|
|
264
270
|
const actionName = `${serviceName}.${isV2() ? `${entityName}_` : ''}${n}`;
|
|
265
271
|
handleAction(actionName, action, cObjectname, [ ...location, 'actions', n ]);
|
|
266
272
|
});
|
|
@@ -273,6 +279,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
273
279
|
// entityNameIfBound : qualified name of entity if bound action/function
|
|
274
280
|
function handleAction( cActionName, cAction, entityNameIfBound, location ) {
|
|
275
281
|
let actionName = cActionName;
|
|
282
|
+
|
|
276
283
|
if (isV2()) { // Replace up to last dot with <serviceName>.EntityContainer
|
|
277
284
|
const lastDotIndex = actionName.lastIndexOf('.');
|
|
278
285
|
if (lastDotIndex > -1)
|
|
@@ -282,55 +289,70 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
282
289
|
actionName += relParList();
|
|
283
290
|
}
|
|
284
291
|
|
|
285
|
-
handleAnnotations(actionName, cAction, location);
|
|
292
|
+
handleAnnotations(actionName, cAction, { location, cAction });
|
|
286
293
|
|
|
287
294
|
if (cAction.params) {
|
|
288
295
|
if (cAction.$paramsAnnoProxies) {
|
|
289
296
|
Object.entries(cAction.$paramsAnnoProxies).forEach(([ paramPath, param ]) => {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
297
|
+
// skip explicit binding parameter in V2
|
|
298
|
+
if (!(options.isV2() && param.type === '$self' && paramPath === cAction.$bindingParam?.name)) {
|
|
299
|
+
const edmTargetName = `${actionName}/${paramPath}`;
|
|
300
|
+
handleAnnotations(edmTargetName, param,
|
|
301
|
+
{
|
|
302
|
+
location: param.$path,
|
|
303
|
+
csnPath: [ ...location, '$paramsAnnoProxies', paramPath ],
|
|
304
|
+
cAction,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
293
307
|
});
|
|
294
308
|
}
|
|
309
|
+
// explicit binding parameter is removed from params in V2 during
|
|
310
|
+
// createActionV2(), no need to check ;)
|
|
295
311
|
Object.entries(cAction.params).forEach(([ n, p ]) => {
|
|
296
312
|
const edmTargetName = `${actionName}/${n}`;
|
|
297
313
|
handleAnnotations(edmTargetName, p,
|
|
298
|
-
|
|
314
|
+
{
|
|
315
|
+
action: true,
|
|
316
|
+
location: [ ...location, 'params', n ],
|
|
317
|
+
cAction,
|
|
318
|
+
});
|
|
299
319
|
});
|
|
300
320
|
}
|
|
301
321
|
if (cAction.returns) {
|
|
302
322
|
if (cAction.$returnsAnnoProxies) {
|
|
303
323
|
Object.entries(cAction.$returnsAnnoProxies).forEach(([ returnsPath, returns ]) => {
|
|
304
324
|
const edmTargetName = `${actionName}/${returnsPath}`;
|
|
305
|
-
handleAnnotations(edmTargetName, returns,
|
|
306
|
-
|
|
325
|
+
handleAnnotations(edmTargetName, returns,
|
|
326
|
+
{
|
|
327
|
+
location: returns.$path,
|
|
328
|
+
csnPath: [ ...location, '$returnsAnnoProxies', returnsPath ],
|
|
329
|
+
cAction,
|
|
330
|
+
});
|
|
307
331
|
});
|
|
308
332
|
}
|
|
309
333
|
const edmTargetName = `${actionName}/$ReturnType`;
|
|
310
334
|
setProp(cAction.returns, '$appliesToReturnType', true);
|
|
311
335
|
handleAnnotations(edmTargetName, cAction.returns,
|
|
312
|
-
|
|
336
|
+
{
|
|
337
|
+
location: [ ...location, 'returns' ],
|
|
338
|
+
cAction,
|
|
339
|
+
});
|
|
313
340
|
delete cAction.returns.$appliesToReturnType;
|
|
314
341
|
}
|
|
315
342
|
|
|
316
343
|
function relParList() {
|
|
317
|
-
|
|
344
|
+
// we rely on the order of params in the csn being the correct one
|
|
318
345
|
const params = [];
|
|
319
346
|
if (entityNameIfBound) {
|
|
320
347
|
// If this is an action and has an explicit binding parameter add it here
|
|
321
|
-
if (cAction.$bindingParam && cAction.kind === 'action'
|
|
348
|
+
if (cAction.$bindingParam && cAction.kind === 'action' ||
|
|
349
|
+
cAction.$bindingParam?.viaAnno) {
|
|
322
350
|
params.push(
|
|
323
351
|
cAction.$bindingParam.items
|
|
324
352
|
? `Collection(${entityNameIfBound})`
|
|
325
353
|
: entityNameIfBound
|
|
326
354
|
);
|
|
327
355
|
}
|
|
328
|
-
// If action/function has no explicit binding parameter add it here
|
|
329
|
-
else if (!cAction.$bindingParam) {
|
|
330
|
-
params.push(cAction['@cds.odata.bindingparameter.collection']
|
|
331
|
-
? `Collection(${entityNameIfBound})`
|
|
332
|
-
: entityNameIfBound);
|
|
333
|
-
}
|
|
334
356
|
}
|
|
335
357
|
// In case this is a function the explicit binding parameter is part of
|
|
336
358
|
// the functions params dictionary. Only for functions all parameters must
|
|
@@ -348,12 +370,12 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
348
370
|
return edmUtils.mapCdsToEdmType(p, messageFunctions, false /* is only called for v4 */);
|
|
349
371
|
}
|
|
350
372
|
else if (options.whatsMySchemaName) {
|
|
351
|
-
const schemaName = options.whatsMySchemaName(p.type);
|
|
373
|
+
const schemaName = options.whatsMySchemaName(p._edmType || p.type);
|
|
352
374
|
// strip the service namespace of from a parameter type
|
|
353
375
|
if (schemaName && schemaName !== options.serviceName)
|
|
354
|
-
return p.type.replace(`${options.serviceName}.`, '');
|
|
376
|
+
return (p._edmType || p.type).replace(`${options.serviceName}.`, '');
|
|
355
377
|
}
|
|
356
|
-
return p.type;
|
|
378
|
+
return p._edmType || p.type;
|
|
357
379
|
}
|
|
358
380
|
}
|
|
359
381
|
}
|
|
@@ -363,7 +385,9 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
363
385
|
// edmTargetName : string, name of the target in edm
|
|
364
386
|
// carrier: object, the annotated cds thing, contains all the annotations
|
|
365
387
|
// as properties with names starting with @
|
|
366
|
-
|
|
388
|
+
// ctx: locations and other information that is required to write the
|
|
389
|
+
// annotations
|
|
390
|
+
function handleAnnotations( edmTargetName, carrier, ctx ) {
|
|
367
391
|
// collect the names of the carrier's annotation properties
|
|
368
392
|
// keep only those annotations that - start with a known vocabulary name
|
|
369
393
|
// - have a value other than null
|
|
@@ -377,6 +401,8 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
377
401
|
(isV2() && (edmUtils.isDerivedType(carrier))))
|
|
378
402
|
return;
|
|
379
403
|
|
|
404
|
+
if (ctx.location == null)
|
|
405
|
+
throw Error('location required');
|
|
380
406
|
|
|
381
407
|
// Filter unknown toplevel annotations
|
|
382
408
|
// Final filtering of all annotations is done in handleTerm
|
|
@@ -396,15 +422,15 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
396
422
|
transformExpression(carrier, knownAnno, {
|
|
397
423
|
ref: (elemref, prop, xpr, csnPath) => {
|
|
398
424
|
if (options.isV2() && elemref.$bparam) {
|
|
399
|
-
error('odata-anno-xpr-ref', location, {
|
|
400
|
-
elemref, anno: knownAnno, version: '2.0', '#': '
|
|
425
|
+
error('odata-anno-xpr-ref', ctx.location, {
|
|
426
|
+
elemref, anno: knownAnno, version: '2.0', '#': 'bparam_v2_expl',
|
|
401
427
|
});
|
|
402
428
|
return;
|
|
403
429
|
}
|
|
404
430
|
const { links, scope } = reqDefsUtils.inspectRef(csnPath);
|
|
405
431
|
let i = scope === '$self' ? 1 : 0;
|
|
406
432
|
if (scope === '$magic') {
|
|
407
|
-
error('odata-anno-xpr-ref', location, {
|
|
433
|
+
error('odata-anno-xpr-ref', ctx.location, {
|
|
408
434
|
elemref, anno: knownAnno, '#': 'magic',
|
|
409
435
|
});
|
|
410
436
|
return;
|
|
@@ -412,7 +438,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
412
438
|
let stop = false;
|
|
413
439
|
for (; i < links.length && !stop; i++) {
|
|
414
440
|
if (!isEdmPropertyRendered(links[i].art, csnPath)) {
|
|
415
|
-
error('odata-anno-xpr-ref', location, {
|
|
441
|
+
error('odata-anno-xpr-ref', ctx.location, {
|
|
416
442
|
count: i + 1, elemref, anno: knownAnno, '#': 'notrendered',
|
|
417
443
|
});
|
|
418
444
|
stop = true;
|
|
@@ -421,16 +447,27 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
421
447
|
const proxy = links[i].art?._target;
|
|
422
448
|
const eltName = links[i + 1].art?.name;
|
|
423
449
|
if (!proxy.elements[eltName]) {
|
|
424
|
-
error('odata-anno-xpr-ref', location, {
|
|
450
|
+
error('odata-anno-xpr-ref', ctx.location, {
|
|
425
451
|
count: i + 2, elemref, anno: knownAnno, '#': 'notrendered',
|
|
426
452
|
});
|
|
427
453
|
stop = true;
|
|
428
454
|
}
|
|
429
455
|
}
|
|
430
456
|
}
|
|
457
|
+
if (!stop && ctx.cAction?.$isBound && scope === '$self') {
|
|
458
|
+
if (options.isV2()) {
|
|
459
|
+
error('odata-anno-xpr-ref', ctx.location, {
|
|
460
|
+
elemref, anno: knownAnno, version: '2.0', '#': 'bparam_v2_impl',
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
xpr[0] = ctx.cAction.$bindingParam.name;
|
|
465
|
+
elemref.param = true;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
431
468
|
},
|
|
432
|
-
},
|
|
433
|
-
xpr2edmJson(carrier, knownAnno, location, options, messageFunctions);
|
|
469
|
+
}, ctx.csnPath || ctx.location);
|
|
470
|
+
xpr2edmJson(carrier, knownAnno, ctx.location, options, messageFunctions);
|
|
434
471
|
}
|
|
435
472
|
});
|
|
436
473
|
|
|
@@ -457,7 +494,7 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
457
494
|
const alternativeAnnotations = [];
|
|
458
495
|
|
|
459
496
|
// now create annotation objects for all the annotations of carrier
|
|
460
|
-
handleAnno2(addAnnotation, prefixTree, location);
|
|
497
|
+
handleAnno2(addAnnotation, prefixTree, ctx.location);
|
|
461
498
|
|
|
462
499
|
// Produce Edm.Annotations and attach collected Edm.Annotation(s) to the
|
|
463
500
|
// envelope (or directly to the Schema)
|
|
@@ -506,7 +543,6 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
506
543
|
}
|
|
507
544
|
|
|
508
545
|
function initCarrierControlVars() {
|
|
509
|
-
// eslint-disable-next-line no-unused-vars
|
|
510
546
|
let testToStandardEdmTargetP = () => true; // if true, assign to standard Edm Target
|
|
511
547
|
let stdEdmTargetNameP = edmTargetName;
|
|
512
548
|
let alternativeEdmTargetNameP = null;
|
|
@@ -516,13 +552,14 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
516
552
|
if (carrier.kind === 'entity') {
|
|
517
553
|
// If AppliesTo=[EntitySet/Singleton/Collection, EntityType], EntitySet/Singleton/Collection has precedence
|
|
518
554
|
testToAlternativeEdmTargetP = ((x) => {
|
|
519
|
-
if (
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
555
|
+
if (x) {
|
|
556
|
+
if (options.isV2())
|
|
557
|
+
return [ 'Singleton', 'EntitySet', 'Collection' ].some(y => x.includes(y));
|
|
558
|
+
return edmUtils.isSingleton(carrier)
|
|
559
|
+
? x.includes('Singleton')
|
|
560
|
+
: [ 'EntitySet', 'Collection' ].some(y => x.includes(y));
|
|
561
|
+
}
|
|
562
|
+
return true;
|
|
526
563
|
});
|
|
527
564
|
testToStandardEdmTargetP = (x => (x ? x.includes('EntityType') : true));
|
|
528
565
|
// if carrier has an alternate 'entitySetName' use this instead of EdmTargetName
|
|
@@ -540,6 +577,23 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
540
577
|
else if (carrier.kind === 'type') {
|
|
541
578
|
testToStandardEdmTargetP = (x => (x ? x.includes(carrier.elements ? 'ComplexType' : 'TypeDefinition') : true));
|
|
542
579
|
}
|
|
580
|
+
else if (carrier.kind === 'action' || carrier.kind === 'function') {
|
|
581
|
+
const type = carrier.kind === 'action' ? 'Action' : 'Function';
|
|
582
|
+
const container = carrier.kind === 'action' ? 'ActionImport' : 'FunctionImport';
|
|
583
|
+
if (options.isV4()) {
|
|
584
|
+
testToStandardEdmTargetP = (x => (x ? x.includes(type) : true));
|
|
585
|
+
// Unbound actions/functions are Action/FunctionImports and are bound to container target
|
|
586
|
+
testToAlternativeEdmTargetP = (x => (x ? x.includes(container) && !carrier.$isBound : true));
|
|
587
|
+
const lastDotIndex = carrier.name.lastIndexOf('.');
|
|
588
|
+
alternativeEdmTargetNameP = lastDotIndex > -1
|
|
589
|
+
? `${serviceName}.EntityContainer/${carrier.name.substring(lastDotIndex + 1)}`
|
|
590
|
+
: `${serviceName}.EntityContainer/${carrier.name}`;
|
|
591
|
+
hasAlternativeCarrierP = true;
|
|
592
|
+
}
|
|
593
|
+
if (options.isV2())
|
|
594
|
+
// same as in V4 but everything goes to standard target
|
|
595
|
+
testToStandardEdmTargetP = (x => (x ? x.includes(type) || (x.includes(container) && !carrier.$isBound) : true));
|
|
596
|
+
}
|
|
543
597
|
else if (carrier.kind === 'service') {
|
|
544
598
|
// if annotated object is a service, annotation goes to EntityContainer,
|
|
545
599
|
// except if AppliesTo contains Schema but not EntityContainer, then annotation goes to Schema
|
|
@@ -764,7 +818,6 @@ function csn2annotationEdm( reqDefs, reqDefsUtils, csnVocabularies, serviceName,
|
|
|
764
818
|
// addAnnotationFunc needs AppliesTo message from dictionary to decide where to put the anno
|
|
765
819
|
const termName = fullTermName.replace(/#(\w+)$/g, ''); // remove qualifier
|
|
766
820
|
const dictTerm = getDictTerm(termName, msg); // message for unknown term was already issued in handleTerm
|
|
767
|
-
// eslint-disable-next-line sonarjs/no-collapsible-if
|
|
768
821
|
if (!addAnnotationFunc(anno, dictTerm && dictTerm.AppliesTo)) {
|
|
769
822
|
if (dictTerm && dictTerm.AppliesTo) {
|
|
770
823
|
message('odata-anno-def', location,
|
package/lib/edm/csn2edm.js
CHANGED
|
@@ -732,11 +732,13 @@ function csn2edmAll( _csn, _options, serviceNames, messageFunctions ) {
|
|
|
732
732
|
if (type === special$self) {
|
|
733
733
|
bpName = entries[0][0];
|
|
734
734
|
setProp(actionCsn, '$bindingParam', firstParam);
|
|
735
|
+
// preserve the original type (as it is the key to reqDefs.defintions)
|
|
736
|
+
// for annotation path resolution (eg. for $draft.IsActiveEntity)
|
|
735
737
|
if (bpType) {
|
|
736
738
|
if (firstParam.items?.type)
|
|
737
|
-
firstParam.items
|
|
739
|
+
setProp(firstParam.items, '_edmType', bpType);
|
|
738
740
|
if (firstParam.type)
|
|
739
|
-
firstParam
|
|
741
|
+
setProp(firstParam, '_edmType', bpType);
|
|
740
742
|
}
|
|
741
743
|
if (!edmUtils.isODataSimpleIdentifier(bpName))
|
|
742
744
|
message('odata-spec-violation-id', [ ...location, 'params', bpName ], { id: bpName });
|
|
@@ -775,11 +777,20 @@ function csn2edmAll( _csn, _options, serviceNames, messageFunctions ) {
|
|
|
775
777
|
if (entityCsn) {
|
|
776
778
|
actionNode.setEdmAttribute('IsBound', true);
|
|
777
779
|
if (!actionCsn.$bindingParam) {
|
|
780
|
+
const bpDef = {
|
|
781
|
+
name: bpName,
|
|
782
|
+
viaAnno: true,
|
|
783
|
+
};
|
|
778
784
|
// Binding Parameter: 'in' at first position in sequence, this is decisive!
|
|
779
|
-
if (actionCsn['@cds.odata.bindingparameter.collection'])
|
|
785
|
+
if (actionCsn['@cds.odata.bindingparameter.collection']) {
|
|
780
786
|
actionNode.append(new Edm.Parameter(v, { Name: bpName, Type: bpType, Collection: true/* , Nullable: false */ } ));
|
|
781
|
-
|
|
787
|
+
bpDef.items = { type: bpType };
|
|
788
|
+
}
|
|
789
|
+
else {
|
|
782
790
|
actionNode.append(new Edm.Parameter(v, { Name: bpName, Type: bpType } ));
|
|
791
|
+
bpDef.type = bpType;
|
|
792
|
+
}
|
|
793
|
+
setProp(actionCsn, '$bindingParam', bpDef);
|
|
783
794
|
}
|
|
784
795
|
}
|
|
785
796
|
else if (EntityContainer) { // unbound => produce Action/FunctionImport
|
|
@@ -891,6 +902,7 @@ function csn2edmAll( _csn, _options, serviceNames, messageFunctions ) {
|
|
|
891
902
|
if (i === 0 && type === special$self) {
|
|
892
903
|
// skip and remove the first parameter if it is a $self binding parameter to
|
|
893
904
|
// omit annotation rendering later on
|
|
905
|
+
setProp(actionCsn, '$bindingParam', parameterCsn);
|
|
894
906
|
delete actionCsn.params[parameterName];
|
|
895
907
|
}
|
|
896
908
|
else {
|
package/lib/edm/edm.js
CHANGED
|
@@ -625,7 +625,8 @@ function getEdm( options, messageFunctions ) {
|
|
|
625
625
|
edmUtils.addTypeFacets(this, this._scalarType);
|
|
626
626
|
}
|
|
627
627
|
else {
|
|
628
|
-
|
|
628
|
+
// it's either _edmType or type (_edmType only used for explicit binding param)
|
|
629
|
+
this._edmAttributes[typeName] = typecsn._edmType || typecsn.type;
|
|
629
630
|
}
|
|
630
631
|
}
|
|
631
632
|
// CDXCORE-245:
|
|
@@ -897,7 +898,6 @@ function getEdm( options, messageFunctions ) {
|
|
|
897
898
|
super(version, attributes, csn);
|
|
898
899
|
// TIPHANACDS-4180
|
|
899
900
|
if (this.v2) {
|
|
900
|
-
// eslint-disable-next-line sonarjs/no-redundant-boolean
|
|
901
901
|
if (csn['@odata.etag'] || csn['@cds.etag'])
|
|
902
902
|
this._edmAttributes.ConcurrencyMode = 'Fixed';
|
|
903
903
|
|
|
@@ -1037,7 +1037,6 @@ function getEdm( options, messageFunctions ) {
|
|
|
1037
1037
|
See csn2edm.createEntityTypeAndSet() for details
|
|
1038
1038
|
2) ContainsTarget stems from the @odata.contained annotation
|
|
1039
1039
|
*/
|
|
1040
|
-
// eslint-disable-next-line sonarjs/no-redundant-boolean
|
|
1041
1040
|
if (csn['@odata.contained'] || csn.containsTarget)
|
|
1042
1041
|
this._edmAttributes.ContainsTarget = true;
|
|
1043
1042
|
|
|
@@ -59,7 +59,6 @@ function applyAppSpecificLateCsnTransformationOnElement( options, element, struc
|
|
|
59
59
|
// runtime cannot set that okra flag (alternatively the runtime has to search
|
|
60
60
|
// for @[odata|cds].etag annotations...
|
|
61
61
|
if (options.isV4() && (element['@odata.etag'] || element['@cds.etag'])) {
|
|
62
|
-
// eslint-disable-next-line sonarjs/no-redundant-boolean
|
|
63
62
|
// don't put element name into collection as per advice from Ralf Handl, as
|
|
64
63
|
// no runtime is interested in the property itself, it is sufficient to mark
|
|
65
64
|
// the entity set.
|
|
@@ -243,7 +242,7 @@ function setSAPSpecificV2AnnotationsToEntitySet( options, carrier ) {
|
|
|
243
242
|
'@sap.updatable.path': addToSetAttr,
|
|
244
243
|
'@sap.deletable.path': addToSetAttr,
|
|
245
244
|
'@sap.searchable': addToSetAttr,
|
|
246
|
-
'@sap.
|
|
245
|
+
'@sap.pageable': addToSetAttr,
|
|
247
246
|
'@sap.topable': addToSetAttr,
|
|
248
247
|
'@sap.countable': addToSetAttr,
|
|
249
248
|
'@sap.addressable': addToSetAttr,
|
|
@@ -100,7 +100,6 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
|
|
|
100
100
|
as a step in the OData transformer with the goal to have a protocol agnostic OData CSN.
|
|
101
101
|
*/
|
|
102
102
|
if (csn.meta && csn.meta.options && csn.meta.options.odataVersion === 'v4' && options.isV2()) {
|
|
103
|
-
// eslint-disable-next-line global-require
|
|
104
103
|
const { toFinalBaseType } = require('../transform/transformUtils').getTransformers(csn, options, messageFunctions);
|
|
105
104
|
expandCSNToFinalBaseType(csn, { toFinalBaseType }, csnUtils, serviceRootNames, options);
|
|
106
105
|
}
|
|
@@ -704,11 +703,6 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
|
|
|
704
703
|
validFrom.push(element);
|
|
705
704
|
|
|
706
705
|
// forward annotations from managed association element to its foreign keys
|
|
707
|
-
// TODO: Try to eliminate this code by rearranging
|
|
708
|
-
// forOdata::addCommonValueListviaAssociation(member, memberName)
|
|
709
|
-
// such that the VL annotations are distributed to the associations *before*
|
|
710
|
-
// FK creation.
|
|
711
|
-
// The FK creation already propagates the annotations from the association
|
|
712
706
|
const elements = construct.items?.elements || construct.elements;
|
|
713
707
|
const assoc = elements[element['@odata.foreignKey4']];
|
|
714
708
|
if (assoc) {
|
|
@@ -1915,7 +1909,7 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
|
|
|
1915
1909
|
function markCollection( obj ) {
|
|
1916
1910
|
const items = obj.items || csn.definitions[obj.type] && csn.definitions[obj.type].items;
|
|
1917
1911
|
if (items) {
|
|
1918
|
-
edmUtils.assignProp(obj, '_NotNullCollection', items.notNull !== undefined ? items.notNull :
|
|
1912
|
+
edmUtils.assignProp(obj, '_NotNullCollection', items.notNull !== undefined ? items.notNull : false);
|
|
1919
1913
|
edmUtils.assignProp(obj, '$isCollection', true);
|
|
1920
1914
|
}
|
|
1921
1915
|
}
|
package/lib/gen/Dictionary.json
CHANGED
|
@@ -1885,9 +1885,18 @@
|
|
|
1885
1885
|
"UI.Placeholder": {
|
|
1886
1886
|
"Type": "Edm.String",
|
|
1887
1887
|
"AppliesTo": [
|
|
1888
|
-
"Property"
|
|
1888
|
+
"Property",
|
|
1889
|
+
"Parameter"
|
|
1889
1890
|
]
|
|
1890
1891
|
},
|
|
1892
|
+
"UI.InputMask": {
|
|
1893
|
+
"Type": "UI.InputMaskType",
|
|
1894
|
+
"AppliesTo": [
|
|
1895
|
+
"Property",
|
|
1896
|
+
"Parameter"
|
|
1897
|
+
],
|
|
1898
|
+
"$experimental": true
|
|
1899
|
+
},
|
|
1891
1900
|
"UI.TextArrangement": {
|
|
1892
1901
|
"Type": "UI.TextArrangementType",
|
|
1893
1902
|
"AppliesTo": [
|
|
@@ -3823,7 +3832,8 @@
|
|
|
3823
3832
|
"ResultSizeDefault": "Edm.Int32",
|
|
3824
3833
|
"ResultSizeMaximum": "Edm.Int32",
|
|
3825
3834
|
"IANATimezoneFormat": "Edm.Boolean",
|
|
3826
|
-
"Treeview": "Edm.Boolean"
|
|
3835
|
+
"Treeview": "Edm.Boolean",
|
|
3836
|
+
"TextDirectionLayout": "Edm.Boolean"
|
|
3827
3837
|
}
|
|
3828
3838
|
},
|
|
3829
3839
|
"PersonalData.EntitySemanticsType": {
|
|
@@ -4274,6 +4284,23 @@
|
|
|
4274
4284
|
"High": "Edm.PrimitiveType"
|
|
4275
4285
|
}
|
|
4276
4286
|
},
|
|
4287
|
+
"UI.InputMaskType": {
|
|
4288
|
+
"$kind": "ComplexType",
|
|
4289
|
+
"Properties": {
|
|
4290
|
+
"Mask": "Edm.String",
|
|
4291
|
+
"PlaceholderSymbol": "Edm.String",
|
|
4292
|
+
"Rules": "Collection(UI.InputMaskRuleType)"
|
|
4293
|
+
},
|
|
4294
|
+
"$experimental": true
|
|
4295
|
+
},
|
|
4296
|
+
"UI.InputMaskRuleType": {
|
|
4297
|
+
"$kind": "ComplexType",
|
|
4298
|
+
"Properties": {
|
|
4299
|
+
"MaskSymbol": "Edm.String",
|
|
4300
|
+
"RegExp": "Edm.String"
|
|
4301
|
+
},
|
|
4302
|
+
"$experimental": true
|
|
4303
|
+
},
|
|
4277
4304
|
"UI.NoteType": {
|
|
4278
4305
|
"$kind": "ComplexType",
|
|
4279
4306
|
"Properties": {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
d2eab9ea0d46c406f6078d8a1125152e
|