@sap/cds-compiler 6.6.0 → 6.7.1
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 +34 -1
- package/bin/cdsc.js +2 -0
- package/bin/cdsse.js +1 -1
- package/lib/base/message-registry.js +6 -7
- package/lib/base/model.js +0 -72
- package/lib/checks/elements.js +1 -1
- package/lib/checks/featureFlags.js +2 -2
- package/lib/compiler/assert-consistency.js +3 -4
- package/lib/compiler/base.js +8 -0
- package/lib/compiler/builtins.js +8 -9
- package/lib/compiler/checks.js +27 -6
- package/lib/compiler/cycle-detector.js +4 -4
- package/lib/compiler/define.js +65 -83
- package/lib/compiler/extend.js +357 -325
- package/lib/compiler/finalize-parse-cdl.js +3 -4
- package/lib/compiler/generate.js +205 -203
- package/lib/compiler/kick-start.js +34 -49
- package/lib/compiler/populate.js +95 -28
- package/lib/compiler/propagator.js +3 -5
- package/lib/compiler/resolve.js +17 -13
- package/lib/compiler/shared.js +47 -19
- package/lib/compiler/tweak-assocs.js +2 -4
- package/lib/compiler/utils.js +84 -31
- package/lib/gen/BaseParser.js +924 -1055
- package/lib/gen/CdlGrammar.checksum +1 -1
- package/lib/gen/CdlParser.js +5 -2
- package/lib/json/from-csn.js +25 -16
- package/lib/main.d.ts +13 -0
- package/lib/model/revealInternalProperties.js +18 -0
- package/lib/parsers/AstBuildingParser.js +22 -5
- package/lib/render/toHdbcds.js +2 -2
- package/lib/render/utils/sql.js +2 -2
- package/lib/render/utils/standardDatabaseFunctions.js +2 -2
- package/lib/transform/db/constraints.js +3 -4
- package/lib/transform/db/killAnnotations.js +1 -1
- package/lib/transform/db/processSqlServices.js +10 -11
- package/lib/transform/effective/associations.js +1 -1
- package/lib/transform/forOdata.js +7 -124
- package/lib/transform/odata/fioriTreeViews.js +173 -0
- package/lib/transform/odata/flattening.js +2 -2
- package/lib/transform/translateAssocsToJoins.js +7 -4
- package/package.json +1 -1
- package/share/messages/message-explanations.json +0 -2
- package/share/messages/type-unexpected-foreign-keys.md +0 -52
- package/share/messages/type-unexpected-on-condition.md +0 -52
package/lib/compiler/define.js
CHANGED
|
@@ -120,17 +120,13 @@
|
|
|
120
120
|
|
|
121
121
|
'use strict';
|
|
122
122
|
|
|
123
|
-
const {
|
|
124
|
-
|
|
125
|
-
forEachInOrder,
|
|
126
|
-
forEachMember,
|
|
127
|
-
} = require('../base/model');
|
|
128
|
-
const { weakLocation } = require('../base/location');
|
|
123
|
+
const { weakLocation, builtinLocation } = require('../base/location');
|
|
124
|
+
|
|
129
125
|
const shuffleGen = require('../base/shuffle');
|
|
130
126
|
const {
|
|
131
127
|
dictAdd, dictAddArray, dictForEach, pushToDict,
|
|
132
128
|
} = require('../base/dictionaries');
|
|
133
|
-
const { kindProperties
|
|
129
|
+
const { kindProperties } = require('./base');
|
|
134
130
|
const {
|
|
135
131
|
setLink,
|
|
136
132
|
initItemsLinks,
|
|
@@ -142,14 +138,14 @@ const {
|
|
|
142
138
|
initBoundSelfParam,
|
|
143
139
|
dependsOnSilent,
|
|
144
140
|
pathName,
|
|
145
|
-
|
|
141
|
+
forEachGeneric,
|
|
142
|
+
forEachInOrder,
|
|
146
143
|
} = require('./utils');
|
|
147
144
|
const { compareLayer } = require('./moduleLayers');
|
|
148
145
|
const { initBuiltins } = require('./builtins');
|
|
149
146
|
const { isInReservedNamespace } = require('../base/builtins');
|
|
150
147
|
|
|
151
148
|
const $location = Symbol.for( 'cds.$location' );
|
|
152
|
-
const $inferred = Symbol.for( 'cds.$inferred' );
|
|
153
149
|
|
|
154
150
|
/**
|
|
155
151
|
* Export function of this file. Transform argument `sources` = dictionary of
|
|
@@ -178,10 +174,9 @@ function define( model ) {
|
|
|
178
174
|
shuffleDict,
|
|
179
175
|
shuffleArray,
|
|
180
176
|
initMainArtifact,
|
|
181
|
-
|
|
182
|
-
targetIsTargetAspect,
|
|
177
|
+
initArtifactParentLink,
|
|
183
178
|
checkRedefinition,
|
|
184
|
-
|
|
179
|
+
createGapArtifact,
|
|
185
180
|
} );
|
|
186
181
|
return doDefine();
|
|
187
182
|
|
|
@@ -200,7 +195,6 @@ function define( model ) {
|
|
|
200
195
|
}
|
|
201
196
|
model.definitions = Object.create( null );
|
|
202
197
|
setLink( model, '_entities', [] ); // for entities with includes
|
|
203
|
-
model.$entity = 0;
|
|
204
198
|
model.$compositionTargets = Object.create( null );
|
|
205
199
|
model.$collectedExtensions = Object.create( null );
|
|
206
200
|
|
|
@@ -404,7 +398,7 @@ function define( model ) {
|
|
|
404
398
|
const absolute = ext.name && resolveUncheckedPath( ext.name, '_uncheckedExtension', ext );
|
|
405
399
|
if (!absolute) // broken path
|
|
406
400
|
return;
|
|
407
|
-
delete ext.name.path[0]._artifact; // might point to wrong JS object in phase 1
|
|
401
|
+
delete ext.name.path[0]._artifact; // might point to wrong JS object in phase 1 - TODO: still?
|
|
408
402
|
ext.name.id = absolute; // definition might not be there yet, no _artifact link
|
|
409
403
|
const location = { file: '' }; // stupid required location
|
|
410
404
|
const late = model.$collectedExtensions[absolute] ||
|
|
@@ -529,12 +523,13 @@ function define( model ) {
|
|
|
529
523
|
initArtifactParentLink( art, model.definitions );
|
|
530
524
|
checkRedefinition( art );
|
|
531
525
|
initDollarSelf( art ); // $self, TODO: also for 'namespace'?
|
|
532
|
-
initMembers( art );
|
|
533
526
|
if (art.params)
|
|
534
527
|
initDollarParameters( art ); // $parameters
|
|
528
|
+
initMembers( art );
|
|
529
|
+
|
|
535
530
|
if (art.query) {
|
|
536
531
|
initArtifactQuery( art );
|
|
537
|
-
restrictToSimpleProjection( art );
|
|
532
|
+
restrictToSimpleProjection( art ); // late syntax check, TODO: do in parsers
|
|
538
533
|
}
|
|
539
534
|
}
|
|
540
535
|
|
|
@@ -551,38 +546,23 @@ function define( model ) {
|
|
|
551
546
|
}
|
|
552
547
|
|
|
553
548
|
function initExtension( parent ) {
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
sub.name = { id: '', location: sub.location };
|
|
560
|
-
setLink( sub, '_block', parent._block );
|
|
561
|
-
initExprAnnoBlock( sub, parent._block );
|
|
562
|
-
setLink( sub, '_parent', parent );
|
|
563
|
-
setLink( sub, '_main', parent._main || parent );
|
|
564
|
-
initExtension( sub );
|
|
565
|
-
} );
|
|
566
|
-
if (parent.kind !== 'extend')
|
|
567
|
-
return;
|
|
568
|
-
// TODO: sub queries? expand/inline?
|
|
569
|
-
parent.columns?.forEach( c => setLink( c, '_block', parent._block ) );
|
|
570
|
-
if (parent.scale && !parent.precision) {
|
|
571
|
-
// TODO: where could we store the location of the name?
|
|
572
|
-
error( 'syntax-missing-type-property', [ parent.scale.location ],
|
|
573
|
-
{ prop: 'scale', otherprop: 'precision' },
|
|
574
|
-
'Type extension with property $(PROP) must also have property $(OTHERPROP)' );
|
|
575
|
-
parent.scale = undefined; // no consequential error
|
|
576
|
-
}
|
|
549
|
+
initMembers( parent );
|
|
550
|
+
if (parent.columns)
|
|
551
|
+
initSelectItems( parent, parent.columns, parent, true );
|
|
552
|
+
// there are no sub queries in extensions yet
|
|
553
|
+
// Remark: sub queries not yet allowed in `extend … with columns`
|
|
577
554
|
}
|
|
578
555
|
|
|
556
|
+
//-----------------------------------------------------------------------------
|
|
557
|
+
|
|
579
558
|
/**
|
|
580
559
|
* Make the `_parent` pointer of artifact `A.B.C` point to `A.B`. If no `A.B`
|
|
581
560
|
* exists in XSN.definitions, create an artifact with kind `namespace` (better
|
|
582
|
-
* would be `$gap`). Add `A.B.C` to the `_subArtifacts` dictionary of `A.B
|
|
561
|
+
* would be `$gap`). Add `A.B.C` to the `_subArtifacts` dictionary of `A.B`
|
|
562
|
+
* if `noSubArtifacts` is not truthy (not for gap artifacts).
|
|
583
563
|
* Do recursively if necessary, `_parent` of `A.B` is `A` in this example.
|
|
584
564
|
*/
|
|
585
|
-
function initArtifactParentLink( art, definitions, path, pathIndex ) {
|
|
565
|
+
function initArtifactParentLink( art, definitions, path, pathIndex, noSubArtifacts ) {
|
|
586
566
|
setLink( art, '_parent', null );
|
|
587
567
|
const { id } = art.name;
|
|
588
568
|
const dot = id.lastIndexOf( '.' );
|
|
@@ -592,7 +572,7 @@ function define( model ) {
|
|
|
592
572
|
let parent = definitions[prefix];
|
|
593
573
|
if (!parent) {
|
|
594
574
|
path ??= art.name.path;
|
|
595
|
-
pathIndex ??= path?.length - 1;
|
|
575
|
+
pathIndex ??= path?.length - 1; // just used for location
|
|
596
576
|
const pathItemOrName = (path && pathIndex) ? path[--pathIndex] : art.name;
|
|
597
577
|
const location = weakLocation( pathItemOrName.location );
|
|
598
578
|
parent = { kind: 'namespace', name: { id: prefix, location }, location };
|
|
@@ -600,6 +580,8 @@ function define( model ) {
|
|
|
600
580
|
initArtifactParentLink( parent, definitions, path, pathIndex );
|
|
601
581
|
}
|
|
602
582
|
setLink( art, '_parent', parent );
|
|
583
|
+
if (noSubArtifacts)
|
|
584
|
+
return;
|
|
603
585
|
if (!parent._subArtifacts)
|
|
604
586
|
setLink( parent, '_subArtifacts', Object.create( null ) );
|
|
605
587
|
if (art.$duplicates !== true) // no redef or "first def"
|
|
@@ -1059,29 +1041,31 @@ function define( model ) {
|
|
|
1059
1041
|
/**
|
|
1060
1042
|
* Set property `_parent` for all elements in `parent` to `parent` and do so
|
|
1061
1043
|
* recursively for all sub elements.
|
|
1062
|
-
*
|
|
1063
|
-
* Param `initExtensions` is for parse.cdl - TODO delete
|
|
1064
1044
|
*/
|
|
1065
1045
|
function initMembers( parent ) {
|
|
1046
|
+
// TODO: combine with initMembers() - better structuring
|
|
1066
1047
|
const block = parent._block;
|
|
1067
|
-
let obj = initItemsLinks( parent, block );
|
|
1068
1048
|
initExprAnnoBlock( parent, block );
|
|
1069
|
-
|
|
1049
|
+
const obj = initItemsLinks( parent, block ); // down many / array of
|
|
1050
|
+
|
|
1051
|
+
if (obj.scale && !obj.precision &&
|
|
1052
|
+
(parent._main || parent).kind === 'extend') { // TODO v7: why just with extend?
|
|
1053
|
+
// TODO: where could we store the location of the name?
|
|
1054
|
+
error( 'syntax-missing-type-property', [ obj.scale.location ],
|
|
1055
|
+
{ prop: 'scale', otherprop: 'precision' },
|
|
1056
|
+
'Type extension with property $(PROP) must also have property $(OTHERPROP)' );
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
if (obj.target?.elements) {
|
|
1060
|
+
// in kick-start.js, we consider a target refererence to an aspect
|
|
1070
1061
|
obj.targetAspect = obj.target;
|
|
1071
1062
|
delete obj.target;
|
|
1072
1063
|
}
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
}
|
|
1079
|
-
if (obj.on && !obj.target) {
|
|
1080
|
-
error( 'type-unexpected-on-condition', [ obj.on.location, parent ] );
|
|
1081
|
-
delete obj.on; // continuation semantics: not specified
|
|
1082
|
-
}
|
|
1083
|
-
if (targetAspect.elements) // eslint-disable-next-line no-multi-assign
|
|
1084
|
-
parent = obj = initAnonymousAspect( parent, obj, targetAspect );
|
|
1064
|
+
if (obj.targetAspect?.elements) {
|
|
1065
|
+
initAnonymousAspect( parent, obj, obj.targetAspect );
|
|
1066
|
+
forEachInOrder( obj.targetAspect, 'elements',
|
|
1067
|
+
(...args) => initArtifact( obj.targetAspect, ...args ) );
|
|
1068
|
+
return;
|
|
1085
1069
|
}
|
|
1086
1070
|
forEachInOrder( obj, 'elements', (...args) => initArtifact( parent, ...args ) );
|
|
1087
1071
|
forEachGeneric( obj, 'enum', (...args) => initArtifact( parent, ...args ) );
|
|
@@ -1107,7 +1091,7 @@ function define( model ) {
|
|
|
1107
1091
|
|
|
1108
1092
|
targetAspect.kind = 'aspect'; // TODO: probably '$aspect' to detect
|
|
1109
1093
|
setLink( targetAspect, '_block', parent._block );
|
|
1110
|
-
initDollarSelf( targetAspect );
|
|
1094
|
+
initDollarSelf( targetAspect ); // not with extend
|
|
1111
1095
|
// allow ref of up_ in anonymous aspect inside entity
|
|
1112
1096
|
// (TODO: complain if used and the managed composition is included into
|
|
1113
1097
|
// another entity - might induce auto-redirection):
|
|
@@ -1131,9 +1115,8 @@ function define( model ) {
|
|
|
1131
1115
|
return targetAspect;
|
|
1132
1116
|
}
|
|
1133
1117
|
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
elem.kind = dictKinds[prop];
|
|
1118
|
+
// TODO: combine with initMembers()
|
|
1119
|
+
function initArtifact( parent, elem, name ) {
|
|
1137
1120
|
if (!elem.name && !elem._outer) {
|
|
1138
1121
|
const ref = elem.targetElement || elem.kind === 'element' && elem.value;
|
|
1139
1122
|
if (ref && ref.path) {
|
|
@@ -1157,9 +1140,9 @@ function define( model ) {
|
|
|
1157
1140
|
|
|
1158
1141
|
// for a correct home path, setMemberParent needed to be called
|
|
1159
1142
|
|
|
1160
|
-
if (!elem.value || elem.kind !== 'element' ||
|
|
1161
|
-
|
|
1162
|
-
|
|
1143
|
+
if (!elem.value || elem.kind !== 'element' || elem.$syntax === 'or-enum')
|
|
1144
|
+
return; // not an element with value
|
|
1145
|
+
// remark: $syntax: 'or-enum' is set in CDL+CSN parser for potential enums
|
|
1163
1146
|
// -> it's a calculated element
|
|
1164
1147
|
if (!elem.type && elem.value.type) { // top-level CAST( expr AS type )
|
|
1165
1148
|
if (!elem.target)
|
|
@@ -1180,25 +1163,24 @@ function define( model ) {
|
|
|
1180
1163
|
}
|
|
1181
1164
|
|
|
1182
1165
|
/**
|
|
1183
|
-
*
|
|
1166
|
+
* Create "gap" artifact (kind: "namespace") for references which might turn out
|
|
1167
|
+
* to refer to a compiler-generated texts or target entity later.
|
|
1168
|
+
*
|
|
1169
|
+
* A _parent link is set as usual, but the parent does not list the gap artifact
|
|
1170
|
+
* in its _subArtifacts (to allow more precise and processing
|
|
1171
|
+
* sequence-independent resolve errors). When the gap artifact is replaced by
|
|
1172
|
+
* the generated entity, it is added to the _subArtifacts of the parent.
|
|
1184
1173
|
*/
|
|
1185
|
-
function
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
return false;
|
|
1196
|
-
// Compare this check with check in acceptEntity() called by resolvePath()
|
|
1197
|
-
// Remark: do not check `on` and `foreignKeys` here, we want error for those, not the aspect
|
|
1198
|
-
const name = resolveUncheckedPath( target, 'target', elem );
|
|
1199
|
-
const aspect = name && model.definitions[name];
|
|
1200
|
-
return (aspect?.kind === 'aspect' || aspect?.kind === 'type') && // type is sloppy
|
|
1201
|
-
aspect.elements && !aspect.elements[$inferred];
|
|
1174
|
+
function createGapArtifact( name, location = builtinLocation() ) {
|
|
1175
|
+
// TODO: make it work without location (or value undefined/null)
|
|
1176
|
+
const art = {
|
|
1177
|
+
kind: 'namespace', name: { id: name, location }, location,
|
|
1178
|
+
};
|
|
1179
|
+
model.definitions[name] = art;
|
|
1180
|
+
// set _parent link, but do not add in _subArtifacts
|
|
1181
|
+
// (TODO: in the future, test better for "valid" completion, and add anyway.)
|
|
1182
|
+
initArtifactParentLink( art, model.definitions, undefined, undefined, true );
|
|
1183
|
+
return art;
|
|
1202
1184
|
}
|
|
1203
1185
|
}
|
|
1204
1186
|
|