@sap/cds-compiler 3.6.0 → 3.7.2
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 +58 -0
- package/README.md +3 -0
- package/bin/cdsc.js +9 -5
- package/doc/CHANGELOG_BETA.md +20 -2
- package/doc/CHANGELOG_DEPRECATED.md +2 -2
- package/lib/api/main.js +2 -1
- package/lib/api/options.js +3 -2
- package/lib/base/dictionaries.js +10 -0
- package/lib/base/message-registry.js +56 -12
- package/lib/base/messages.js +39 -20
- package/lib/base/model.js +1 -0
- package/lib/base/shuffle.js +2 -1
- package/lib/checks/elements.js +29 -1
- package/lib/checks/{emptyOrOnlyVirtual.js → hasPersistedElements.js} +9 -5
- package/lib/checks/nonexpandableStructured.js +1 -1
- package/lib/checks/onConditions.js +8 -5
- package/lib/checks/types.js +6 -1
- package/lib/checks/validator.js +7 -3
- package/lib/compiler/assert-consistency.js +20 -23
- package/lib/compiler/base.js +1 -2
- package/lib/compiler/builtins.js +2 -2
- package/lib/compiler/checks.js +237 -242
- package/lib/compiler/define.js +63 -75
- package/lib/compiler/extend.js +325 -22
- package/lib/compiler/finalize-parse-cdl.js +1 -55
- package/lib/compiler/kick-start.js +6 -7
- package/lib/compiler/populate.js +284 -288
- package/lib/compiler/propagator.js +15 -13
- package/lib/compiler/resolve.js +136 -306
- package/lib/compiler/shared.js +42 -44
- package/lib/compiler/tweak-assocs.js +29 -27
- package/lib/compiler/utils.js +29 -3
- package/lib/edm/annotations/genericTranslation.js +7 -13
- package/lib/edm/annotations/preprocessAnnotations.js +3 -0
- package/lib/edm/csn2edm.js +0 -4
- package/lib/edm/edm.js +6 -4
- package/lib/edm/edmAnnoPreprocessor.js +1 -0
- package/lib/edm/edmPreprocessor.js +1 -5
- package/lib/gen/Dictionary.json +34 -2
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +2429 -2401
- package/lib/inspect/inspectPropagation.js +2 -0
- package/lib/json/from-csn.js +87 -41
- package/lib/json/to-csn.js +47 -16
- package/lib/language/errorStrategy.js +1 -0
- package/lib/language/genericAntlrParser.js +109 -28
- package/lib/language/language.g4 +20 -4
- package/lib/model/csnRefs.js +30 -2
- package/lib/model/csnUtils.js +1 -0
- package/lib/model/revealInternalProperties.js +1 -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 +20 -7
- package/lib/render/toHdbcds.js +2 -8
- package/lib/render/toSql.js +6 -5
- package/lib/render/utils/common.js +9 -5
- 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 +559 -0
- package/lib/transform/db/transformExists.js +15 -6
- package/lib/transform/db/views.js +40 -37
- package/lib/transform/forRelationalDB.js +44 -30
- package/lib/transform/odata/typesExposure.js +50 -15
- package/lib/transform/parseExpr.js +14 -8
- package/lib/transform/transformUtilsNew.js +6 -5
- package/lib/transform/translateAssocsToJoins.js +49 -33
- package/package.json +1 -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 {
|
|
@@ -184,7 +183,6 @@ function fns( model ) {
|
|
|
184
183
|
resolveTypeArgumentsUnchecked,
|
|
185
184
|
resolvePath,
|
|
186
185
|
checkAnnotate,
|
|
187
|
-
copyAnnotationsForExtensions,
|
|
188
186
|
attachAndEmitValidNames,
|
|
189
187
|
} );
|
|
190
188
|
return;
|
|
@@ -253,16 +251,12 @@ function fns( model ) {
|
|
|
253
251
|
}
|
|
254
252
|
|
|
255
253
|
function checkSourceRef( art, path ) { // for FROM
|
|
256
|
-
if (art.
|
|
257
|
-
return
|
|
258
|
-
if (art.kind !== 'element')
|
|
259
|
-
return true;
|
|
254
|
+
if (!art._main)
|
|
255
|
+
return (art.kind !== 'entity');
|
|
260
256
|
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;
|
|
257
|
+
// at least the last main definition should be an entity
|
|
258
|
+
// an additional check for target would need effectiveType()
|
|
259
|
+
return (elem && elem._main.kind !== 'entity');
|
|
266
260
|
}
|
|
267
261
|
|
|
268
262
|
// Return absolute name for unchecked path `ref`. We first try searching for
|
|
@@ -313,7 +307,6 @@ function fns( model ) {
|
|
|
313
307
|
// incomplete type AST or empty env (already reported)
|
|
314
308
|
return setArtifactLink( ref, undefined );
|
|
315
309
|
}
|
|
316
|
-
setArtifactLink( ref, 0 ); // avoid cycles for type T: association to T.m;
|
|
317
310
|
|
|
318
311
|
let spec = specExpected[expected];
|
|
319
312
|
const { path } = ref;
|
|
@@ -324,10 +317,12 @@ function fns( model ) {
|
|
|
324
317
|
|
|
325
318
|
if (ref.scope === 'param') {
|
|
326
319
|
if (!spec.escape) {
|
|
327
|
-
error( 'ref-unexpected-scope', [ ref.location, user ], {}
|
|
328
|
-
'Unexpected parameter reference' );
|
|
320
|
+
error( 'ref-unexpected-scope', [ ref.location, user ], { '#': 'std' } );
|
|
329
321
|
return setArtifactLink( ref, null );
|
|
330
322
|
}
|
|
323
|
+
if (user.$syntax === 'calc')
|
|
324
|
+
error('ref-unexpected-scope', [ ref.location, user ], { '#': 'calc' } );
|
|
325
|
+
|
|
331
326
|
spec = specExpected[spec.escape];
|
|
332
327
|
// In queries and query entities, the first lexical search environment
|
|
333
328
|
// are the parameters, otherwise the block. It is currently ensured that
|
|
@@ -363,8 +358,12 @@ function fns( model ) {
|
|
|
363
358
|
return setArtifactLink( ref, art );
|
|
364
359
|
}
|
|
365
360
|
else if (!spec.envFn && user._pathHead) {
|
|
366
|
-
if (art.kind === '$self')
|
|
367
|
-
|
|
361
|
+
if (art.kind === '$self') {
|
|
362
|
+
const headEnv = VolatileFns.environment( user._pathHead ) &&
|
|
363
|
+
user._pathHead._origin &&
|
|
364
|
+
VolatileFns.environment( user._pathHead._origin );
|
|
365
|
+
rejectBareSelf( spec, path, user, headEnv );
|
|
366
|
+
}
|
|
368
367
|
}
|
|
369
368
|
else if (art.kind === 'using') {
|
|
370
369
|
const def = model.definitions[art.name.absolute];
|
|
@@ -464,13 +463,13 @@ function fns( model ) {
|
|
|
464
463
|
spec.noDep === 'only-entity' && art.kind !== 'entity')) {
|
|
465
464
|
const { location } = ref; // || combinedLocation( head, path[tail.length] );
|
|
466
465
|
// TODO: location of last path item if not main artifact
|
|
467
|
-
if (
|
|
468
|
-
dependsOn( user, art, location );
|
|
469
|
-
}
|
|
470
|
-
else {
|
|
466
|
+
if (spec.assoc === 'from' && art._main) {
|
|
471
467
|
dependsOn( user, art._main, location );
|
|
472
468
|
VolatileFns.environment( art, location, user );
|
|
473
|
-
|
|
469
|
+
}
|
|
470
|
+
else if (art.kind !== 'select') { // no real dependency to bare $self
|
|
471
|
+
dependsOn( user, art, location );
|
|
472
|
+
// Without on-demand resolve, we can simply signal 'undefined "x"'
|
|
474
473
|
// instead of 'illegal cycle' in the following case:
|
|
475
474
|
// element elem: type of elem.x;
|
|
476
475
|
}
|
|
@@ -772,12 +771,13 @@ function fns( model ) {
|
|
|
772
771
|
|
|
773
772
|
const fn = (spec.envFn && artItemsCount >= 0) ? spec.envFn : VolatileFns.environment;
|
|
774
773
|
const env = fn( art, item.location, user, spec.assoc );
|
|
775
|
-
const sub = setArtifactLink( item, env
|
|
774
|
+
const sub = setArtifactLink( item, env?.[item.id] );
|
|
776
775
|
|
|
777
776
|
if (!sub) {
|
|
778
777
|
// element was not found in environment
|
|
779
|
-
|
|
780
|
-
|
|
778
|
+
|
|
779
|
+
// TODO (done?): if `env` was 0, we might set a dependency to induce an
|
|
780
|
+
// illegal-cycle error instead of reporting via `errorNotFound`.
|
|
781
781
|
if (art.$uncheckedElements) { // magic variable / replacement variable
|
|
782
782
|
signalNotFound( 'ref-unknown-var', [ item.location, user ], [ env ],
|
|
783
783
|
{ id: pathName( path ) } );
|
|
@@ -971,26 +971,24 @@ function fns( model ) {
|
|
|
971
971
|
info( 'anno-builtin', [ construct.name.location, construct ], {},
|
|
972
972
|
'Builtin types should not be annotated. Use custom type instead' );
|
|
973
973
|
}
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
else
|
|
993
|
-
dictAddArray( art, annoProp, extAnno );
|
|
974
|
+
// --> without art._block, art not found
|
|
975
|
+
else if (construct.kind === 'annotate' && art._block?.$frontend === 'cdl') {
|
|
976
|
+
if (construct.$syntax === 'returns' && art.kind !== 'action' && art.kind !== 'function' ) {
|
|
977
|
+
// `annotate ABC with returns {}` is handled just like `elements`. Warn if it is used
|
|
978
|
+
// for non-actions. We can't only check for !art.returns, because `action A();` is valid.
|
|
979
|
+
// `art._block` ensures that `art` is a defined def.
|
|
980
|
+
warning('ext-unexpected-returns', [ construct.name.location, construct ],
|
|
981
|
+
{ keyword: 'returns', meta: art.kind }, 'Unexpected $(KEYWORD) for $(META)');
|
|
982
|
+
}
|
|
983
|
+
else if (construct.$syntax !== 'returns' &&
|
|
984
|
+
(art.kind === 'action' || art.kind === 'function') && construct.elements) {
|
|
985
|
+
warning('ext-expected-returns', [ construct.name.location, construct ], {
|
|
986
|
+
'#': art.kind, keyword: 'returns', code: 'annotate ‹name› with returns { … }',
|
|
987
|
+
}, {
|
|
988
|
+
std: 'Expected $(CODE)', // unused variant
|
|
989
|
+
action: 'Expected $(KEYWORD) when annotating action return structure, i.e. $(CODE)',
|
|
990
|
+
function: 'Expected $(KEYWORD) when annotating function return structure, i.e. $(CODE)',
|
|
991
|
+
});
|
|
994
992
|
}
|
|
995
993
|
}
|
|
996
994
|
}
|
|
@@ -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
|
}
|
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 '_':
|
|
@@ -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
|
|
@@ -428,6 +452,7 @@ module.exports = {
|
|
|
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,
|
|
@@ -1179,21 +1179,15 @@ function csn2annotationEdm(reqDefs, csnVocabularies, serviceName, Edm = undefine
|
|
|
1179
1179
|
}
|
|
1180
1180
|
}
|
|
1181
1181
|
else if (typeof value === 'number') {
|
|
1182
|
-
if (isComplexType(resolvedType)
|
|
1182
|
+
if (isComplexType(resolvedType) ||
|
|
1183
|
+
resolvedType === 'Edm.PropertyPath' ||
|
|
1184
|
+
resolvedType === 'Edm.Boolean') {
|
|
1183
1185
|
message('odata-anno-value', msg.location,
|
|
1184
|
-
|
|
1186
|
+
{ anno: msg.anno(), value, type: resolvedType });
|
|
1185
1187
|
}
|
|
1186
1188
|
else if (resolvedType === 'Edm.String') {
|
|
1187
1189
|
typeName = 'String';
|
|
1188
1190
|
}
|
|
1189
|
-
else if (resolvedType === 'Edm.PropertyPath') {
|
|
1190
|
-
message('odata-anno-value', msg.location,
|
|
1191
|
-
{ anno: msg.anno(), value, type: resolvedType });
|
|
1192
|
-
}
|
|
1193
|
-
else if (resolvedType === 'Edm.Boolean') {
|
|
1194
|
-
message('odata-anno-value', msg.location,
|
|
1195
|
-
{ anno: msg.anno(), value, type: resolvedType });
|
|
1196
|
-
}
|
|
1197
1191
|
else if (resolvedType === 'Edm.Decimal') {
|
|
1198
1192
|
typeName = 'Decimal';
|
|
1199
1193
|
}
|
|
@@ -1204,18 +1198,18 @@ function csn2annotationEdm(reqDefs, csnVocabularies, serviceName, Edm = undefine
|
|
|
1204
1198
|
//typeName = Number.isInteger(val) ? 'Int' : 'Float';
|
|
1205
1199
|
if(Number.isInteger(value)) {
|
|
1206
1200
|
typeName = 'Int';
|
|
1207
|
-
if(resolvedType ==
|
|
1201
|
+
if(resolvedType == null || resolvedType === 'Edm.PrimitiveType' || !resolvedType.startsWith('Edm.'))
|
|
1208
1202
|
resolvedType = 'Edm.Int64';
|
|
1209
1203
|
}
|
|
1210
1204
|
else {
|
|
1211
1205
|
typeName = 'Float';
|
|
1212
|
-
if(resolvedType ==
|
|
1206
|
+
if(resolvedType == null || resolvedType === 'Edm.PrimitiveType'|| !resolvedType.startsWith('Edm.'))
|
|
1213
1207
|
resolvedType = 'Edm.Double';
|
|
1214
1208
|
}
|
|
1215
1209
|
}
|
|
1216
1210
|
}
|
|
1217
1211
|
else if (value === null)
|
|
1218
|
-
if((resolvedType == null || resolvedType
|
|
1212
|
+
if((resolvedType == null || resolvedType === 'Edm.PrimitiveType') && typeName === 'String') {
|
|
1219
1213
|
resolvedType = 'Edm.String';
|
|
1220
1214
|
}
|
|
1221
1215
|
else {
|
|
@@ -63,6 +63,9 @@ function preprocessAnnotations(csn, serviceName, options) {
|
|
|
63
63
|
artifact.elements && Object.entries(artifact.elements).forEach(([elementName, element]) => {
|
|
64
64
|
handleAnnotations(artifactName, elementName, element, [ ...location, 'elements', elementName ]);
|
|
65
65
|
});
|
|
66
|
+
artifact.params && Object.entries(artifact.params).forEach(([paramName, param]) => {
|
|
67
|
+
handleAnnotations(artifactName, paramName, param, [ ...location, 'actions', artifactName, 'params', paramName ]);
|
|
68
|
+
});
|
|
66
69
|
forEachGeneric(artifact, 'actions', (action, actionName) => {
|
|
67
70
|
action.params && Object.entries(action.params).forEach(([paramName, param]) => {
|
|
68
71
|
handleAnnotations(actionName, paramName, param, [ ...location, 'actions', actionName, 'params', paramName ]);
|
package/lib/edm/csn2edm.js
CHANGED
|
@@ -518,10 +518,6 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
518
518
|
const properties = createProperties(elementsCsn, structuredTypeCsn)[0];
|
|
519
519
|
const loc = ['definitions', structuredTypeCsn.name];
|
|
520
520
|
|
|
521
|
-
if(properties.length === 0) {
|
|
522
|
-
warning(null, loc, { name: structuredTypeCsn.name },
|
|
523
|
-
'EDM ComplexType $(NAME) has no properties');
|
|
524
|
-
}
|
|
525
521
|
if(!edmUtils.isODataSimpleIdentifier(attributes.Name))
|
|
526
522
|
message('odata-spec-violation-id', loc, { id: attributes.Name });
|
|
527
523
|
|
package/lib/edm/edm.js
CHANGED
|
@@ -749,7 +749,7 @@ function getEdm(options, messageFunctions) {
|
|
|
749
749
|
this._edmAttributes && Object.entries(this._edmAttributes).forEach(([p, v]) => {
|
|
750
750
|
if (p !== 'Name' && p !== this._typeName
|
|
751
751
|
// remove this line if Nullable=true becomes default
|
|
752
|
-
&& !(p === 'Nullable' && v
|
|
752
|
+
&& !(p === 'Nullable' && !v))
|
|
753
753
|
{
|
|
754
754
|
json[p[0] === '@' ? p : '$' + p] = v;
|
|
755
755
|
}
|
|
@@ -763,7 +763,7 @@ function getEdm(options, messageFunctions) {
|
|
|
763
763
|
}
|
|
764
764
|
}
|
|
765
765
|
|
|
766
|
-
class ComplexType extends TypeBase {
|
|
766
|
+
class ComplexType extends TypeBase {
|
|
767
767
|
constructor(v, details, csn) {
|
|
768
768
|
super(v, details, csn);
|
|
769
769
|
if(this.v4 && !!csn['@open'] && isBetaEnabled(options, 'odataOpenType')) {
|
|
@@ -979,6 +979,7 @@ function getEdm(options, messageFunctions) {
|
|
|
979
979
|
// TIPHANACDS-4180
|
|
980
980
|
if(this.v2)
|
|
981
981
|
{
|
|
982
|
+
// eslint-disable-next-line sonarjs/no-redundant-boolean
|
|
982
983
|
if(csn['@odata.etag'] == true || csn['@cds.etag'] == true)
|
|
983
984
|
this._edmAttributes.ConcurrencyMode='Fixed'
|
|
984
985
|
|
|
@@ -1101,8 +1102,8 @@ function getEdm(options, messageFunctions) {
|
|
|
1101
1102
|
delete this._edmAttributes.Nullable;
|
|
1102
1103
|
}
|
|
1103
1104
|
// we have exactly one selfReference or the default partner
|
|
1104
|
-
let partner =
|
|
1105
|
-
!csn.$noPartner ?
|
|
1105
|
+
let partner =
|
|
1106
|
+
!csn.$noPartner ?
|
|
1106
1107
|
csn._selfReferences.length === 1
|
|
1107
1108
|
? csn._selfReferences[0]
|
|
1108
1109
|
: csn._constraints._partnerCsn
|
|
@@ -1121,6 +1122,7 @@ function getEdm(options, messageFunctions) {
|
|
|
1121
1122
|
See csn2edm.createParmeterizedEntityTypeAndSet() for details
|
|
1122
1123
|
2) ContainsTarget stems from the @odata.contained annotation
|
|
1123
1124
|
*/
|
|
1125
|
+
// eslint-disable-next-line sonarjs/no-redundant-boolean
|
|
1124
1126
|
if(csn['@odata.contained'] == true || csn.containsTarget) {
|
|
1125
1127
|
this._edmAttributes.ContainsTarget = true;
|
|
1126
1128
|
}
|
|
@@ -70,6 +70,7 @@ function applyAppSpecificLateCsnTransformationOnElement(options, element, struct
|
|
|
70
70
|
// for @[odata|cds].etag annotations...
|
|
71
71
|
if(options.isV4())
|
|
72
72
|
{
|
|
73
|
+
// eslint-disable-next-line sonarjs/no-redundant-boolean
|
|
73
74
|
if(element['@odata.etag'] == true || element['@cds.etag'] == true) {
|
|
74
75
|
// don't put element name into collection as per advice from Ralf Handl, as
|
|
75
76
|
// no runtime is interested in the property itself, it is sufficient to mark
|
|
@@ -100,10 +100,6 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
|
|
|
100
100
|
|
|
101
101
|
/*
|
|
102
102
|
Enrich the CSN by de-anonymizing and exposing types that are required to make the service self contained.
|
|
103
|
-
Type exposure will add additional schema contexts and group the exposed types in these contexts.
|
|
104
|
-
Contexts either represent another service (if the type to be exposed resides in that
|
|
105
|
-
service), the namespace (including (sub-)contexts) or as last resort (if the type name
|
|
106
|
-
has no prefix path) a 'root' namespace.
|
|
107
103
|
*/
|
|
108
104
|
const schemas = typesExposure(csn, whatsMyServiceRootName, requestedServiceNames,
|
|
109
105
|
fallBackSchemaName, options, csnUtils, { error });
|
|
@@ -1933,7 +1929,7 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
|
|
|
1933
1929
|
const localRestrictions = container[NavResAnno] ?
|
|
1934
1930
|
cloneAnnotationValue(container[NavResAnno]) : []
|
|
1935
1931
|
|
|
1936
|
-
// prefix the existing navigation property
|
|
1932
|
+
// prefix the existing navigation property restrictions on the container
|
|
1937
1933
|
if(prefix.length) {
|
|
1938
1934
|
localRestrictions.forEach(npe => {
|
|
1939
1935
|
if(npe.NavigationProperty &&
|
package/lib/gen/Dictionary.json
CHANGED
|
@@ -512,6 +512,14 @@
|
|
|
512
512
|
],
|
|
513
513
|
"$experimental": true
|
|
514
514
|
},
|
|
515
|
+
"Common.IsTimezone": {
|
|
516
|
+
"Type": "Core.Tag",
|
|
517
|
+
"AppliesTo": [
|
|
518
|
+
"Property",
|
|
519
|
+
"Parameter"
|
|
520
|
+
],
|
|
521
|
+
"$experimental": true
|
|
522
|
+
},
|
|
515
523
|
"Common.IsDigitSequence": {
|
|
516
524
|
"Type": "Core.Tag",
|
|
517
525
|
"AppliesTo": [
|
|
@@ -1376,6 +1384,16 @@
|
|
|
1376
1384
|
"Function"
|
|
1377
1385
|
]
|
|
1378
1386
|
},
|
|
1387
|
+
"Core.RequiresExplicitBinding": {
|
|
1388
|
+
"Type": "Core.Tag",
|
|
1389
|
+
"AppliesTo": [
|
|
1390
|
+
"Action",
|
|
1391
|
+
"Function"
|
|
1392
|
+
]
|
|
1393
|
+
},
|
|
1394
|
+
"Core.ExplicitOperationBindings": {
|
|
1395
|
+
"Type": "Collection(Core.QualifiedBoundOperationName)"
|
|
1396
|
+
},
|
|
1379
1397
|
"Core.SymbolicName": {
|
|
1380
1398
|
"Type": "Core.SimpleIdentifier"
|
|
1381
1399
|
},
|
|
@@ -1457,30 +1475,35 @@
|
|
|
1457
1475
|
"Measures.ISOCurrency": {
|
|
1458
1476
|
"Type": "Edm.String",
|
|
1459
1477
|
"AppliesTo": [
|
|
1478
|
+
"Parameter",
|
|
1460
1479
|
"Property"
|
|
1461
1480
|
]
|
|
1462
1481
|
},
|
|
1463
1482
|
"Measures.Scale": {
|
|
1464
1483
|
"Type": "Edm.Byte",
|
|
1465
1484
|
"AppliesTo": [
|
|
1485
|
+
"Parameter",
|
|
1466
1486
|
"Property"
|
|
1467
1487
|
]
|
|
1468
1488
|
},
|
|
1469
1489
|
"Measures.Unit": {
|
|
1470
1490
|
"Type": "Edm.String",
|
|
1471
1491
|
"AppliesTo": [
|
|
1492
|
+
"Parameter",
|
|
1472
1493
|
"Property"
|
|
1473
1494
|
]
|
|
1474
1495
|
},
|
|
1475
1496
|
"Measures.UNECEUnit": {
|
|
1476
1497
|
"Type": "Edm.String",
|
|
1477
1498
|
"AppliesTo": [
|
|
1499
|
+
"Parameter",
|
|
1478
1500
|
"Property"
|
|
1479
1501
|
]
|
|
1480
1502
|
},
|
|
1481
1503
|
"Measures.DurationGranularity": {
|
|
1482
1504
|
"Type": "Measures.DurationGranularityType",
|
|
1483
1505
|
"AppliesTo": [
|
|
1506
|
+
"Parameter",
|
|
1484
1507
|
"Property"
|
|
1485
1508
|
]
|
|
1486
1509
|
},
|
|
@@ -3360,6 +3383,10 @@
|
|
|
3360
3383
|
"$kind": "TypeDefinition",
|
|
3361
3384
|
"UnderlyingType": "Edm.String"
|
|
3362
3385
|
},
|
|
3386
|
+
"Core.QualifiedBoundOperationName": {
|
|
3387
|
+
"$kind": "TypeDefinition",
|
|
3388
|
+
"UnderlyingType": "Edm.String"
|
|
3389
|
+
},
|
|
3363
3390
|
"Core.LocalDateTime": {
|
|
3364
3391
|
"$kind": "TypeDefinition",
|
|
3365
3392
|
"UnderlyingType": "Edm.String"
|
|
@@ -3455,6 +3482,7 @@
|
|
|
3455
3482
|
"Border": "Edm.Boolean",
|
|
3456
3483
|
"FitToPage": "Edm.Boolean",
|
|
3457
3484
|
"Padding": "Edm.Boolean",
|
|
3485
|
+
"HeaderFooter": "Edm.Boolean",
|
|
3458
3486
|
"ResultSizeDefault": "Edm.Int32",
|
|
3459
3487
|
"ResultSizeMaximum": "Edm.Int32"
|
|
3460
3488
|
}
|
|
@@ -3939,7 +3967,7 @@
|
|
|
3939
3967
|
"$kind": "ComplexType",
|
|
3940
3968
|
"BaseType": "UI.DataFieldForActionAbstract",
|
|
3941
3969
|
"Properties": {
|
|
3942
|
-
"Action": "
|
|
3970
|
+
"Action": "UI.ActionName",
|
|
3943
3971
|
"InvocationGrouping": "UI.OperationGroupingType",
|
|
3944
3972
|
"Inline": "Edm.Boolean",
|
|
3945
3973
|
"Determining": "Edm.Boolean",
|
|
@@ -3994,7 +4022,7 @@
|
|
|
3994
4022
|
"BaseType": "UI.DataField",
|
|
3995
4023
|
"Properties": {
|
|
3996
4024
|
"Value": "Edm.PrimitiveType",
|
|
3997
|
-
"Action": "
|
|
4025
|
+
"Action": "UI.ActionName",
|
|
3998
4026
|
"Label": "Edm.String",
|
|
3999
4027
|
"Criticality": "UI.CriticalityType",
|
|
4000
4028
|
"CriticalityRepresentation": "UI.CriticalityRepresentationType",
|
|
@@ -4258,6 +4286,10 @@
|
|
|
4258
4286
|
"Symbols": {}
|
|
4259
4287
|
}
|
|
4260
4288
|
},
|
|
4289
|
+
"UI.ActionName": {
|
|
4290
|
+
"$kind": "TypeDefinition",
|
|
4291
|
+
"UnderlyingType": "Edm.String"
|
|
4292
|
+
},
|
|
4261
4293
|
"Validation.AllowedValue": {
|
|
4262
4294
|
"$kind": "ComplexType",
|
|
4263
4295
|
"Properties": {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
6c1cc14fd8155dcb48908afb59568b42
|