@sap/cds-compiler 3.9.4 → 4.0.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 +92 -4
- package/README.md +0 -1
- package/bin/cdsc.js +11 -23
- package/bin/cdsse.js +3 -3
- package/doc/API.md +5 -0
- package/doc/CHANGELOG_ARCHIVE.md +1 -1
- package/doc/CHANGELOG_BETA.md +17 -1
- package/doc/CHANGELOG_DEPRECATED.md +28 -0
- package/lib/api/.eslintrc.json +1 -1
- package/lib/api/main.js +26 -8
- package/lib/api/options.js +2 -0
- package/lib/base/error.js +2 -0
- package/lib/base/message-registry.js +143 -64
- package/lib/base/messages.js +213 -107
- package/lib/base/model.js +11 -11
- package/lib/checks/.eslintrc.json +1 -1
- package/lib/checks/annotationsOData.js +2 -2
- package/lib/checks/elements.js +1 -1
- package/lib/checks/enricher.js +26 -3
- package/lib/checks/onConditions.js +67 -12
- package/lib/checks/queryNoDbArtifacts.js +106 -105
- package/lib/checks/sql-snippets.js +2 -0
- package/lib/checks/types.js +12 -6
- package/lib/checks/validator.js +2 -2
- package/lib/compiler/assert-consistency.js +10 -8
- package/lib/compiler/builtins.js +8 -2
- package/lib/compiler/checks.js +52 -35
- package/lib/compiler/define.js +31 -26
- package/lib/compiler/extend.js +120 -65
- package/lib/compiler/finalize-parse-cdl.js +12 -43
- package/lib/compiler/generate.js +16 -5
- package/lib/compiler/index.js +8 -5
- package/lib/compiler/kick-start.js +4 -3
- package/lib/compiler/populate.js +96 -95
- package/lib/compiler/propagator.js +7 -8
- package/lib/compiler/resolve.js +377 -103
- package/lib/compiler/shared.js +794 -517
- package/lib/compiler/tweak-assocs.js +8 -6
- package/lib/compiler/utils.js +44 -0
- package/lib/edm/annotations/genericTranslation.js +12 -4
- package/lib/edm/csn2edm.js +34 -32
- package/lib/edm/edm.js +34 -31
- package/lib/edm/edmAnnoPreprocessor.js +0 -23
- package/lib/edm/edmInboundChecks.js +7 -2
- package/lib/edm/edmPreprocessor.js +18 -17
- package/lib/edm/edmUtils.js +8 -4
- package/lib/gen/Dictionary.json +18 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +4 -2
- package/lib/gen/languageParser.js +5006 -4582
- package/lib/json/from-csn.js +157 -112
- package/lib/json/to-csn.js +60 -89
- package/lib/language/antlrParser.js +17 -13
- package/lib/language/docCommentParser.js +11 -1
- package/lib/language/genericAntlrParser.js +13 -10
- package/lib/language/language.g4 +168 -97
- package/lib/main.d.ts +128 -36
- package/lib/main.js +1 -1
- package/lib/model/csnRefs.js +24 -5
- package/lib/model/csnUtils.js +9 -8
- package/lib/model/revealInternalProperties.js +7 -12
- package/lib/modelCompare/compare.js +1 -1
- package/lib/modelCompare/utils/filter.js +40 -2
- package/lib/optionProcessor.js +0 -3
- package/lib/render/toCdl.js +247 -214
- package/lib/render/toHdbcds.js +197 -181
- package/lib/render/toSql.js +325 -289
- package/lib/render/utils/common.js +42 -4
- package/lib/render/utils/delta.js +1 -1
- package/lib/render/utils/sql.js +3 -3
- package/lib/transform/braceExpression.js +2 -2
- package/lib/transform/db/.eslintrc.json +1 -1
- package/lib/transform/db/applyTransformations.js +3 -3
- package/lib/transform/db/associations.js +24 -12
- package/lib/transform/db/expansion.js +17 -18
- package/lib/transform/db/flattening.js +17 -21
- package/lib/transform/db/rewriteCalculatedElements.js +171 -64
- package/lib/transform/db/views.js +3 -4
- package/lib/transform/draft/db.js +21 -12
- package/lib/transform/draft/odata.js +4 -0
- package/lib/transform/forOdataNew.js +11 -10
- package/lib/transform/forRelationalDB.js +12 -7
- package/lib/transform/localized.js +4 -2
- package/lib/transform/odata/toFinalBaseType.js +5 -5
- package/lib/transform/odata/typesExposure.js +3 -3
- package/lib/transform/parseExpr.js +3 -0
- package/lib/transform/transformUtilsNew.js +43 -23
- package/lib/transform/translateAssocsToJoins.js +7 -6
- package/lib/transform/universalCsn/.eslintrc.json +1 -1
- package/lib/transform/universalCsn/coreComputed.js +7 -5
- package/lib/transform/universalCsn/universalCsnEnricher.js +12 -12
- package/package.json +2 -2
- package/share/messages/{duplicate-autoexposed.md → def-duplicate-autoexposed.md} +5 -1
- package/share/messages/message-explanations.json +1 -1
package/lib/compiler/populate.js
CHANGED
|
@@ -45,10 +45,24 @@ const {
|
|
|
45
45
|
setExpandStatus,
|
|
46
46
|
setExpandStatusAnnotate,
|
|
47
47
|
} = require('./utils');
|
|
48
|
+
const { typeParameters } = require('./builtins');
|
|
48
49
|
|
|
49
50
|
const $inferred = Symbol.for('cds.$inferred');
|
|
50
51
|
const $location = Symbol.for('cds.$location');
|
|
51
52
|
|
|
53
|
+
/**
|
|
54
|
+
* These properties are copied from specified elements.
|
|
55
|
+
*/
|
|
56
|
+
const typePropertiesFromSpecifiedElements = {
|
|
57
|
+
// 'key' is special case, see setSpecifiedElementTypeProperties()
|
|
58
|
+
// TODO: Decide on behavior if an actual key does not have "key" property in specified elements,
|
|
59
|
+
// and another non-key is marked key in them.
|
|
60
|
+
// key: 'if-undefined',
|
|
61
|
+
default: 1,
|
|
62
|
+
notNull: 1,
|
|
63
|
+
localized: 1,
|
|
64
|
+
...typeParameters.expectedLiteralsFor,
|
|
65
|
+
};
|
|
52
66
|
|
|
53
67
|
// Export function of this file.
|
|
54
68
|
function populate( model ) {
|
|
@@ -64,11 +78,11 @@ function populate( model ) {
|
|
|
64
78
|
extendArtifactBefore,
|
|
65
79
|
extendArtifactAfter,
|
|
66
80
|
} = model.$functions;
|
|
67
|
-
model.$volatileFunctions.environment = environment;
|
|
68
81
|
Object.assign( model.$functions, {
|
|
69
82
|
effectiveType,
|
|
70
83
|
getOrigin,
|
|
71
84
|
resolveType,
|
|
85
|
+
navigationEnv,
|
|
72
86
|
} );
|
|
73
87
|
// let depth = 100;
|
|
74
88
|
|
|
@@ -113,17 +127,8 @@ function populate( model ) {
|
|
|
113
127
|
//--------------------------------------------------------------------------
|
|
114
128
|
// Phase 2: call effectiveType() on-demand, which also calculates view elems
|
|
115
129
|
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
// chain and resolve the association `target`. View elements are calculated
|
|
119
|
-
// on demand.
|
|
120
|
-
function environment( art, location, user, assocSpec ) {
|
|
121
|
-
const env = navigationEnv( art, location, user, assocSpec );
|
|
122
|
-
if (env === 0)
|
|
123
|
-
return 0;
|
|
124
|
-
return env && env.elements || Object.create(null);
|
|
125
|
-
}
|
|
126
|
-
|
|
130
|
+
// TODO: move setting dependencies and complaining about assocs in keys
|
|
131
|
+
// to resolvePath - then remove params: location, user
|
|
127
132
|
function navigationEnv( art, location, user, assocSpec ) {
|
|
128
133
|
// = effectiveType() on from-path, TODO: should actually already part of
|
|
129
134
|
// resolvePath() on FROM
|
|
@@ -132,7 +137,7 @@ function populate( model ) {
|
|
|
132
137
|
let type = effectiveType( art );
|
|
133
138
|
while (type?.items) // TODO: disallow navigation to many sometimes
|
|
134
139
|
type = effectiveType( type.items );
|
|
135
|
-
if (!type?.target)
|
|
140
|
+
if (!type?.target || assocSpec === 'targetAspectOnly')
|
|
136
141
|
return type;
|
|
137
142
|
|
|
138
143
|
if (assocSpec === false) {
|
|
@@ -215,12 +220,14 @@ function populate( model ) {
|
|
|
215
220
|
// Without type, value.path or _origin at beginning, link to itself:
|
|
216
221
|
extendArtifactBefore( a );
|
|
217
222
|
art = populateArtifact( a, art ) || a;
|
|
218
|
-
if (a.elements$ || a.enum$)
|
|
219
|
-
mergeSpecifiedElementsOrEnum( a );
|
|
220
223
|
setLink( a, '_effectiveType', art );
|
|
221
224
|
a.$effectiveSeqNo = ++effectiveSeqNo;
|
|
225
|
+
if (a.elements$ || a.enum$)
|
|
226
|
+
mergeSpecifiedElementsOrEnum( a );
|
|
222
227
|
// console.log( 'ET-DO:', effectiveSeqNo, a?.kind, a?.name, a._extensions?.elements?.length )
|
|
223
228
|
extendArtifactAfter( a ); // after setting _effectiveType (for messages)
|
|
229
|
+
if (a.typeProps$)
|
|
230
|
+
setSpecifiedElementTypeProperties(a);
|
|
224
231
|
}
|
|
225
232
|
// console.log( 'ET-END:', art?.kind, art?.name )
|
|
226
233
|
return art;
|
|
@@ -241,6 +248,9 @@ function populate( model ) {
|
|
|
241
248
|
if (!art.expand)
|
|
242
249
|
return art;
|
|
243
250
|
}
|
|
251
|
+
else if (art.targetAspect) { // target aspect in aspect
|
|
252
|
+
return art;
|
|
253
|
+
}
|
|
244
254
|
|
|
245
255
|
// With properties to be calculated: ----------------------------------------
|
|
246
256
|
if (art.query && art.kind !== '$tableAlias') { // query entity
|
|
@@ -313,19 +323,21 @@ function populate( model ) {
|
|
|
313
323
|
return getOrigin( art.$queries?.[0] );
|
|
314
324
|
}
|
|
315
325
|
else {
|
|
326
|
+
// TODO: write checks for path in enum?
|
|
316
327
|
if (art.value?.path)
|
|
317
|
-
return resolvePath( art.value, 'expr', art
|
|
328
|
+
return resolvePath( art.value, (art.$syntax === 'calc' ? 'calc' : 'expr'), art );
|
|
318
329
|
if (art.kind === 'select')
|
|
319
330
|
return getOrigin( dictFirst( art.$tableAliases ) );
|
|
320
331
|
// init sets _origin for alias to sub query, only need to handle ref here:
|
|
321
332
|
if (art.kind === '$tableAlias') {
|
|
322
333
|
// do not use navigationEnv(): it would always call effectiveType() on the
|
|
323
|
-
// source → we would
|
|
334
|
+
// source → we would have a deeper callstack
|
|
324
335
|
const source = resolvePath( art, 'from', art._parent );
|
|
325
336
|
if (!source?._main)
|
|
326
337
|
return source; // direct entity (or undefined)
|
|
327
338
|
// Before having done the resolvePath cleanup, do not rely on resolvePath
|
|
328
339
|
// to call effectiveType() on the last assoc of a from ref:
|
|
340
|
+
// TODO: check this with test3/Queries/DollarSelf/CorruptedSource.err.cds
|
|
329
341
|
const assoc = effectiveType( source );
|
|
330
342
|
return resolvePath( assoc?.target, 'target', assoc );
|
|
331
343
|
}
|
|
@@ -338,25 +350,6 @@ function populate( model ) {
|
|
|
338
350
|
return ref._artifact;
|
|
339
351
|
while (user._outer) // in items
|
|
340
352
|
user = user._outer;
|
|
341
|
-
if (ref.scope === 'typeOf') {
|
|
342
|
-
let struct = user;
|
|
343
|
-
while (struct.kind === 'element')
|
|
344
|
-
struct = struct._parent;
|
|
345
|
-
if (struct.kind === 'select' || struct.kind === 'annotation') {
|
|
346
|
-
// `type of` in annotation definitions can't work, because csn type refs
|
|
347
|
-
// always refer to definitions.
|
|
348
|
-
message( 'type-unexpected-typeof', [ ref.location, user ],
|
|
349
|
-
{ keyword: 'type of', '#': struct.kind } );
|
|
350
|
-
// we actually refer to an element in _combined; TODO: return null if
|
|
351
|
-
// not configurable; would produce illegal CSN with sub queries in FROM
|
|
352
|
-
}
|
|
353
|
-
else if (struct !== user._main) {
|
|
354
|
-
message( 'type-unexpected-typeof', [ ref.location, user ],
|
|
355
|
-
{ keyword: 'type of', '#': struct.kind } );
|
|
356
|
-
return setArtifactLink( ref, null );
|
|
357
|
-
}
|
|
358
|
-
return resolvePath( ref, 'typeOf', user );
|
|
359
|
-
}
|
|
360
353
|
if (user.kind === 'event')
|
|
361
354
|
return resolvePath( ref, 'eventType', user );
|
|
362
355
|
if (user.kind === 'param' && user._parent &&
|
|
@@ -525,8 +518,7 @@ function populate( model ) {
|
|
|
525
518
|
* Merge _specified_ elements with _inferred_ elements in the given view/element,
|
|
526
519
|
* where specified elements can appear through CSN.
|
|
527
520
|
*
|
|
528
|
-
* We only copy annotations
|
|
529
|
-
* but only appear in `elements` in CSN.
|
|
521
|
+
* We only copy annotations.
|
|
530
522
|
*
|
|
531
523
|
* This is important to ensure re-compilability.
|
|
532
524
|
*
|
|
@@ -535,6 +527,8 @@ function populate( model ) {
|
|
|
535
527
|
* @param art
|
|
536
528
|
*/
|
|
537
529
|
function mergeSpecifiedElementsOrEnum( art ) {
|
|
530
|
+
let wasAnnotated = false;
|
|
531
|
+
|
|
538
532
|
for (const id in (art.elements || art.enum)) {
|
|
539
533
|
const ielem = art.elements ? art.elements[id] : art.enum[id]; // inferred element
|
|
540
534
|
const selem = art.elements$ ? art.elements$[id] : art.enum$[id]; // specified element
|
|
@@ -543,44 +537,69 @@ function populate( model ) {
|
|
|
543
537
|
'Element $(ID) is missing in specified elements' );
|
|
544
538
|
}
|
|
545
539
|
else {
|
|
546
|
-
let wasAnnotated = false;
|
|
547
540
|
for (const prop in selem) {
|
|
548
541
|
// just annotation assignments and doc comments for the moment
|
|
549
542
|
if (prop.charAt(0) === '@' || prop === 'doc') {
|
|
550
543
|
ielem[prop] = selem[prop];
|
|
551
544
|
// required for gensrc mode of to-csn.js, otherwise the annotation
|
|
552
545
|
// may be lost during recompilation.
|
|
546
|
+
// TODO: Clarify: Should gensrc add this annotation to the column or as an
|
|
547
|
+
// annotate statement? Currently it's at the column.
|
|
553
548
|
ielem[prop].$priority = 'annotate';
|
|
554
549
|
wasAnnotated = true;
|
|
555
550
|
}
|
|
551
|
+
else if (typePropertiesFromSpecifiedElements[prop]) {
|
|
552
|
+
if (!ielem.typeProps$)
|
|
553
|
+
setLink(ielem, 'typeProps$', Object.create(null));
|
|
554
|
+
// Note: At this point in time, effectiveType() was likely not called on the
|
|
555
|
+
// element, yet. Setting it here, we can't compare it to it's value from _origin.
|
|
556
|
+
ielem.typeProps$[prop] = selem[prop];
|
|
557
|
+
}
|
|
556
558
|
}
|
|
557
559
|
|
|
558
|
-
if (wasAnnotated)
|
|
559
|
-
setExpandStatusAnnotate(art, 'annotate');
|
|
560
|
-
|
|
561
560
|
selem.$replacement = true;
|
|
562
|
-
if (selem.elements)
|
|
561
|
+
if (selem.elements)
|
|
563
562
|
setLink(ielem, 'elements$', selem.elements);
|
|
564
|
-
|
|
565
|
-
}
|
|
566
|
-
if (selem.enum) {
|
|
563
|
+
if (selem.enum)
|
|
567
564
|
setLink(ielem, 'enum$', selem.enum);
|
|
568
|
-
delete selem.enum;
|
|
569
|
-
}
|
|
570
565
|
}
|
|
571
566
|
}
|
|
567
|
+
|
|
568
|
+
if (wasAnnotated)
|
|
569
|
+
setExpandStatusAnnotate(art, 'annotate');
|
|
570
|
+
|
|
572
571
|
// TODO: We don't check enum$, yet! We first need to fix expansion for
|
|
573
572
|
// `cast(elem as EnumType)` (see #9421)
|
|
574
573
|
for (const id in art.elements$) {
|
|
575
|
-
const
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
574
|
+
const specifiedElement = art.elements$[id];
|
|
575
|
+
// TODO: Custom kind?
|
|
576
|
+
specifiedElement.$isSpecifiedElement = true;
|
|
577
|
+
if (!specifiedElement.$replacement) {
|
|
578
|
+
const loc = [ specifiedElement.name.location, specifiedElement ];
|
|
579
|
+
error( 'query-unspecified-element', loc, { id },
|
|
579
580
|
'Element $(ID) does not result from the query' );
|
|
580
581
|
}
|
|
581
582
|
}
|
|
582
583
|
}
|
|
583
584
|
|
|
585
|
+
function setSpecifiedElementTypeProperties( art ) {
|
|
586
|
+
for (const prop in art.typeProps$) {
|
|
587
|
+
let o = art;
|
|
588
|
+
if (o._effectiveType !== 0) { // cyclic
|
|
589
|
+
while (!o[prop] && getOrigin(o))
|
|
590
|
+
o = getOrigin(o);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
if (typePropertiesFromSpecifiedElements[prop] === 'if-undefined') {
|
|
594
|
+
if (!o[prop])
|
|
595
|
+
art[prop] = art.typeProps$[prop];
|
|
596
|
+
}
|
|
597
|
+
else if (!o[prop] || art.typeProps$[prop].val !== o[prop]?.val) {
|
|
598
|
+
art[prop] = art.typeProps$[prop];
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
584
603
|
function populateQuery( query ) {
|
|
585
604
|
if (query._combined || !query.from || !query.$tableAliases)
|
|
586
605
|
// already done or $join query or parse error
|
|
@@ -633,7 +652,7 @@ function populate( model ) {
|
|
|
633
652
|
return null;
|
|
634
653
|
// If we allow CDL-style casts of `expand`s to associations in the future, we
|
|
635
654
|
// need to ignore an explicit type, i.e. not getOrigin():
|
|
636
|
-
const assoc = resolvePath( elem.value, 'expr', elem
|
|
655
|
+
const assoc = resolvePath( elem.value, 'expr', elem ); // TODO: extra 'column'?
|
|
637
656
|
if (!effectiveType( assoc )?.target)
|
|
638
657
|
return initFromColumns( elem, elem.expand );
|
|
639
658
|
const { targetMax } = path[path.length - 1].cardinality || getCardinality( assoc );
|
|
@@ -727,8 +746,10 @@ function populate( model ) {
|
|
|
727
746
|
return;
|
|
728
747
|
}
|
|
729
748
|
if (!elem.type && elem.value?.type) { // top-level CAST( expr AS type )
|
|
730
|
-
if (!elem.target)
|
|
749
|
+
if (!elem.target) { // TODO: we might issue an error if there is a target
|
|
731
750
|
elem.type = { ...elem.value.type, $inferred: 'cast' };
|
|
751
|
+
// TODO: What about other direct properties in cast such as items/enum/...?
|
|
752
|
+
}
|
|
732
753
|
}
|
|
733
754
|
if (elem.foreignKeys) // REDIRECTED with explicit foreign keys
|
|
734
755
|
forEachGeneric( elem, 'foreignKeys', (key, name) => initKey( key, name, elem ) );
|
|
@@ -832,9 +853,12 @@ function populate( model ) {
|
|
|
832
853
|
|
|
833
854
|
function columnEnv( envParent, query ) { // etc. wildcard._pathHead;
|
|
834
855
|
// if (envParent) console.log( 'CE:', envParent._origin, query );
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
856
|
+
if (!envParent)
|
|
857
|
+
return userQuery( query )._combined;
|
|
858
|
+
const env = navigationEnv( getOrigin( envParent ) );
|
|
859
|
+
if (env === 0)
|
|
860
|
+
return 0;
|
|
861
|
+
return env?.elements || Object.create(null);
|
|
838
862
|
}
|
|
839
863
|
|
|
840
864
|
function reportReplacement( sibling, navElem, query ) {
|
|
@@ -903,13 +927,17 @@ function populate( model ) {
|
|
|
903
927
|
// PRE: elem has no target, assoc has target prop
|
|
904
928
|
if (elem.kind === '$tableAlias')
|
|
905
929
|
return false;
|
|
930
|
+
// Specified elements could lead to warnings that seem unfixable by the user.
|
|
931
|
+
// TODO: Custom kind?
|
|
932
|
+
if (elem.$isSpecifiedElement)
|
|
933
|
+
return false;
|
|
906
934
|
const assocTarget = resolvePath( assoc.target, 'target', assoc );
|
|
907
935
|
let target = assocTarget;
|
|
908
936
|
// console.log( info( null, [ elem.location, elem ], {target,art:assoc,name:''+assoc.target},
|
|
909
937
|
// 'RED').toString())
|
|
910
938
|
if (!target)
|
|
911
939
|
return false; // error in target ref
|
|
912
|
-
const { location } = elem.value || elem.type || elem.name;
|
|
940
|
+
const { location } = elem.value || elem.type || elem.name || elem;
|
|
913
941
|
const service = (elem._main || elem)._service;
|
|
914
942
|
if (service && service !== target._service && assocIsToBeRedirected( elem )) {
|
|
915
943
|
if (service !== (assoc._main || assoc)._service ||
|
|
@@ -920,36 +948,9 @@ function populate( model ) {
|
|
|
920
948
|
if (elem === assoc) { // redirection of user-provided target
|
|
921
949
|
if (assocTarget === target) // no change (due to no implicit redirection)
|
|
922
950
|
return true;
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
name: elem.name,
|
|
927
|
-
type: { // TODO: necessary?
|
|
928
|
-
path: [ { id: type.name.absolute, location: elem.type.location } ],
|
|
929
|
-
scope: 'global',
|
|
930
|
-
location: elem.type.location,
|
|
931
|
-
$inferred: 'REDIRECTED',
|
|
932
|
-
},
|
|
933
|
-
target: elem.target,
|
|
934
|
-
$inferred: 'REDIRECTED',
|
|
935
|
-
location: elem.target.location,
|
|
936
|
-
};
|
|
937
|
-
setLink( elem, '_origin', origin );
|
|
938
|
-
setArtifactLink( elem.type, type );
|
|
939
|
-
setLink( origin, '_outer', elem );
|
|
940
|
-
setLink( origin, '_parent', elem._parent );
|
|
941
|
-
if (elem._main) // remark: the param `elem` can also be a type
|
|
942
|
-
setLink( origin, '_main', elem._main );
|
|
943
|
-
setLink( origin, '_effectiveType', origin );
|
|
944
|
-
setLink( origin, '_block', elem._block );
|
|
945
|
-
if (elem.foreignKeys) {
|
|
946
|
-
origin.foreignKeys = elem.foreignKeys;
|
|
947
|
-
delete elem.foreignKeys; // will be rewritten
|
|
948
|
-
}
|
|
949
|
-
if (elem.on) {
|
|
950
|
-
origin.on = elem.on;
|
|
951
|
-
delete elem.on; // will be rewritten
|
|
952
|
-
}
|
|
951
|
+
elem.target.$inferred = '';
|
|
952
|
+
setArtifactLink( elem.target, target );
|
|
953
|
+
return true;
|
|
953
954
|
}
|
|
954
955
|
if (target !== assocTarget)
|
|
955
956
|
setExpandStatus( elem, 'target' ); // (might) also set in rewriteCondition
|
|
@@ -1235,22 +1236,22 @@ function populate( model ) {
|
|
|
1235
1236
|
}
|
|
1236
1237
|
return autoexposed;
|
|
1237
1238
|
}
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1239
|
+
message( 'def-duplicate-autoexposed', [ service.name.location, service ],
|
|
1240
|
+
{ target, art: absolute },
|
|
1241
|
+
'Name $(ART) of auto-exposed entity for $(TARGET) collides with other definition' );
|
|
1241
1242
|
info( null, [ target.name.location, target ],
|
|
1242
1243
|
{ art: service },
|
|
1243
1244
|
'Expose this (or the competing) entity explicitly in service $(ART)' );
|
|
1244
1245
|
if (autoexposed.$inferred !== 'autoexposed')
|
|
1245
1246
|
return target;
|
|
1246
1247
|
const firstTarget = autoexposed.query.from._artifact;
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1248
|
+
message( 'def-duplicate-autoexposed', [ service.name.location, service ],
|
|
1249
|
+
{ target: firstTarget, art: absolute },
|
|
1250
|
+
'Name $(ART) of auto-exposed entity for $(TARGET) collides with other definition' );
|
|
1250
1251
|
info( null, [ firstTarget.name.location, firstTarget ],
|
|
1251
1252
|
{ art: service },
|
|
1252
1253
|
'Expose this (or the competing) entity explicitly in service $(ART)' );
|
|
1253
|
-
autoexposed.$inferred = 'duplicate-autoexposed';
|
|
1254
|
+
autoexposed.$inferred = 'def-duplicate-autoexposed';
|
|
1254
1255
|
return target;
|
|
1255
1256
|
}
|
|
1256
1257
|
// console.log(absolute)
|
|
@@ -13,7 +13,6 @@ const {
|
|
|
13
13
|
forEachMember,
|
|
14
14
|
forEachGeneric,
|
|
15
15
|
isDeprecatedEnabled,
|
|
16
|
-
isBetaEnabled,
|
|
17
16
|
} = require( '../base/model');
|
|
18
17
|
const {
|
|
19
18
|
setLink,
|
|
@@ -43,8 +42,8 @@ function propagate( model ) {
|
|
|
43
42
|
'@cds.external': never,
|
|
44
43
|
'@cds.redirection.target': never,
|
|
45
44
|
'@fiori.draft.enabled': onlyViaArtifact,
|
|
46
|
-
'@': annotation, // always except in 'items'
|
|
47
|
-
doc: annotation, // always except in 'items'
|
|
45
|
+
'@': annotation, // always except in 'items' (and parameters for entity return types)
|
|
46
|
+
doc: annotation, // always except in 'items' (and parameters for entity return types)
|
|
48
47
|
default: withKind, // always except in 'items'
|
|
49
48
|
virtual,
|
|
50
49
|
notNull,
|
|
@@ -74,7 +73,6 @@ function propagate( model ) {
|
|
|
74
73
|
// eslint-disable-next-line max-len
|
|
75
74
|
const oldVirtualNotNullPropagation = isDeprecatedEnabled( options, '_oldVirtualNotNullPropagation' );
|
|
76
75
|
const { warning, throwWithError } = model.$messageFunctions;
|
|
77
|
-
const propagateToReturns = isBetaEnabled( options, 'v4preview' );
|
|
78
76
|
|
|
79
77
|
forEachDefinition( model, run );
|
|
80
78
|
|
|
@@ -157,7 +155,7 @@ function propagate( model ) {
|
|
|
157
155
|
|
|
158
156
|
function step({ target, source }) {
|
|
159
157
|
// console.log('PROPS:',source&&source.name,'->',target.name)
|
|
160
|
-
const viaType = target.type && // TODO: falsy $inferred value instead 'cast'?
|
|
158
|
+
const viaType = target.type && // TODO: falsy $inferred value instead of 'cast'?
|
|
161
159
|
(!target.type.$inferred || target.type.$inferred === 'cast');
|
|
162
160
|
const keys = Object.keys( source );
|
|
163
161
|
for (const prop of keys) {
|
|
@@ -279,13 +277,14 @@ function propagate( model ) {
|
|
|
279
277
|
const from = viewFromPrimary( target )?.path;
|
|
280
278
|
// do not propagate from member / if follow assoc in from or into `returns` of actions (v4)
|
|
281
279
|
if (!(from ? from[from.length - 1]._artifact : source)._main &&
|
|
282
|
-
!(
|
|
280
|
+
!(target._parent && target._parent.returns === target))
|
|
283
281
|
annotation( prop, target, source );
|
|
284
282
|
}
|
|
285
283
|
|
|
286
284
|
function withKind( prop, target, source ) {
|
|
287
|
-
if (target.kind &&
|
|
288
|
-
|
|
285
|
+
if (target.kind === 'param' && source.kind === 'entity')
|
|
286
|
+
return; // Don't propagate from entity types to parameters (+ return type).
|
|
287
|
+
if (target.kind)
|
|
289
288
|
always(prop, target, source); // not in 'items'
|
|
290
289
|
}
|
|
291
290
|
|