@sap/cds-compiler 3.6.2 → 3.8.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 +109 -1
- package/README.md +3 -0
- package/bin/cdsc.js +12 -5
- package/doc/CHANGELOG_ARCHIVE.md +6 -6
- package/doc/CHANGELOG_BETA.md +35 -2
- package/doc/CHANGELOG_DEPRECATED.md +2 -2
- package/doc/DeprecatedOptions_v2.md +1 -1
- package/doc/NameResolution.md +1 -1
- package/lib/api/main.js +63 -23
- package/lib/api/options.js +1 -0
- package/lib/api/validate.js +5 -0
- package/lib/base/dictionaries.js +15 -3
- package/lib/base/keywords.js +2 -0
- package/lib/base/message-registry.js +120 -34
- package/lib/base/messages.js +51 -27
- package/lib/base/model.js +4 -2
- package/lib/base/shuffle.js +2 -1
- package/lib/checks/arrayOfs.js +1 -1
- package/lib/checks/defaultValues.js +1 -1
- package/lib/checks/elements.js +29 -1
- package/lib/checks/{emptyOrOnlyVirtual.js → hasPersistedElements.js} +10 -6
- package/lib/checks/invalidTarget.js +1 -1
- package/lib/checks/nonexpandableStructured.js +1 -1
- package/lib/checks/onConditions.js +15 -9
- package/lib/checks/sql-snippets.js +2 -2
- package/lib/checks/types.js +5 -1
- package/lib/checks/validator.js +7 -3
- package/lib/compiler/assert-consistency.js +42 -26
- package/lib/compiler/base.js +50 -4
- package/lib/compiler/builtins.js +17 -8
- package/lib/compiler/checks.js +241 -246
- package/lib/compiler/define.js +113 -146
- package/lib/compiler/extend.js +889 -383
- package/lib/compiler/finalize-parse-cdl.js +5 -58
- package/lib/compiler/index.js +1 -1
- package/lib/compiler/kick-start.js +7 -8
- package/lib/compiler/populate.js +297 -293
- package/lib/compiler/propagator.js +27 -18
- package/lib/compiler/resolve.js +146 -463
- package/lib/compiler/shared.js +36 -79
- package/lib/compiler/tweak-assocs.js +30 -28
- package/lib/compiler/utils.js +31 -5
- package/lib/edm/annotations/genericTranslation.js +131 -59
- package/lib/edm/annotations/preprocessAnnotations.js +3 -0
- package/lib/edm/csn2edm.js +22 -5
- package/lib/edm/edm.js +6 -4
- package/lib/edm/edmAnnoPreprocessor.js +1 -0
- package/lib/edm/edmPreprocessor.js +42 -26
- package/lib/gen/Dictionary.json +38 -2
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +3 -1
- package/lib/gen/languageLexer.js +1 -1
- package/lib/gen/languageParser.js +4828 -4472
- package/lib/inspect/inspectPropagation.js +20 -34
- package/lib/json/from-csn.js +140 -44
- package/lib/json/to-csn.js +114 -122
- package/lib/language/errorStrategy.js +2 -0
- package/lib/language/genericAntlrParser.js +156 -36
- package/lib/language/language.g4 +100 -58
- package/lib/language/textUtils.js +13 -0
- package/lib/main.d.ts +43 -3
- package/lib/main.js +4 -2
- package/lib/model/csnRefs.js +15 -3
- package/lib/model/csnUtils.js +12 -74
- package/lib/model/revealInternalProperties.js +4 -2
- package/lib/modelCompare/compare.js +2 -1
- package/lib/optionProcessor.js +3 -0
- package/lib/render/manageConstraints.js +5 -2
- package/lib/render/toCdl.js +216 -104
- package/lib/render/toHdbcds.js +2 -9
- package/lib/render/toRename.js +14 -51
- package/lib/render/toSql.js +4 -3
- package/lib/render/utils/common.js +9 -5
- package/lib/transform/braceExpression.js +6 -0
- package/lib/transform/db/assertUnique.js +2 -1
- package/lib/transform/db/expansion.js +2 -0
- package/lib/transform/db/flattening.js +37 -36
- package/lib/transform/db/rewriteCalculatedElements.js +600 -0
- package/lib/transform/db/transformExists.js +4 -0
- package/lib/transform/db/views.js +40 -37
- package/lib/transform/forOdataNew.js +20 -15
- package/lib/transform/forRelationalDB.js +58 -41
- package/lib/transform/odata/typesExposure.js +50 -15
- package/lib/transform/parseExpr.js +16 -8
- package/lib/transform/transformUtilsNew.js +42 -14
- package/lib/transform/translateAssocsToJoins.js +60 -37
- package/lib/transform/universalCsn/coreComputed.js +15 -7
- package/lib/transform/universalCsn/universalCsnEnricher.js +4 -4
- package/package.json +2 -1
package/lib/compiler/shared.js
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
6
|
const { searchName } = require('../base/messages');
|
|
7
|
-
const { dictAddArray } = require('../base/dictionaries');
|
|
8
7
|
const { isDeprecatedEnabled } = require('../base/model');
|
|
9
8
|
|
|
10
9
|
const {
|
|
@@ -183,8 +182,6 @@ function fns( model ) {
|
|
|
183
182
|
resolveUncheckedPath,
|
|
184
183
|
resolveTypeArgumentsUnchecked,
|
|
185
184
|
resolvePath,
|
|
186
|
-
checkAnnotate,
|
|
187
|
-
copyAnnotationsForExtensions,
|
|
188
185
|
attachAndEmitValidNames,
|
|
189
186
|
} );
|
|
190
187
|
return;
|
|
@@ -253,16 +250,12 @@ function fns( model ) {
|
|
|
253
250
|
}
|
|
254
251
|
|
|
255
252
|
function checkSourceRef( art, path ) { // for FROM
|
|
256
|
-
if (art.
|
|
257
|
-
return
|
|
258
|
-
if (art.kind !== 'element')
|
|
259
|
-
return true;
|
|
253
|
+
if (!art._main)
|
|
254
|
+
return (art.kind !== 'entity');
|
|
260
255
|
const elem = path.find( item => item._artifact._main )._artifact;
|
|
261
|
-
//
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
VolatileFns.environment( art ); // sets _effectiveType on art
|
|
265
|
-
return !(art._effectiveType || art).target;
|
|
256
|
+
// at least the last main definition should be an entity
|
|
257
|
+
// an additional check for target would need effectiveType()
|
|
258
|
+
return (elem && elem._main.kind !== 'entity');
|
|
266
259
|
}
|
|
267
260
|
|
|
268
261
|
// Return absolute name for unchecked path `ref`. We first try searching for
|
|
@@ -307,13 +300,12 @@ function fns( model ) {
|
|
|
307
300
|
function resolvePath( ref, expected, user, extDict, msgArt ) {
|
|
308
301
|
if (ref == null) // no references -> nothing to do
|
|
309
302
|
return undefined;
|
|
310
|
-
if (
|
|
303
|
+
if (ref._artifact !== undefined)
|
|
311
304
|
return ref._artifact;
|
|
312
305
|
if (!ref.path || ref.path.broken || !ref.path.length) {
|
|
313
306
|
// incomplete type AST or empty env (already reported)
|
|
314
307
|
return setArtifactLink( ref, undefined );
|
|
315
308
|
}
|
|
316
|
-
setArtifactLink( ref, 0 ); // avoid cycles for type T: association to T.m;
|
|
317
309
|
|
|
318
310
|
let spec = specExpected[expected];
|
|
319
311
|
const { path } = ref;
|
|
@@ -324,10 +316,12 @@ function fns( model ) {
|
|
|
324
316
|
|
|
325
317
|
if (ref.scope === 'param') {
|
|
326
318
|
if (!spec.escape) {
|
|
327
|
-
error( 'ref-unexpected-scope', [ ref.location, user ], {}
|
|
328
|
-
'Unexpected parameter reference' );
|
|
319
|
+
error( 'ref-unexpected-scope', [ ref.location, user ], { '#': 'std' } );
|
|
329
320
|
return setArtifactLink( ref, null );
|
|
330
321
|
}
|
|
322
|
+
if (user.$syntax === 'calc')
|
|
323
|
+
error('ref-unexpected-scope', [ ref.location, user ], { '#': 'calc' } );
|
|
324
|
+
|
|
331
325
|
spec = specExpected[spec.escape];
|
|
332
326
|
// In queries and query entities, the first lexical search environment
|
|
333
327
|
// are the parameters, otherwise the block. It is currently ensured that
|
|
@@ -363,8 +357,12 @@ function fns( model ) {
|
|
|
363
357
|
return setArtifactLink( ref, art );
|
|
364
358
|
}
|
|
365
359
|
else if (!spec.envFn && user._pathHead) {
|
|
366
|
-
if (art.kind === '$self')
|
|
367
|
-
|
|
360
|
+
if (art.kind === '$self') {
|
|
361
|
+
const headEnv = VolatileFns.environment( user._pathHead ) &&
|
|
362
|
+
user._pathHead._origin &&
|
|
363
|
+
VolatileFns.environment( user._pathHead._origin );
|
|
364
|
+
rejectBareSelf( spec, path, user, headEnv );
|
|
365
|
+
}
|
|
368
366
|
}
|
|
369
367
|
else if (art.kind === 'using') {
|
|
370
368
|
const def = model.definitions[art.name.absolute];
|
|
@@ -464,13 +462,13 @@ function fns( model ) {
|
|
|
464
462
|
spec.noDep === 'only-entity' && art.kind !== 'entity')) {
|
|
465
463
|
const { location } = ref; // || combinedLocation( head, path[tail.length] );
|
|
466
464
|
// TODO: location of last path item if not main artifact
|
|
467
|
-
if (
|
|
468
|
-
dependsOn( user, art, location );
|
|
469
|
-
}
|
|
470
|
-
else {
|
|
465
|
+
if (spec.assoc === 'from' && art._main) {
|
|
471
466
|
dependsOn( user, art._main, location );
|
|
472
467
|
VolatileFns.environment( art, location, user );
|
|
473
|
-
|
|
468
|
+
}
|
|
469
|
+
else if (art.kind !== 'select') { // no real dependency to bare $self
|
|
470
|
+
dependsOn( user, art, location );
|
|
471
|
+
// Without on-demand resolve, we can simply signal 'undefined "x"'
|
|
474
472
|
// instead of 'illegal cycle' in the following case:
|
|
475
473
|
// element elem: type of elem.x;
|
|
476
474
|
}
|
|
@@ -599,7 +597,7 @@ function fns( model ) {
|
|
|
599
597
|
// if (head.id === 'k') {console.log(Object.keys(user));
|
|
600
598
|
// throw new CompilerAssertion(JSON.stringify(user.name))}
|
|
601
599
|
// if head._artifact is set or is null then it was already computed once
|
|
602
|
-
if (
|
|
600
|
+
if (head._artifact !== undefined)
|
|
603
601
|
return Array.isArray(head._artifact) ? false : head._artifact;
|
|
604
602
|
// console.log(pathName(path), !spec.next && !extDict &&
|
|
605
603
|
// (spec.useDefinitions || env.$frontend === 'json' || env))
|
|
@@ -617,7 +615,7 @@ function fns( model ) {
|
|
|
617
615
|
break; // TODO: probably remove _$next link
|
|
618
616
|
const e = art.artifacts || art.$tableAliases || Object.create(null);
|
|
619
617
|
const r = e[head.id];
|
|
620
|
-
if (r) {
|
|
618
|
+
if (r && r.$inferred !== '$internal') {
|
|
621
619
|
if (Array.isArray(r)) { // redefinitions
|
|
622
620
|
setArtifactLink( head, r );
|
|
623
621
|
return false;
|
|
@@ -651,11 +649,14 @@ function fns( model ) {
|
|
|
651
649
|
if (r[0].kind === '$navElement' && r.every( e => !e._parent.$duplicates )) {
|
|
652
650
|
// only complain about ambiguous source elements if we do not have
|
|
653
651
|
// duplicate table aliases, only mention non-ambiguous source elems
|
|
654
|
-
const
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
652
|
+
const uniqueNames = r.filter( e => !e.$duplicates);
|
|
653
|
+
if (uniqueNames.length) {
|
|
654
|
+
const names = uniqueNames.filter( e => e._parent.$inferred !== '$internal' )
|
|
655
|
+
.map( e => `${ e.name.alias }.${ e.name.element }` );
|
|
656
|
+
let variant = names.length === uniqueNames.length ? 'std' : 'few';
|
|
657
|
+
if (names.length === 0)
|
|
658
|
+
variant = 'none';
|
|
659
|
+
error( 'ref-ambiguous', [ head.location, user ], { '#': variant, id: head.id, names });
|
|
659
660
|
}
|
|
660
661
|
}
|
|
661
662
|
setArtifactLink( head, r );
|
|
@@ -772,12 +773,13 @@ function fns( model ) {
|
|
|
772
773
|
|
|
773
774
|
const fn = (spec.envFn && artItemsCount >= 0) ? spec.envFn : VolatileFns.environment;
|
|
774
775
|
const env = fn( art, item.location, user, spec.assoc );
|
|
775
|
-
const sub = setArtifactLink( item, env
|
|
776
|
+
const sub = setArtifactLink( item, env?.[item.id] );
|
|
776
777
|
|
|
777
778
|
if (!sub) {
|
|
778
779
|
// element was not found in environment
|
|
779
|
-
|
|
780
|
-
|
|
780
|
+
|
|
781
|
+
// TODO (done?): if `env` was 0, we might set a dependency to induce an
|
|
782
|
+
// illegal-cycle error instead of reporting via `errorNotFound`.
|
|
781
783
|
if (art.$uncheckedElements) { // magic variable / replacement variable
|
|
782
784
|
signalNotFound( 'ref-unknown-var', [ item.location, user ], [ env ],
|
|
783
785
|
{ id: pathName( path ) } );
|
|
@@ -935,7 +937,7 @@ function fns( model ) {
|
|
|
935
937
|
msg.validNames = Object.create( null );
|
|
936
938
|
for (const name of Object.keys( valid )) {
|
|
937
939
|
// ignore internal types such as cds.Association
|
|
938
|
-
if (valid[name].internal || valid[name].deprecated)
|
|
940
|
+
if (valid[name].internal || valid[name].deprecated || valid[name].$inferred === '$internal')
|
|
939
941
|
continue;
|
|
940
942
|
msg.validNames[name] = valid[name];
|
|
941
943
|
}
|
|
@@ -949,51 +951,6 @@ function fns( model ) {
|
|
|
949
951
|
{ std: `Valid: ${ names.sort().join(', ') }`, zero: 'No valid names' });
|
|
950
952
|
}
|
|
951
953
|
}
|
|
952
|
-
|
|
953
|
-
// Issue messages for annotations on namespaces and builtins
|
|
954
|
-
// (TODO: really here?, probably split main artifacts vs returns)
|
|
955
|
-
// see also lateExtensions() where similar messages are reported
|
|
956
|
-
function checkAnnotate( construct, art ) {
|
|
957
|
-
// TODO: Handle extend statements properly: Different message for empty extend?
|
|
958
|
-
|
|
959
|
-
// Namespaces cannot be annotated in CSN but because they exist as XSN artifacts
|
|
960
|
-
// they can still be applied. Namespace annotations are extracted in to-csn.js
|
|
961
|
-
// In parseCdl mode USINGs and other unknown references are generated as
|
|
962
|
-
// namespaces which would lead to false positives.
|
|
963
|
-
// TODO: should this really be different to annotate-unknown?
|
|
964
|
-
if (art.kind === 'namespace') {
|
|
965
|
-
info( 'anno-namespace', [ construct.name.location, construct ], {},
|
|
966
|
-
'Namespaces can\'t be annotated' );
|
|
967
|
-
}
|
|
968
|
-
// Builtin annotations would also get lost. Same as for namespaces:
|
|
969
|
-
// extracted in to-csn.js
|
|
970
|
-
else if (art.builtin === true) {
|
|
971
|
-
info( 'anno-builtin', [ construct.name.location, construct ], {},
|
|
972
|
-
'Builtin types should not be annotated. Use custom type instead' );
|
|
973
|
-
}
|
|
974
|
-
else if (construct.$syntax === 'returns' && art._block && art.kind !== 'action' &&
|
|
975
|
-
art.kind !== 'function' ) {
|
|
976
|
-
// `annotate ABC with returns {}` is handled just like `elements`. Warn if it is used
|
|
977
|
-
// for non-actions. We can't only check for !art.returns, because `action A();` is valid.
|
|
978
|
-
// `art._block` ensures that `art` is a defined def.
|
|
979
|
-
warning('anno-unexpected-returns', [ construct.name.location, construct ],
|
|
980
|
-
{ keyword: 'returns', meta: art.kind }, 'Unexpected $(KEYWORD) for $(META)');
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
// Copy annotations from `ext` to `art`, overwriting inferred ones.
|
|
985
|
-
// TODO: move to extend.js if not used anymore in define.js
|
|
986
|
-
function copyAnnotationsForExtensions( ext, art ) {
|
|
987
|
-
for (const annoProp in ext) {
|
|
988
|
-
if (annoProp.charAt(0) === '@' || annoProp === 'doc') {
|
|
989
|
-
const extAnno = ext[annoProp];
|
|
990
|
-
if (art[annoProp]?.$inferred)
|
|
991
|
-
art[annoProp] = extAnno; // overwrite $inferred annos
|
|
992
|
-
else
|
|
993
|
-
dictAddArray( art, annoProp, extAnno );
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
954
|
}
|
|
998
955
|
|
|
999
956
|
module.exports = {
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
5
5
|
const {
|
|
6
|
-
forEachDefinition,
|
|
7
6
|
forEachGeneric,
|
|
8
7
|
forEachInOrder,
|
|
9
8
|
} = require('../base/model');
|
|
@@ -31,19 +30,13 @@ function tweakAssocs( model ) {
|
|
|
31
30
|
} = model.$messageFunctions;
|
|
32
31
|
const {
|
|
33
32
|
effectiveType,
|
|
34
|
-
|
|
33
|
+
getOrigin,
|
|
35
34
|
resolveExpr,
|
|
36
35
|
} = model.$functions;
|
|
37
36
|
const { environment } = model.$volatileFunctions;
|
|
38
37
|
|
|
39
38
|
// Phase 5: rewrite associations
|
|
40
|
-
|
|
41
|
-
// TODO: sequence not good enough with derived type of structure with
|
|
42
|
-
// includes: first "direct" structures, then _entities, then the rest.
|
|
43
|
-
// v2: We might run a silent cycle detection earlier, then we could use the
|
|
44
|
-
// SCC number (_scc.lowlink) to sort.
|
|
45
|
-
model._entities.forEach( rewriteView );
|
|
46
|
-
model._entities.forEach( rewriteViewCheck );
|
|
39
|
+
model._entities.forEach( rewriteArtifact );
|
|
47
40
|
// Think hard whether an on condition rewrite can lead to a new cylcic
|
|
48
41
|
// dependency. If so, we need other messages anyway. TODO: probably do
|
|
49
42
|
// another cyclic check with testMode.js
|
|
@@ -55,33 +48,41 @@ function tweakAssocs( model ) {
|
|
|
55
48
|
//--------------------------------------------------------------------------
|
|
56
49
|
// Only top-level queries and sub queries in FROM
|
|
57
50
|
|
|
58
|
-
function
|
|
51
|
+
function rewriteArtifact( art ) {
|
|
59
52
|
// return;
|
|
60
|
-
if (!art.
|
|
53
|
+
if (!art.query) {
|
|
61
54
|
// console.log(message( null, art.location, art, {target:art._target},
|
|
62
55
|
// 'Info','RAS').toString())
|
|
63
56
|
rewriteAssociation( art );
|
|
64
57
|
forEachGeneric( art, 'elements', rewriteAssociation );
|
|
65
58
|
}
|
|
59
|
+
else {
|
|
60
|
+
traverseQueryExtra( art, ( query ) => {
|
|
61
|
+
forEachGeneric( query, 'elements', rewriteAssociation );
|
|
62
|
+
} );
|
|
63
|
+
}
|
|
66
64
|
if (art._service)
|
|
67
65
|
forEachGeneric( art, 'elements', excludeAssociation );
|
|
68
|
-
}
|
|
69
66
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
forEachGeneric( query, 'elements', rewriteAssociation );
|
|
67
|
+
traverseQueryPost( art.query, false, ( query ) => {
|
|
68
|
+
forEachGeneric( query, 'elements', rewriteAssociationCheck );
|
|
73
69
|
} );
|
|
74
|
-
if (view.includes) // entities with structure includes:
|
|
75
|
-
forEachGeneric( view, 'elements', rewriteAssociation );
|
|
76
70
|
}
|
|
77
71
|
|
|
72
|
+
// function rewriteView( view ) {
|
|
73
|
+
// // TODO: we could sort according to the $effectiveSeqNo instead
|
|
74
|
+
// // (and then remove traverseQueryExtra)
|
|
75
|
+
// if (view.includes) // entities with structure includes:
|
|
76
|
+
// forEachGeneric( view, 'elements', rewriteAssociation );
|
|
77
|
+
// }
|
|
78
|
+
|
|
78
79
|
// Check explicit ON / keys with REDIRECTED TO
|
|
79
80
|
// TODO: run on all queries, but this is potentially incompatible
|
|
80
|
-
function rewriteViewCheck( view ) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
81
|
+
// function rewriteViewCheck( view ) {
|
|
82
|
+
// traverseQueryPost( view.query, false, ( query ) => {
|
|
83
|
+
// forEachGeneric( query, 'elements', rewriteAssociationCheck );
|
|
84
|
+
// } );
|
|
85
|
+
// }
|
|
85
86
|
|
|
86
87
|
function excludeAssociation( elem ) {
|
|
87
88
|
const target = elem.target && elem.target._artifact;
|
|
@@ -112,7 +113,7 @@ function tweakAssocs( model ) {
|
|
|
112
113
|
if (!elem.target)
|
|
113
114
|
return;
|
|
114
115
|
if (elem.on && !elem.on.$inferred) {
|
|
115
|
-
const assoc =
|
|
116
|
+
const assoc = getOrigin( elem );
|
|
116
117
|
if (assoc && assoc.foreignKeys) {
|
|
117
118
|
error( 'rewrite-key-for-unmanaged', [ elem.on.location, elem ],
|
|
118
119
|
{ keyword: 'on', art: assocWithExplicitSpec( assoc ) },
|
|
@@ -121,7 +122,7 @@ function tweakAssocs( model ) {
|
|
|
121
122
|
}
|
|
122
123
|
}
|
|
123
124
|
else if (elem.foreignKeys && !inferredForeignKeys( elem.foreignKeys )) {
|
|
124
|
-
const assoc =
|
|
125
|
+
const assoc = getOrigin( elem );
|
|
125
126
|
if (assoc && assoc.on) {
|
|
126
127
|
error( 'rewrite-on-for-managed',
|
|
127
128
|
[ elem.foreignKeys[$location] || dictLocation( elem.foreignKeys ), elem ],
|
|
@@ -195,7 +196,7 @@ function tweakAssocs( model ) {
|
|
|
195
196
|
function assocWithExplicitSpec( assoc ) {
|
|
196
197
|
while (assoc.foreignKeys && inferredForeignKeys( assoc.foreignKeys, 'keys') ||
|
|
197
198
|
assoc.on && assoc.on.$inferred)
|
|
198
|
-
assoc =
|
|
199
|
+
assoc = getOrigin( assoc );
|
|
199
200
|
return assoc;
|
|
200
201
|
}
|
|
201
202
|
|
|
@@ -211,6 +212,7 @@ function tweakAssocs( model ) {
|
|
|
211
212
|
// With cyclic dependencies on select items, testing for the _effectiveType to
|
|
212
213
|
// be 0 (test above) is not enough if we we have an explicit redirection
|
|
213
214
|
// target -> avoid infloop ourselves with _status.
|
|
215
|
+
// TODO: this should be good now
|
|
214
216
|
const chain = [];
|
|
215
217
|
while (!elem.on && !elem.foreignKeys) {
|
|
216
218
|
chain.push( elem );
|
|
@@ -220,7 +222,7 @@ function tweakAssocs( model ) {
|
|
|
220
222
|
return;
|
|
221
223
|
}
|
|
222
224
|
setLink( elem, '_status', 'rewrite' );
|
|
223
|
-
elem =
|
|
225
|
+
elem = getOrigin( elem );
|
|
224
226
|
if (!elem || elem.builtin) // safety
|
|
225
227
|
return;
|
|
226
228
|
}
|
|
@@ -236,7 +238,7 @@ function tweakAssocs( model ) {
|
|
|
236
238
|
}
|
|
237
239
|
|
|
238
240
|
function originTarget( elem ) {
|
|
239
|
-
const assoc = !elem.expand &&
|
|
241
|
+
const assoc = !elem.expand && getOrigin( elem );
|
|
240
242
|
const ftype = assoc && effectiveType( assoc );
|
|
241
243
|
return ftype && ftype.target && ftype.target._artifact;
|
|
242
244
|
}
|
|
@@ -254,7 +256,7 @@ function tweakAssocs( model ) {
|
|
|
254
256
|
const fk = linkToOrigin( orig, name, elem, 'foreignKeys', elem.location );
|
|
255
257
|
fk.$inferred = 'rewrite'; // Override existing value; TODO: other $inferred value?
|
|
256
258
|
// TODO: re-check for case that foreign key is managed association
|
|
257
|
-
if (
|
|
259
|
+
if (orig._effectiveType !== undefined)
|
|
258
260
|
setLink( fk, '_effectiveType', orig._effectiveType);
|
|
259
261
|
const te = copyExpr( orig.targetElement, elem.location );
|
|
260
262
|
if (elem._redirected) {
|
package/lib/compiler/utils.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
'use strict';
|
|
12
12
|
|
|
13
|
-
const { dictAdd, pushToDict } = require('../base/dictionaries');
|
|
13
|
+
const { dictAdd, pushToDict, dictFirst } = require('../base/dictionaries');
|
|
14
14
|
const { kindProperties } = require('./base');
|
|
15
15
|
|
|
16
16
|
// for links, i.e., properties starting with an underscore '_':
|
|
@@ -55,7 +55,7 @@ function annotationLocation( anno ) {
|
|
|
55
55
|
* @param {*} [val]
|
|
56
56
|
* @param {string} [literal]
|
|
57
57
|
*/
|
|
58
|
-
function
|
|
58
|
+
function setAnnotation( art, anno, location = art.location, val = true, literal = 'boolean' ) {
|
|
59
59
|
if (art[anno]) // do not overwrite user-defined including null
|
|
60
60
|
return;
|
|
61
61
|
art[anno] = {
|
|
@@ -71,10 +71,11 @@ function annotateWith( art, anno, location = art.location, val = true, literal =
|
|
|
71
71
|
|
|
72
72
|
// The link (_artifact,_effectiveType,...) usually has the artifact as value.
|
|
73
73
|
// Falsy values are:
|
|
74
|
-
// - undefined: not computed yet, parse error, no ref
|
|
75
|
-
// - null:
|
|
74
|
+
// - undefined: not computed yet, parse error (TODO: null), no ref
|
|
75
|
+
// - null: ref to unknown, param:true if that is not allowed (TODO: false)
|
|
76
76
|
// - false (only complete ref): multiple definitions, rejected
|
|
77
77
|
// - 0 (for _effectiveType only): circular reference
|
|
78
|
+
// - '' (for _origin only): no origin provided
|
|
78
79
|
function setLink( obj, prop, value ) {
|
|
79
80
|
Object.defineProperty( obj, prop, { value, configurable: true, writable: true } );
|
|
80
81
|
return value;
|
|
@@ -105,6 +106,20 @@ function linkToOrigin( origin, name, parent, prop, location, silentDep ) {
|
|
|
105
106
|
return elem;
|
|
106
107
|
}
|
|
107
108
|
|
|
109
|
+
function proxyCopyMembers( art, dictProp, originDict, location, kind ) {
|
|
110
|
+
art[dictProp] = Object.create( null );
|
|
111
|
+
for (const name in originDict) {
|
|
112
|
+
const origin = originDict[name];
|
|
113
|
+
const member = linkToOrigin( origin, name, art, dictProp,
|
|
114
|
+
location || origin.location, true );
|
|
115
|
+
member.$inferred = 'expanded';
|
|
116
|
+
if (kind)
|
|
117
|
+
member.kind = kind;
|
|
118
|
+
if (kind && origin.masked) // TODO: remove!
|
|
119
|
+
member.masked = Object.assign( { $inferred: 'nav' }, origin.masked );
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
108
123
|
/**
|
|
109
124
|
* Set the member `elem` to have a _parent link to `parent` and a corresponding
|
|
110
125
|
* _main link. Also set the member's name accordingly, where argument `name`
|
|
@@ -370,6 +385,15 @@ function traverseQueryExtra( main, callback ) {
|
|
|
370
385
|
}
|
|
371
386
|
}
|
|
372
387
|
|
|
388
|
+
// Returns what was available at view._from[0] before:
|
|
389
|
+
// (think first whether to really use this function)
|
|
390
|
+
function viewFromPrimary( view ) {
|
|
391
|
+
let query = view.$queries?.[0];
|
|
392
|
+
while (query?._origin?.kind === 'select') // sub query in from
|
|
393
|
+
query = query._origin;
|
|
394
|
+
return dictFirst( query?.$tableAliases );
|
|
395
|
+
}
|
|
396
|
+
|
|
373
397
|
// About Helper property $expand for faster the XSN-to-CSN transformation
|
|
374
398
|
// - null/undefined: artifact, member, items does not contain expanded members
|
|
375
399
|
// - 'origin': all expanded (sub) elements have no new target/on and no new annotations
|
|
@@ -424,10 +448,11 @@ module.exports = {
|
|
|
424
448
|
annotationIsFalse,
|
|
425
449
|
annotationHasEllipsis,
|
|
426
450
|
annotationLocation,
|
|
427
|
-
|
|
451
|
+
setAnnotation,
|
|
428
452
|
setLink,
|
|
429
453
|
setArtifactLink,
|
|
430
454
|
linkToOrigin,
|
|
455
|
+
proxyCopyMembers,
|
|
431
456
|
dependsOn,
|
|
432
457
|
dependsOnSilent,
|
|
433
458
|
setMemberParent,
|
|
@@ -441,6 +466,7 @@ module.exports = {
|
|
|
441
466
|
targetMaxNotOne,
|
|
442
467
|
traverseQueryPost,
|
|
443
468
|
traverseQueryExtra,
|
|
469
|
+
viewFromPrimary,
|
|
444
470
|
setExpandStatus,
|
|
445
471
|
setExpandStatusAnnotate,
|
|
446
472
|
isDirectComposition,
|