@sap/cds-compiler 4.2.4 → 4.3.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 +26 -0
- package/bin/cdsc.js +8 -0
- package/bin/cdshi.js +3 -3
- package/doc/CHANGELOG_BETA.md +7 -0
- package/lib/api/main.js +19 -0
- package/lib/base/location.js +16 -0
- package/lib/base/message-registry.js +47 -16
- package/lib/base/messages.js +49 -38
- package/lib/base/model.js +1 -1
- package/lib/checks/checkPathsInStoredCalcElement.js +83 -0
- package/lib/checks/existsExpressionsOnlyForeignKeys.js +71 -0
- package/lib/checks/existsMustEndInAssoc.js +27 -0
- package/lib/checks/onConditions.js +47 -1
- package/lib/checks/validator.js +10 -1
- package/lib/compiler/assert-consistency.js +23 -15
- package/lib/compiler/base.js +31 -14
- package/lib/compiler/builtins.js +21 -20
- package/lib/compiler/checks.js +36 -49
- package/lib/compiler/define.js +71 -91
- package/lib/compiler/extend.js +27 -25
- package/lib/compiler/finalize-parse-cdl.js +1 -1
- package/lib/compiler/generate.js +67 -87
- package/lib/compiler/kick-start.js +7 -5
- package/lib/compiler/populate.js +32 -30
- package/lib/compiler/propagator.js +2 -0
- package/lib/compiler/resolve.js +29 -25
- package/lib/compiler/shared.js +57 -31
- package/lib/compiler/tweak-assocs.js +203 -22
- package/lib/compiler/utils.js +0 -18
- package/lib/gen/Dictionary.json +10 -4
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/languageParser.js +3 -3
- package/lib/inspect/inspectPropagation.js +2 -1
- package/lib/json/from-csn.js +63 -28
- package/lib/json/to-csn.js +23 -13
- package/lib/language/antlrParser.js +1 -1
- package/lib/language/errorStrategy.js +5 -1
- package/lib/language/genericAntlrParser.js +67 -61
- package/lib/main.d.ts +26 -1
- package/lib/main.js +2 -1
- package/lib/model/csnRefs.js +1 -0
- package/lib/model/csnUtils.js +28 -0
- package/lib/model/revealInternalProperties.js +3 -9
- package/lib/optionProcessor.js +17 -1
- package/lib/render/toCdl.js +1 -1
- package/lib/transform/db/associations.js +3 -4
- package/lib/transform/db/backlinks.js +293 -0
- package/lib/transform/db/expansion.js +9 -7
- package/lib/transform/db/flattening.js +3 -2
- package/lib/transform/db/rewriteCalculatedElements.js +1 -67
- package/lib/transform/db/transformExists.js +3 -58
- package/lib/transform/db/views.js +8 -14
- package/lib/transform/effective/.eslintrc.json +4 -0
- package/lib/transform/effective/associations.js +101 -0
- package/lib/transform/effective/main.js +88 -0
- package/lib/transform/effective/misc.js +61 -0
- package/lib/transform/effective/queries.js +42 -0
- package/lib/transform/effective/types.js +121 -0
- package/lib/transform/forRelationalDB.js +12 -235
- package/lib/transform/localized.js +22 -3
- package/lib/transform/parseExpr.js +7 -3
- package/lib/transform/transformUtils.js +5 -22
- package/lib/transform/translateAssocsToJoins.js +42 -38
- package/lib/transform/universalCsn/universalCsnEnricher.js +17 -1
- package/package.json +1 -2
- package/lib/language/language.g4 +0 -3260
package/lib/compiler/extend.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
5
|
-
const {
|
|
5
|
+
const { weakLocation } = require('../base/location');
|
|
6
|
+
const { searchName } = require('../base/messages');
|
|
6
7
|
const {
|
|
7
8
|
forEachInOrder,
|
|
8
9
|
forEachDefinition,
|
|
@@ -66,7 +67,7 @@ function extend( model ) {
|
|
|
66
67
|
// TMP:
|
|
67
68
|
function tagIncludes( art ) {
|
|
68
69
|
if (art.includes)
|
|
69
|
-
extensionsDict[art.name.
|
|
70
|
+
extensionsDict[art.name.id] = [];
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
//-----------------------------------------------------------------------------
|
|
@@ -86,10 +87,10 @@ function extend( model ) {
|
|
|
86
87
|
if (!art._main && !art._outer && art._extensions === undefined &&
|
|
87
88
|
art.name && // TODO: probably just a workaround, check with TODO in getOriginRaw()
|
|
88
89
|
art.kind !== 'namespace') {
|
|
89
|
-
const {
|
|
90
|
-
setLink( art, '_extensions', model.$collectedExtensions[
|
|
90
|
+
const { id } = art.name;
|
|
91
|
+
setLink( art, '_extensions', model.$collectedExtensions[id]?._extensions || null );
|
|
91
92
|
if (art._extensions && !art.builtin) { // keep extensions for builtin in $collectedExtensions
|
|
92
|
-
delete model.$collectedExtensions[
|
|
93
|
+
delete model.$collectedExtensions[id];
|
|
93
94
|
// TODO: if the extension mechanism has been completed, we could uncomment:
|
|
94
95
|
// art._extensions.forEach( ext => resolvePath( ext.name, ext.kind, ext )); // for LSP
|
|
95
96
|
// for now, we do that at the end of createRemainingAnnotateStatements()
|
|
@@ -182,8 +183,8 @@ function extend( model ) {
|
|
|
182
183
|
return;
|
|
183
184
|
for (const ext of source.extensions ) {
|
|
184
185
|
const { name } = ext;
|
|
185
|
-
if (name?.
|
|
186
|
-
const refCtx = (name.
|
|
186
|
+
if (name?.id && name._artifact === undefined) {
|
|
187
|
+
const refCtx = (name.id.startsWith( 'localized.' )) ? '_extensions' : ext.kind;
|
|
187
188
|
resolvePath( name, refCtx, ext ); // for LSP
|
|
188
189
|
}
|
|
189
190
|
}
|
|
@@ -361,10 +362,10 @@ function extend( model ) {
|
|
|
361
362
|
'You can\'t use EXTEND on the generated $(ART)' );
|
|
362
363
|
}
|
|
363
364
|
else if (art.kind !== 'annotate' && !art._outer) { // not with elem extension in targetAspect
|
|
364
|
-
const {
|
|
365
|
-
const dict = extensionsDict[
|
|
365
|
+
const { id } = art.name;
|
|
366
|
+
const dict = extensionsDict[id] || (extensionsDict[id] = []);
|
|
366
367
|
dict.push( ext ); // TODO: change
|
|
367
|
-
// console.log( 'ASI:',prop,art.name,ext,extensionsDict[
|
|
368
|
+
// console.log( 'ASI:',prop,art.name,ext,extensionsDict[id])
|
|
368
369
|
}
|
|
369
370
|
// art[prop] = (art[prop]) ? art[prop].concat( ext[prop] ) : ext[prop];
|
|
370
371
|
}
|
|
@@ -491,7 +492,8 @@ function extend( model ) {
|
|
|
491
492
|
|
|
492
493
|
function normalizeRef( node ) { // see to-csn.js
|
|
493
494
|
const ref = pathName( node.path );
|
|
494
|
-
|
|
495
|
+
// TODO: get rid of name.variant (induces a wrong structure anyway)
|
|
496
|
+
return node.variant ? `${ ref }#${ pathName( node.variant.path ) }` : ref;
|
|
495
497
|
}
|
|
496
498
|
|
|
497
499
|
// For extendArtifactAfter(): -------------------------------------------------
|
|
@@ -507,7 +509,7 @@ function extend( model ) {
|
|
|
507
509
|
// - 'ext-unexpected-type-argument' (TODO) if the artifact does not have the prop
|
|
508
510
|
// - 'ext-invalid-type-argument' if the value is wrong for extend (no overwrite)
|
|
509
511
|
//
|
|
510
|
-
// TODO
|
|
512
|
+
// TODO v5: do not allow `extend … with (precision: …)` alone if original def also has `scale`
|
|
511
513
|
function applyTypeExtensions( art, ext, prop, scaleDiff ) {
|
|
512
514
|
// console.log('ATE:',art?.[prop],ext?.[prop],scaleDiff)
|
|
513
515
|
if (!ext?.[prop])
|
|
@@ -652,9 +654,9 @@ function extend( model ) {
|
|
|
652
654
|
if (art._main)
|
|
653
655
|
return annotateFor( art._parent, kindProperties[art.kind].dict, art.name.id );
|
|
654
656
|
|
|
655
|
-
const {
|
|
656
|
-
return model.$collectedExtensions[
|
|
657
|
-
annotateCreate( model.$collectedExtensions,
|
|
657
|
+
const { id } = art.name;
|
|
658
|
+
return model.$collectedExtensions[id] ||
|
|
659
|
+
annotateCreate( model.$collectedExtensions, id );
|
|
658
660
|
}
|
|
659
661
|
|
|
660
662
|
function annotateCreate( dict, id, parent, prop ) {
|
|
@@ -668,9 +670,6 @@ function extend( model ) {
|
|
|
668
670
|
setLink( annotate, '_parent', parent );
|
|
669
671
|
setLink( annotate, '_main', parent._main || parent );
|
|
670
672
|
}
|
|
671
|
-
else {
|
|
672
|
-
annotate.name.absolute = id; // TODO later (if all names are sparse): delete absolute
|
|
673
|
-
}
|
|
674
673
|
dict[prop || id] = annotate;
|
|
675
674
|
return annotate;
|
|
676
675
|
}
|
|
@@ -774,9 +773,9 @@ function extend( model ) {
|
|
|
774
773
|
function createSuperAnnotate( annotate ) {
|
|
775
774
|
const extensions = annotate._extensions;
|
|
776
775
|
if (extensions && !annotate._main) {
|
|
777
|
-
const {
|
|
778
|
-
const isLocalized =
|
|
779
|
-
const art = model.definitions[
|
|
776
|
+
const { id } = annotate.name;
|
|
777
|
+
const isLocalized = id.startsWith( 'localized.' ); // TODO: && anno
|
|
778
|
+
const art = model.definitions[id];
|
|
780
779
|
for (const ext of extensions)
|
|
781
780
|
checkRemainingMainExtensions( art, ext, isLocalized );
|
|
782
781
|
if (art?.builtin && art.kind !== 'namespace') { // TODO: do not set `builtin` on cds, cds.hana
|
|
@@ -799,7 +798,7 @@ function extend( model ) {
|
|
|
799
798
|
}
|
|
800
799
|
|
|
801
800
|
function checkRemainingMainExtensions( art, ext, localized ) {
|
|
802
|
-
if (localized) // TODO
|
|
801
|
+
if (localized) // TODO v5: ignore only for annotate
|
|
803
802
|
return;
|
|
804
803
|
if (!resolvePath( ext.name, ext.kind, ext )) // error for extend, info for annotate
|
|
805
804
|
return;
|
|
@@ -1035,13 +1034,16 @@ function extend( model ) {
|
|
|
1035
1034
|
* @param {object} validDict
|
|
1036
1035
|
*/
|
|
1037
1036
|
function extendNothing( extensions, prop, name, art, validDict ) {
|
|
1037
|
+
// TODO: probably too much magic in the creation of artName…
|
|
1038
|
+
const extMain = { ...(art._main || art) };
|
|
1038
1039
|
const artName = searchName( art, name, dictKinds[prop] );
|
|
1040
|
+
setLink( artName, '_main', extMain );
|
|
1039
1041
|
for (const ext of extensions) {
|
|
1040
1042
|
// TODO: use shared functionality with notFound in resolver.js
|
|
1041
1043
|
const { location } = ext.name;
|
|
1042
|
-
|
|
1044
|
+
extMain.kind = ext.kind;
|
|
1043
1045
|
const msg
|
|
1044
|
-
= error( 'extend-undefined', [ location,
|
|
1046
|
+
= error( 'extend-undefined', [ location, artName ],
|
|
1045
1047
|
{ art: artName },
|
|
1046
1048
|
{
|
|
1047
1049
|
std: 'Unknown $(ART) - nothing to extend',
|
|
@@ -1210,7 +1212,7 @@ function extend( model ) {
|
|
|
1210
1212
|
* Report duplicates in parent[prop] that happen due to multiple includes having the
|
|
1211
1213
|
* same member. Covers `entity G : E, G {};` but not `entity G : E {}; extend G with F;`.
|
|
1212
1214
|
*
|
|
1213
|
-
* TODO(
|
|
1215
|
+
* TODO(v5): Make this a hard error; see checkRedefinition(); maybe combine both;
|
|
1214
1216
|
*/
|
|
1215
1217
|
function checkRedefinitionThroughIncludes( parent, prop ) {
|
|
1216
1218
|
if (!parent[prop])
|
|
@@ -40,7 +40,7 @@ function finalizeParseCdl( model ) {
|
|
|
40
40
|
// TODO: why not just use the extensions as they are from the first source?
|
|
41
41
|
for (const name in late) {
|
|
42
42
|
for (const ext of late[name]._extensions) {
|
|
43
|
-
ext.name.
|
|
43
|
+
ext.name.id = resolveUncheckedPath( ext.name, '_extensions', ext );
|
|
44
44
|
// Initialize members and define annotations in sub-elements.
|
|
45
45
|
initMembers( ext, ext, ext._block, true );
|
|
46
46
|
extensions.push( ext );
|
package/lib/compiler/generate.js
CHANGED
|
@@ -14,11 +14,10 @@ const {
|
|
|
14
14
|
linkToOrigin,
|
|
15
15
|
setMemberParent,
|
|
16
16
|
augmentPath,
|
|
17
|
-
splitIntoPath,
|
|
18
17
|
isDirectComposition,
|
|
19
18
|
copyExpr,
|
|
20
19
|
} = require('./utils');
|
|
21
|
-
const { weakLocation } = require('../base/
|
|
20
|
+
const { weakLocation } = require('../base/location');
|
|
22
21
|
|
|
23
22
|
function generate( model ) {
|
|
24
23
|
const { options } = model;
|
|
@@ -165,7 +164,7 @@ function generate( model ) {
|
|
|
165
164
|
const fioriAnno = art['@fiori.draft.enabled'];
|
|
166
165
|
const fioriEnabled = fioriAnno && (fioriAnno.val === undefined || fioriAnno.val);
|
|
167
166
|
|
|
168
|
-
const textsName = `${ art.name.
|
|
167
|
+
const textsName = `${ art.name.id }.texts`;
|
|
169
168
|
const textsEntity = model.definitions[textsName];
|
|
170
169
|
const localized = localizedData( art, textsEntity, fioriEnabled );
|
|
171
170
|
if (!localized)
|
|
@@ -278,20 +277,45 @@ function generate( model ) {
|
|
|
278
277
|
* @param {boolean} fioriEnabled
|
|
279
278
|
*/
|
|
280
279
|
function createTextsEntity( base, absolute, textElems, fioriEnabled ) {
|
|
281
|
-
const art = useTextsAspect
|
|
282
|
-
? createTextsEntityWithInclude( base, absolute, fioriEnabled )
|
|
283
|
-
: createTextsEntityWithDefaultElements( base, absolute, fioriEnabled );
|
|
284
|
-
// both functions are rather similar...
|
|
285
|
-
|
|
286
280
|
const { location } = base.name;
|
|
281
|
+
const art = {
|
|
282
|
+
kind: 'entity',
|
|
283
|
+
name: { id: absolute, location },
|
|
284
|
+
location: base.location,
|
|
285
|
+
elements: Object.create( null ),
|
|
286
|
+
$inferred: 'localized-entity',
|
|
287
|
+
};
|
|
288
|
+
setLink( art, '_block', model.$internal );
|
|
289
|
+
model.definitions[absolute] = art;
|
|
290
|
+
extendArtifactBefore( art ); // having extensions here would be wrong
|
|
291
|
+
|
|
292
|
+
if (!fioriEnabled) {
|
|
293
|
+
// To be compatible, we switch off draft without @fiori.draft.enabled
|
|
294
|
+
setAnnotation( art, '@odata.draft.enabled', art.location, false );
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
const textId = {
|
|
298
|
+
name: { location, id: 'ID_texts' },
|
|
299
|
+
kind: 'element',
|
|
300
|
+
key: { val: true, location },
|
|
301
|
+
type: linkMainArtifact( location, 'cds.UUID' ),
|
|
302
|
+
location,
|
|
303
|
+
};
|
|
304
|
+
dictAdd( art.elements, 'ID_texts', textId );
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const enrich = useTextsAspect
|
|
308
|
+
? enrichTextsEntityWithInclude
|
|
309
|
+
: enrichTextsEntityWithDefaultElements;
|
|
310
|
+
enrich( art, base, absolute, fioriEnabled );
|
|
287
311
|
|
|
288
312
|
if (addTextsLanguageAssoc) {
|
|
289
313
|
const language = {
|
|
290
314
|
name: { location, id: 'language' },
|
|
291
315
|
kind: 'element',
|
|
292
316
|
location,
|
|
293
|
-
type:
|
|
294
|
-
target:
|
|
317
|
+
type: linkMainArtifact( location, 'cds.Association' ),
|
|
318
|
+
target: linkMainArtifact( location, 'sap.common.Languages' ),
|
|
295
319
|
on: {
|
|
296
320
|
op: { val: '=', location },
|
|
297
321
|
args: [
|
|
@@ -362,46 +386,25 @@ function generate( model ) {
|
|
|
362
386
|
}
|
|
363
387
|
|
|
364
388
|
/**
|
|
365
|
-
*
|
|
389
|
+
* Enrich the `.texts` entity for the given base artifact.
|
|
366
390
|
* In contrast to createTextsEntityWithDefaultElements(), this one creates
|
|
367
391
|
* an include for `sap.common.TextsAspect`.
|
|
368
392
|
*
|
|
369
393
|
* Does NOT apply the include!
|
|
370
394
|
*
|
|
395
|
+
* @param {XSN.Artifact} art
|
|
371
396
|
* @param {XSN.Artifact} base
|
|
372
397
|
* @param {string} absolute
|
|
373
398
|
* @param {boolean} fioriEnabled
|
|
374
399
|
*/
|
|
375
|
-
function
|
|
400
|
+
function enrichTextsEntityWithInclude( art, base, absolute, fioriEnabled ) {
|
|
376
401
|
const textsAspectName = 'sap.common.TextsAspect';
|
|
377
402
|
const textsAspect = model.definitions['sap.common.TextsAspect'];
|
|
378
|
-
const
|
|
379
|
-
const { location } = base.name;
|
|
380
|
-
const art = {
|
|
381
|
-
kind: 'entity',
|
|
382
|
-
name: { path: splitIntoPath( location, absolute ), absolute, location },
|
|
383
|
-
includes: [ createInclude( textsAspectName, base.location ) ],
|
|
384
|
-
location: base.location,
|
|
385
|
-
elements,
|
|
386
|
-
$inferred: 'localized-entity',
|
|
387
|
-
};
|
|
403
|
+
const { location } = art.name;
|
|
388
404
|
|
|
389
|
-
|
|
390
|
-
// To be compatible, we switch off draft without @fiori.draft.enabled
|
|
391
|
-
setAnnotation( art, '@odata.draft.enabled', art.location, false );
|
|
392
|
-
}
|
|
393
|
-
else {
|
|
394
|
-
// @fiori.draft.enabled artifacts need default elements ID_texts and locale.
|
|
395
|
-
// `locale` is copied from `sap.common.TextsAspect`, but without "key".
|
|
396
|
-
const textId = {
|
|
397
|
-
name: { location, id: 'ID_texts' },
|
|
398
|
-
kind: 'element',
|
|
399
|
-
key: { val: true, location },
|
|
400
|
-
type: augmentPath( location, 'cds.UUID' ),
|
|
401
|
-
location,
|
|
402
|
-
};
|
|
403
|
-
dictAdd( art.elements, 'ID_texts', textId );
|
|
405
|
+
art.includes = [ createInclude( textsAspectName, base.location ) ];
|
|
404
406
|
|
|
407
|
+
if (fioriEnabled) {
|
|
405
408
|
// "Early" include; only for element `locale`, which has its `key` property
|
|
406
409
|
// removed (or rather: it is not copied).
|
|
407
410
|
linkToOrigin( textsAspect.elements.locale, 'locale', art, 'elements', location );
|
|
@@ -410,61 +413,31 @@ function generate( model ) {
|
|
|
410
413
|
if (addTextsLanguageAssoc && art.elements.language)
|
|
411
414
|
art.elements.language = undefined; // TODO: Message? Ignore?
|
|
412
415
|
// TODO: what is this necessary? We do not create a text entity in this case
|
|
413
|
-
|
|
414
|
-
setLink( art, '_block', model.$internal );
|
|
415
|
-
model.definitions[absolute] = art;
|
|
416
|
-
extendArtifactBefore( art ); // having extensions here would be wrong
|
|
417
|
-
return art;
|
|
418
416
|
}
|
|
419
417
|
|
|
420
418
|
/**
|
|
419
|
+
* @param {XSN.Artifact} art
|
|
421
420
|
* @param {XSN.Artifact} base
|
|
422
421
|
* @param {string} absolute
|
|
423
422
|
* @param {boolean} fioriEnabled
|
|
424
423
|
*/
|
|
425
|
-
function
|
|
426
|
-
const elements = Object.create( null );
|
|
427
|
-
const { location } = base.name;
|
|
428
|
-
const art = {
|
|
429
|
-
kind: 'entity',
|
|
430
|
-
name: { path: splitIntoPath( location, absolute ), absolute, location },
|
|
431
|
-
location: base.location,
|
|
432
|
-
elements,
|
|
433
|
-
$inferred: 'localized-entity',
|
|
434
|
-
};
|
|
424
|
+
function enrichTextsEntityWithDefaultElements( art, base, absolute, fioriEnabled ) {
|
|
435
425
|
// If there is a type `sap.common.Locale`, then use it as the type for the element `locale`.
|
|
436
426
|
// If not, use the default `cds.String` with a length of 14.
|
|
437
427
|
const hasLocaleType = model.definitions['sap.common.Locale']?.kind === 'type';
|
|
428
|
+
const { location } = art.name;
|
|
438
429
|
const locale = {
|
|
439
430
|
name: { location, id: 'locale' },
|
|
440
431
|
kind: 'element',
|
|
441
|
-
type:
|
|
432
|
+
type: linkMainArtifact( location, hasLocaleType ? 'sap.common.Locale' : 'cds.String' ),
|
|
442
433
|
location,
|
|
443
434
|
};
|
|
444
435
|
if (!hasLocaleType)
|
|
445
436
|
locale.length = { literal: 'number', val: 14, location };
|
|
446
437
|
|
|
447
|
-
if (!fioriEnabled)
|
|
438
|
+
if (!fioriEnabled)
|
|
448
439
|
locale.key = { val: true, location };
|
|
449
|
-
// To be compatible, we switch off draft without @fiori.draft.enabled
|
|
450
|
-
setAnnotation( art, '@odata.draft.enabled', art.location, false );
|
|
451
|
-
}
|
|
452
|
-
else {
|
|
453
|
-
const textId = {
|
|
454
|
-
name: { location, id: 'ID_texts' },
|
|
455
|
-
kind: 'element',
|
|
456
|
-
key: { val: true, location },
|
|
457
|
-
type: augmentPath( location, 'cds.UUID' ),
|
|
458
|
-
location,
|
|
459
|
-
};
|
|
460
|
-
dictAdd( art.elements, 'ID_texts', textId );
|
|
461
|
-
}
|
|
462
440
|
dictAdd( art.elements, 'locale', locale );
|
|
463
|
-
|
|
464
|
-
setLink( art, '_block', model.$internal );
|
|
465
|
-
model.definitions[absolute] = art;
|
|
466
|
-
extendArtifactBefore( art ); // having extensions here would be wrong
|
|
467
|
-
return art;
|
|
468
441
|
}
|
|
469
442
|
|
|
470
443
|
/**
|
|
@@ -482,9 +455,9 @@ function generate( model ) {
|
|
|
482
455
|
kind: 'element',
|
|
483
456
|
location,
|
|
484
457
|
$inferred: 'localized',
|
|
485
|
-
type:
|
|
458
|
+
type: linkMainArtifact( location, 'cds.Composition' ),
|
|
486
459
|
cardinality: { targetMax: { literal: 'string', val: '*', location }, location },
|
|
487
|
-
target:
|
|
460
|
+
target: linkMainArtifact( location, textsName ),
|
|
488
461
|
on: augmentEqual( location, 'texts', keys ),
|
|
489
462
|
};
|
|
490
463
|
setMemberParent( texts, 'texts', art, 'elements' );
|
|
@@ -497,8 +470,8 @@ function generate( model ) {
|
|
|
497
470
|
kind: 'element',
|
|
498
471
|
location,
|
|
499
472
|
$inferred: 'localized',
|
|
500
|
-
type:
|
|
501
|
-
target:
|
|
473
|
+
type: linkMainArtifact( location, 'cds.Association' ),
|
|
474
|
+
target: linkMainArtifact( location, textsName ),
|
|
502
475
|
on: augmentEqual( location, 'localized', keys ),
|
|
503
476
|
};
|
|
504
477
|
setMemberParent( localized, 'localized', art, 'elements' );
|
|
@@ -537,7 +510,7 @@ function generate( model ) {
|
|
|
537
510
|
*/
|
|
538
511
|
function hasTruthyProp( art, prop ) {
|
|
539
512
|
const processed = Object.create( null ); // avoid infloops with circular refs
|
|
540
|
-
let name = art.name.
|
|
513
|
+
let name = (art._main || art).name.id; // is ok, since no recursive type possible
|
|
541
514
|
while (art && !processed[name]) {
|
|
542
515
|
if (art[prop])
|
|
543
516
|
return art[prop].val;
|
|
@@ -546,7 +519,7 @@ function generate( model ) {
|
|
|
546
519
|
art = art._origin;
|
|
547
520
|
if (!art.name) // anonymous aspect
|
|
548
521
|
return false;
|
|
549
|
-
name = art
|
|
522
|
+
name = (art._main || art)?.name?.id;
|
|
550
523
|
}
|
|
551
524
|
else if (art.type && art._block && art.type.scope !== 'typeOf') {
|
|
552
525
|
// TODO: also do something special for TYPE OF inside `art`s own elements
|
|
@@ -599,7 +572,7 @@ function generate( model ) {
|
|
|
599
572
|
target = resolvePath( origin.targetAspect, 'targetAspect', origin );
|
|
600
573
|
if (!target || !target.elements)
|
|
601
574
|
return;
|
|
602
|
-
const entityName = `${ base.name.
|
|
575
|
+
const entityName = `${ base.name.id }.${ elem.name.id }`;
|
|
603
576
|
const entity = allowAspectComposition( target, elem, keys, entityName ) &&
|
|
604
577
|
createTargetEntity( target, elem, keys, entityName, base );
|
|
605
578
|
elem.target = {
|
|
@@ -615,7 +588,7 @@ function generate( model ) {
|
|
|
615
588
|
// already has an _origin (when the managed composition is included)
|
|
616
589
|
if (up_)
|
|
617
590
|
setLink( up_, '_origin', entity.elements.up_ );
|
|
618
|
-
model.$compositionTargets[entity.name.
|
|
591
|
+
model.$compositionTargets[entity.name.id] = true;
|
|
619
592
|
processAspectComposition( entity );
|
|
620
593
|
processLocalizedData( entity );
|
|
621
594
|
}
|
|
@@ -674,7 +647,7 @@ function generate( model ) {
|
|
|
674
647
|
|
|
675
648
|
if (elem.type && !isDirectComposition( elem )) {
|
|
676
649
|
// Only issue warning for direct usages, not for projections, includes, etc.
|
|
677
|
-
// TODO: Make it configurable error;
|
|
650
|
+
// TODO: Make it configurable error; v5: error
|
|
678
651
|
warning( 'def-expected-comp-aspect', [ elem.type.location, elem ],
|
|
679
652
|
{ prop: 'Composition of', otherprop: 'Association to' },
|
|
680
653
|
'Expected $(PROP), but found $(OTHERPROP) for composition of aspect' );
|
|
@@ -698,8 +671,7 @@ function generate( model ) {
|
|
|
698
671
|
const art = {
|
|
699
672
|
kind: 'entity',
|
|
700
673
|
name: {
|
|
701
|
-
|
|
702
|
-
absolute: entityName,
|
|
674
|
+
id: entityName,
|
|
703
675
|
// for code navigation (e.g. via `extend`s): point to the element's name
|
|
704
676
|
location: elem.name.location,
|
|
705
677
|
},
|
|
@@ -724,8 +696,8 @@ function generate( model ) {
|
|
|
724
696
|
kind: 'element',
|
|
725
697
|
location: upLocation,
|
|
726
698
|
$inferred: 'aspect-composition',
|
|
727
|
-
type:
|
|
728
|
-
target:
|
|
699
|
+
type: linkMainArtifact( upLocation, 'cds.Association' ),
|
|
700
|
+
target: linkMainArtifact( upLocation, base.name.id ),
|
|
729
701
|
cardinality: {
|
|
730
702
|
targetMin: { val: 1, literal: 'number', location: upLocation },
|
|
731
703
|
targetMax: { val: 1, literal: 'number', location: upLocation },
|
|
@@ -755,9 +727,11 @@ function generate( model ) {
|
|
|
755
727
|
model.definitions[entityName] = art;
|
|
756
728
|
initArtifact( art );
|
|
757
729
|
|
|
758
|
-
|
|
730
|
+
// Apply annotations to generated artifact, prepare (not apply!) element
|
|
731
|
+
// annotations (remark: adding elements is not allowed for generated artifacts):
|
|
732
|
+
extendArtifactBefore( art );
|
|
759
733
|
// Copy persistence annotations from aspect.
|
|
760
|
-
copyPersistenceAnnotations( art, target ); // after
|
|
734
|
+
copyPersistenceAnnotations( art, target ); // after extendArtifactBefore()
|
|
761
735
|
return art;
|
|
762
736
|
}
|
|
763
737
|
|
|
@@ -808,6 +782,12 @@ function generate( model ) {
|
|
|
808
782
|
target[anno] = { ...source[anno], $inferred: 'parent-origin' };
|
|
809
783
|
}
|
|
810
784
|
}
|
|
785
|
+
|
|
786
|
+
function linkMainArtifact( location, absolute ) {
|
|
787
|
+
const r = { location };
|
|
788
|
+
setArtifactLink( r, model.definitions[absolute] );
|
|
789
|
+
return r;
|
|
790
|
+
}
|
|
811
791
|
}
|
|
812
792
|
|
|
813
793
|
function augmentEqual( location, assocname, relations, prefix = '' ) {
|
|
@@ -105,7 +105,7 @@ function kickStart( model ) {
|
|
|
105
105
|
const service = art._service;
|
|
106
106
|
if (!service)
|
|
107
107
|
return;
|
|
108
|
-
const sname = service.name.
|
|
108
|
+
const sname = service.name.id;
|
|
109
109
|
art._ancestors.forEach( expose );
|
|
110
110
|
return;
|
|
111
111
|
|
|
@@ -122,14 +122,16 @@ function kickStart( model ) {
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
function tagCompositionTargets( elem ) {
|
|
125
|
-
const type = elem
|
|
126
|
-
if (elem.target && type &&
|
|
125
|
+
const { type } = elem;
|
|
126
|
+
if (elem.target && type &&
|
|
127
|
+
(type._artifact === model.definitions['cds.Composition'] ||
|
|
128
|
+
type.path?.[0].id === 'cds.Composition')) {
|
|
127
129
|
// A target aspect would have already moved to property `targetAspect` in
|
|
128
130
|
// define.js (hm... more something for kick-start.js...)
|
|
129
131
|
// TODO: for safety, just use resolveUncheckedPath()
|
|
130
132
|
const target = resolvePath( elem.target, 'target', elem );
|
|
131
133
|
if (target)
|
|
132
|
-
model.$compositionTargets[target.name.
|
|
134
|
+
model.$compositionTargets[target.name.id] = true;
|
|
133
135
|
}
|
|
134
136
|
forEachGeneric( elem, 'elements', tagCompositionTargets );
|
|
135
137
|
}
|
|
@@ -143,7 +145,7 @@ function kickStart( model ) {
|
|
|
143
145
|
for (const def of src.usings) {
|
|
144
146
|
if (def.usings) // using {...}
|
|
145
147
|
resolveUsings( def );
|
|
146
|
-
if (!def.name || !def.name.
|
|
148
|
+
if (!def.name || !def.name.id)
|
|
147
149
|
continue; // using {...}, parse error
|
|
148
150
|
const art = model.definitions[def.name.absolute];
|
|
149
151
|
if (art && art.$duplicates)
|