@sap/cds-compiler 2.10.2 → 2.11.4
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 +90 -5
- package/bin/.eslintrc.json +1 -2
- package/bin/cds_update_identifiers.js +3 -1
- package/bin/cdsc.js +49 -25
- package/bin/cdsse.js +1 -0
- package/bin/cdsv2m.js +3 -2
- package/doc/CHANGELOG_BETA.md +10 -0
- package/lib/api/.eslintrc.json +2 -0
- package/lib/api/main.js +8 -36
- package/lib/api/options.js +15 -6
- package/lib/api/validate.js +30 -3
- package/lib/backends.js +12 -13
- package/lib/base/dictionaries.js +2 -1
- package/lib/base/keywords.js +3 -2
- package/lib/base/message-registry.js +34 -10
- package/lib/base/messages.js +38 -18
- package/lib/base/model.js +5 -4
- package/lib/base/optionProcessorHelper.js +57 -23
- package/lib/checks/emptyOrOnlyVirtual.js +2 -2
- package/lib/checks/selectItems.js +4 -0
- package/lib/checks/unknownMagic.js +6 -3
- package/lib/compiler/assert-consistency.js +9 -2
- package/lib/compiler/base.js +65 -0
- package/lib/compiler/builtins.js +62 -16
- package/lib/compiler/checks.js +2 -1
- package/lib/compiler/definer.js +66 -108
- package/lib/compiler/index.js +29 -29
- package/lib/compiler/propagator.js +5 -2
- package/lib/compiler/resolver.js +225 -58
- package/lib/compiler/shared.js +53 -229
- package/lib/compiler/utils.js +184 -0
- package/lib/edm/annotations/genericTranslation.js +1 -1
- package/lib/edm/csn2edm.js +3 -2
- package/lib/edm/edmPreprocessor.js +34 -38
- package/lib/edm/edmUtils.js +3 -3
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +17 -1
- package/lib/gen/language.tokens +79 -73
- package/lib/gen/languageLexer.interp +19 -1
- package/lib/gen/languageLexer.js +779 -731
- package/lib/gen/languageLexer.tokens +71 -65
- package/lib/gen/languageParser.js +4668 -4072
- package/lib/json/from-csn.js +10 -10
- package/lib/json/to-csn.js +228 -47
- package/lib/language/antlrParser.js +11 -0
- package/lib/language/errorStrategy.js +26 -8
- package/lib/language/genericAntlrParser.js +73 -14
- package/lib/language/language.g4 +79 -3
- package/lib/main.d.ts +215 -18
- package/lib/main.js +3 -1
- package/lib/model/api.js +2 -2
- package/lib/model/csnRefs.js +117 -33
- package/lib/model/csnUtils.js +65 -133
- package/lib/model/enrichCsn.js +62 -37
- package/lib/model/revealInternalProperties.js +25 -8
- package/lib/model/sortViews.js +8 -1
- package/lib/modelCompare/compare.js +2 -1
- package/lib/optionProcessor.js +33 -18
- package/lib/render/.eslintrc.json +1 -2
- package/lib/render/DuplicateChecker.js +1 -1
- package/lib/render/toCdl.js +15 -8
- package/lib/render/toHdbcds.js +26 -49
- package/lib/render/toSql.js +61 -39
- package/lib/render/utils/common.js +1 -1
- package/lib/transform/db/applyTransformations.js +189 -0
- package/lib/transform/db/constraints.js +273 -119
- package/lib/transform/db/draft.js +3 -2
- package/lib/transform/db/expansion.js +6 -4
- package/lib/transform/db/flattening.js +19 -3
- package/lib/transform/db/transformExists.js +102 -9
- package/lib/transform/db/views.js +485 -0
- package/lib/transform/forHanaNew.js +93 -448
- package/lib/transform/forOdataNew.js +9 -2
- package/lib/transform/localized.js +2 -0
- package/lib/transform/odata/structuralPath.js +1 -5
- package/lib/transform/transformUtilsNew.js +22 -8
- package/lib/transform/translateAssocsToJoins.js +7 -15
- package/lib/utils/file.js +11 -5
- package/lib/utils/term.js +65 -42
- package/lib/utils/timetrace.js +48 -26
- package/package.json +1 -1
- package/lib/transform/db/helpers.js +0 -58
package/lib/model/api.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* - the ‹property name› (might be useful if the same function is used for several props)
|
|
16
16
|
*/
|
|
17
17
|
const defaultFunctions = {
|
|
18
|
-
'@': () => {
|
|
18
|
+
'@': () => { /* do not traverse annotation assignments */ },
|
|
19
19
|
args: dictionary,
|
|
20
20
|
elements: dictionary,
|
|
21
21
|
enum: dictionary,
|
|
@@ -23,7 +23,7 @@ const defaultFunctions = {
|
|
|
23
23
|
actions: dictionary,
|
|
24
24
|
mixin: dictionary,
|
|
25
25
|
definitions: dictionary,
|
|
26
|
-
'$': () => {
|
|
26
|
+
'$': () => { /* do not traverse properties starting with '$' */},
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
package/lib/model/csnRefs.js
CHANGED
|
@@ -225,17 +225,19 @@ function csnRefs( csn ) {
|
|
|
225
225
|
const cachedType = getCache( art, '_effectiveType' );
|
|
226
226
|
if (cachedType !== undefined)
|
|
227
227
|
return cachedType;
|
|
228
|
-
else if (!art.type && !art.$origin ||
|
|
229
|
-
art.elements || art.target || art.targetAspect || art.enum)
|
|
230
|
-
return setCache( art, '_effectiveType', art );
|
|
231
228
|
|
|
232
229
|
const chain = [];
|
|
233
|
-
|
|
230
|
+
let origin;
|
|
231
|
+
while (getCache( art, '_effectiveType' ) === undefined &&
|
|
232
|
+
(origin = cached( art, '_origin', getOriginRaw )) &&
|
|
234
233
|
!art.elements && !art.target && !art.targetAspect && !art.enum && !art.items) {
|
|
235
234
|
chain.push( art );
|
|
236
235
|
setCache( art, '_effectiveType', 0 ); // initial setting in case of cycles
|
|
237
|
-
art =
|
|
236
|
+
art = origin;
|
|
238
237
|
}
|
|
238
|
+
if (!chain.length)
|
|
239
|
+
return setCache( art, '_effectiveType', art );
|
|
240
|
+
|
|
239
241
|
if (getCache( art, '_effectiveType' ) === 0)
|
|
240
242
|
throw new Error( 'Circular type reference');
|
|
241
243
|
const type = getCache( art, '_effectiveType' ) || art;
|
|
@@ -251,10 +253,16 @@ function csnRefs( csn ) {
|
|
|
251
253
|
// here, we do not care whether it is semantically ok to navigate into sub
|
|
252
254
|
// elements of array items (that is the task of the core compiler /
|
|
253
255
|
// semantic check)
|
|
254
|
-
while (type.items)
|
|
256
|
+
while (type.items) {
|
|
257
|
+
cached( type, '$origin', _a => setImplicitOrigin( type, origin ) );
|
|
255
258
|
type = effectiveType( type.items );
|
|
259
|
+
}
|
|
256
260
|
// cannot navigate along targetAspect!
|
|
257
|
-
|
|
261
|
+
const env = (type.target) ? csn.definitions[type.target] : type;
|
|
262
|
+
const origin = cached( env, '_origin', getOriginRaw );
|
|
263
|
+
if (origin && origin !== BUILTIN_TYPE)
|
|
264
|
+
cached( env, '$origin', _a => setImplicitOrigin( env, origin ) );
|
|
265
|
+
return env;
|
|
258
266
|
}
|
|
259
267
|
|
|
260
268
|
/**
|
|
@@ -279,38 +287,109 @@ function csnRefs( csn ) {
|
|
|
279
287
|
function artifactPathRef( ref ) {
|
|
280
288
|
const [ head, ...tail ] = ref.ref;
|
|
281
289
|
let art = csn.definitions[pathId( head )];
|
|
282
|
-
for (const elem of tail)
|
|
283
|
-
|
|
290
|
+
for (const elem of tail) {
|
|
291
|
+
const env = navigationEnv( art );
|
|
292
|
+
art = env.elements[pathId( elem )];
|
|
293
|
+
}
|
|
284
294
|
return art;
|
|
285
295
|
}
|
|
286
296
|
|
|
287
|
-
function getOrigin(
|
|
288
|
-
const
|
|
289
|
-
if (
|
|
290
|
-
|
|
291
|
-
|
|
297
|
+
function getOrigin( art, alsoType ) {
|
|
298
|
+
const origin = cached( art, '_origin', getOriginRaw );
|
|
299
|
+
if (origin && origin !== BUILTIN_TYPE)
|
|
300
|
+
cached( art, '$origin', _a => setImplicitOrigin( art, origin ) );
|
|
301
|
+
return art.type && !alsoType ? undefined : origin;
|
|
292
302
|
}
|
|
293
303
|
|
|
294
|
-
function
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
304
|
+
function getOriginRaw( art ) {
|
|
305
|
+
if (art.type) // TODO: make robust against "linked" = only direct
|
|
306
|
+
return artifactRef( art.type, BUILTIN_TYPE );
|
|
307
|
+
if (!art.$origin) // implicit $origin should have been set
|
|
308
|
+
return null;
|
|
309
|
+
// art.$origin must not be a string here - shortened refs should already
|
|
310
|
+
// have been used to set the _origin cache
|
|
311
|
+
if (!Array.isArray( art.$origin )) // anonymous prototype in $origin
|
|
312
|
+
return cached( art.$origin, '_origin', getOriginRaw );
|
|
313
|
+
const [ head, ...tail ] = art.$origin;
|
|
314
|
+
let origin = csn.definitions[head];
|
|
315
|
+
// allow shorter $origin ref for actions/functions, just using a string:
|
|
316
|
+
let isAction = art.kind === 'action' || art.kind === 'function';
|
|
317
|
+
for (const elem of tail) {
|
|
318
|
+
origin = originNavigation( origin, elem, isAction );
|
|
319
|
+
isAction = false;
|
|
320
|
+
}
|
|
321
|
+
return origin;
|
|
300
322
|
}
|
|
301
323
|
|
|
302
|
-
function originNavigation( art, elem ) {
|
|
324
|
+
function originNavigation( art, elem, isAction ) {
|
|
303
325
|
if (typeof elem !== 'string') {
|
|
304
326
|
if (elem.action)
|
|
305
|
-
return art.actions[elem.action]
|
|
327
|
+
return art.actions[elem.action];
|
|
306
328
|
if (elem.param)
|
|
307
|
-
return
|
|
329
|
+
return art.params[elem.param];
|
|
330
|
+
if (elem.returns)
|
|
331
|
+
return art.returns;
|
|
308
332
|
}
|
|
309
|
-
if (
|
|
333
|
+
if (isAction)
|
|
334
|
+
return art.actions[elem];
|
|
335
|
+
// TODO: if we use effectiveType(), we might have more implicit prototypes
|
|
336
|
+
// we might then need a function like effectiveArtifact,
|
|
337
|
+
// which cares about actions/params
|
|
338
|
+
// let origin = cached( art, '_origin', getOriginRaw );
|
|
339
|
+
// while (art.items) {
|
|
340
|
+
// cached( art, '$origin', _a => setImplicitOrigin( art, origin ) );
|
|
341
|
+
// art = art.items;
|
|
342
|
+
// origin = cached( art, '_origin', getOriginRaw );
|
|
343
|
+
// }
|
|
344
|
+
// if (origin)
|
|
345
|
+
// cached( art, '$origin', _a => setImplicitOrigin( art, origin ) );
|
|
346
|
+
// console.log(art)
|
|
347
|
+
return (art.elements || art.enum || targetAspect( art ).elements)[elem];
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function targetAspect( art ) {
|
|
351
|
+
const { $origin } = art;
|
|
352
|
+
return art.targetAspect ||
|
|
353
|
+
$origin && typeof $origin === 'object' && !Array.isArray( $origin ) && $origin.target ||
|
|
354
|
+
art.target;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// From the current CSN object, set implicit origin for the next navigation step
|
|
358
|
+
function setImplicitOrigin( art, origin ) {
|
|
359
|
+
setMembersImplicit( art.actions, origin.actions );
|
|
360
|
+
setMembersImplicit( art.params, origin.params );
|
|
361
|
+
if (art.returns) {
|
|
310
362
|
art = art.returns;
|
|
311
|
-
|
|
363
|
+
if (art.type || typeof art.$origin === 'object') // null, […], {…}
|
|
364
|
+
return true; // not implicit or shortened
|
|
365
|
+
origin = effectiveType( origin.returns );
|
|
366
|
+
setCache( art, '_origin', origin );
|
|
367
|
+
return true;
|
|
368
|
+
}
|
|
369
|
+
while (art.items) {
|
|
312
370
|
art = art.items;
|
|
313
|
-
|
|
371
|
+
if (art.type || typeof art.$origin === 'object') // null, […], {…}
|
|
372
|
+
return true; // not implicit or shortened
|
|
373
|
+
origin = effectiveType( origin.items );
|
|
374
|
+
setCache( art, '_origin', origin );
|
|
375
|
+
}
|
|
376
|
+
setMembersImplicit( art.elements, origin.elements );
|
|
377
|
+
// The enum base type is _not_ where we find the origins of the enum symbols.
|
|
378
|
+
// A derived type of an enum type with individual annotations on a symbol
|
|
379
|
+
// has both 'type' and '$origin'.
|
|
380
|
+
if (!art.type || art.$origin)
|
|
381
|
+
setMembersImplicit( art.enum, origin.enum );
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function setMembersImplicit( members, originMembers ) {
|
|
386
|
+
if (!members)
|
|
387
|
+
return;
|
|
388
|
+
for (const name in members) {
|
|
389
|
+
const elem = members[name];
|
|
390
|
+
if (!elem.type && typeof elem.$origin !== 'object') // undefined or string
|
|
391
|
+
setCache( elem, '_origin', originMembers[elem.$origin || name] || false );
|
|
392
|
+
}
|
|
314
393
|
}
|
|
315
394
|
|
|
316
395
|
/**
|
|
@@ -371,6 +450,9 @@ function csnRefs( csn ) {
|
|
|
371
450
|
if (semantics.dynamic === 'global' || ref.global)
|
|
372
451
|
return resolvePath( path, csn.definitions[head], 'global', refCtx === 'from' );
|
|
373
452
|
|
|
453
|
+
const origin = cached( main, '_origin', getOriginRaw )
|
|
454
|
+
if (origin)
|
|
455
|
+
cached( main, '$origin', _a => setImplicitOrigin( main, origin ) );
|
|
374
456
|
cached( main, '$queries', allQueries );
|
|
375
457
|
let qcache = query && cache.get( query.projection || query );
|
|
376
458
|
// BACKEND ISSUE: you cannot call csnRefs(), inspect some refs, change the
|
|
@@ -387,7 +469,7 @@ function csnRefs( csn ) {
|
|
|
387
469
|
while (cache) {
|
|
388
470
|
const alias = tryAlias && cache.$aliases[head];
|
|
389
471
|
if (alias)
|
|
390
|
-
return resolvePath( path, alias._select || alias, 'alias', cache.$queryNumber );
|
|
472
|
+
return resolvePath( path, alias._select || alias._ref, 'alias', cache.$queryNumber );
|
|
391
473
|
const mixin = cache._select.mixin && cache._select.mixin[head];
|
|
392
474
|
if (mixin && {}.hasOwnProperty.call( cache._select.mixin, head ))
|
|
393
475
|
return resolvePath( path, mixin, 'mixin', cache.$queryNumber );
|
|
@@ -405,7 +487,7 @@ function csnRefs( csn ) {
|
|
|
405
487
|
// not selecting the corresponding element for a select column works,
|
|
406
488
|
// because explicit keys can only be provided with explicit redirection
|
|
407
489
|
// target
|
|
408
|
-
const target = csn.definitions[parent.target || parent.cast.target];
|
|
490
|
+
const target = csn.definitions[parent.target || parent.$origin && parent.$origin.target || parent.cast.target];
|
|
409
491
|
return resolvePath( path, target.elements[head], 'target' );
|
|
410
492
|
}
|
|
411
493
|
if (baseEnv) // ref-target (filter condition), expand, inline
|
|
@@ -481,7 +563,8 @@ function csnRefs( csn ) {
|
|
|
481
563
|
if (query.ref) { // ref in from
|
|
482
564
|
// console.log('SQ:',query,cache.get(query))
|
|
483
565
|
const as = query.as || implicitAs( query.ref );
|
|
484
|
-
|
|
566
|
+
const _ref = fromRef( query );
|
|
567
|
+
getCache( fromSelect, '$aliases' )[as] = { _ref, elements: _ref.elements };
|
|
485
568
|
}
|
|
486
569
|
else {
|
|
487
570
|
const qcache = getQueryCache( parentQuery );
|
|
@@ -517,7 +600,7 @@ function csnRefs( csn ) {
|
|
|
517
600
|
function getQueryCache( parentQuery ) {
|
|
518
601
|
if (!parentQuery)
|
|
519
602
|
return { $aliases: Object.create(null) };
|
|
520
|
-
const pcache = cache.get( parentQuery );
|
|
603
|
+
const pcache = cache.get( parentQuery.projection || parentQuery );
|
|
521
604
|
if (!parentQuery.SET) // SELECT / projection: real sub query
|
|
522
605
|
return { $aliases: Object.create(null), $next: pcache };
|
|
523
606
|
// the parent query is a SET: that is not a sub query
|
|
@@ -607,7 +690,7 @@ function queryOrMain( query, main ) {
|
|
|
607
690
|
*
|
|
608
691
|
* @param {CSN.Query} query
|
|
609
692
|
* @param {CSN.QuerySelect} fromSelect
|
|
610
|
-
* @param {CSN.Query} parentQuery
|
|
693
|
+
* @param {CSN.Query} parentQuery
|
|
611
694
|
* @param {(query: CSN.Query&CSN.QueryFrom, select: CSN.QuerySelectEnriched) => void} callback
|
|
612
695
|
*/
|
|
613
696
|
function traverseQuery( query, fromSelect, parentQuery, callback ) {
|
|
@@ -632,8 +715,9 @@ function traverseQuery( query, fromSelect, parentQuery, callback ) {
|
|
|
632
715
|
|
|
633
716
|
/**
|
|
634
717
|
* @param {CSN.QueryFrom} from
|
|
635
|
-
* @param {CSN.QuerySelect}
|
|
636
|
-
* @param {
|
|
718
|
+
* @param {CSN.QuerySelect} fromSelect
|
|
719
|
+
* @param {CSN.Query} parentQuery
|
|
720
|
+
* @param {(from: CSN.QueryFrom, select: CSN.QuerySelect, parentQuery: CSN.Query) => void} callback
|
|
637
721
|
*/
|
|
638
722
|
function traverseFrom( from, fromSelect, parentQuery, callback ) {
|
|
639
723
|
if (from.ref) {
|
package/lib/model/csnUtils.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { setProp } = require('../base/model');
|
|
4
3
|
const { csnRefs } = require('../model/csnRefs');
|
|
4
|
+
const { applyTransformations, applyTransformationsOnNonDictionary } = require('../transform/db/applyTransformations');
|
|
5
|
+
const { isBuiltinType } = require('../compiler/builtins.js')
|
|
5
6
|
const { sortCsn, cloneCsnDictionary: _cloneCsnDictionary } = require('../json/to-csn');
|
|
6
7
|
const version = require('../../package.json').version;
|
|
7
8
|
|
|
@@ -11,8 +12,8 @@ const version = require('../../package.json').version;
|
|
|
11
12
|
* Generic Callback
|
|
12
13
|
*
|
|
13
14
|
* @callback genericCallback
|
|
14
|
-
* @param {
|
|
15
|
-
* @param {
|
|
15
|
+
* @param {any} art
|
|
16
|
+
* @param {string} name Artifact Name
|
|
16
17
|
* @param {string} prop Dictionary Property
|
|
17
18
|
* @param {CSN.Path} path Location
|
|
18
19
|
* @param {CSN.Artifact} [dictionary]
|
|
@@ -457,8 +458,8 @@ function getUtils(model) {
|
|
|
457
458
|
return resultNode;
|
|
458
459
|
}
|
|
459
460
|
}
|
|
460
|
-
|
|
461
|
-
|
|
461
|
+
|
|
462
|
+
|
|
462
463
|
/**
|
|
463
464
|
* Resolve to the final type of a type, that means follow type chains, references to other types or
|
|
464
465
|
* elements a.s.o
|
|
@@ -497,12 +498,12 @@ function getUtils(model) {
|
|
|
497
498
|
* Composed types (structures, entities, views, ...) are returned as type objects, if not drilled down into
|
|
498
499
|
* the elements. Path steps that have no corresponding element lead to 'undefined'. Refs to something that has
|
|
499
500
|
* no type (e.g. expr in a view without explicit type) returns 'null'
|
|
500
|
-
*
|
|
501
|
+
*
|
|
501
502
|
* @param {string|object} type Type - either string or ref
|
|
502
|
-
* @param {CSN.Path} path
|
|
503
|
+
* @param {CSN.Path} path
|
|
503
504
|
* @param {WeakMap} [resolved=new WeakMap()] WeakMap containing already resolved refs - if a ref is not cached, it will be resolved JIT
|
|
504
|
-
* @param {object} [cycleCheck] Dictionary to remember already resolved types - to be cycle-safe
|
|
505
|
-
* @returns
|
|
505
|
+
* @param {object} [cycleCheck] Dictionary to remember already resolved types - to be cycle-safe
|
|
506
|
+
* @returns
|
|
506
507
|
*/
|
|
507
508
|
function getFinalBaseType(type, path = [], resolved = new WeakMap(), cycleCheck = undefined) {
|
|
508
509
|
if (!type)
|
|
@@ -552,16 +553,6 @@ function getUtils(model) {
|
|
|
552
553
|
}
|
|
553
554
|
}
|
|
554
555
|
|
|
555
|
-
// Tell if a type is (directly) a builtin type
|
|
556
|
-
// Note that in CSN builtins are not in the definition of the model, so we can only check against their absolute names.
|
|
557
|
-
// Builtin types are "cds.<something>", i.e. they are directly in 'cds', but not for example
|
|
558
|
-
// in 'cds.foundation'. Also note, that a type might be a ref object, that refers to something else,
|
|
559
|
-
// so if you consider type chains don't forget first to resolve to the final type before
|
|
560
|
-
function isBuiltinType(type) {
|
|
561
|
-
return typeof(type) === 'string' && type.startsWith('cds.') && !type.startsWith('cds.foundation.')
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
|
|
565
556
|
/**
|
|
566
557
|
* Deeply clone the given CSN model and return it.
|
|
567
558
|
* In testMode (or with testSortCsn), definitions are sorted.
|
|
@@ -817,11 +808,25 @@ function forAllQueries(query, callback, path = []){
|
|
|
817
808
|
}
|
|
818
809
|
}
|
|
819
810
|
|
|
820
|
-
function forAllElements(artifact, artifactName, cb){
|
|
811
|
+
function forAllElements(artifact, artifactName, cb, includeActions = false){
|
|
821
812
|
if(artifact.elements) {
|
|
822
813
|
cb(artifact, artifact.elements, ['definitions', artifactName, 'elements']);
|
|
823
814
|
}
|
|
824
815
|
|
|
816
|
+
if(includeActions && artifact.actions) {
|
|
817
|
+
Object.entries(artifact.actions).forEach( ([actionName, action]) => {
|
|
818
|
+
const path = ['definitions', artifactName, 'actions', actionName];
|
|
819
|
+
if(action.params) {
|
|
820
|
+
Object.entries(action.params).forEach( ([paramName, param]) => {
|
|
821
|
+
if(param.elements)
|
|
822
|
+
cb(param, param.elements, path.concat(['params', paramName, 'elements']));
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
if(action.returns && action.returns.elements)
|
|
826
|
+
cb(action.returns, action.returns.elements,path.concat(['returns', 'elements']));
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
|
|
825
830
|
if(artifact.query) {
|
|
826
831
|
forAllQueries(artifact.query, (q, p) => {
|
|
827
832
|
const s = q.SELECT;
|
|
@@ -871,7 +876,7 @@ function hasAnnotationValue(artifact, annotationName, expected = true) {
|
|
|
871
876
|
* function accepts EDM internal and external options
|
|
872
877
|
*
|
|
873
878
|
* @param {CSN.Element} elementCsn
|
|
874
|
-
* @param {
|
|
879
|
+
* @param {ODataOptions} options EDM specific options
|
|
875
880
|
*/
|
|
876
881
|
function isEdmPropertyRendered(elementCsn, options) {
|
|
877
882
|
if(options.toOdata)
|
|
@@ -921,10 +926,10 @@ function getArtifactDatabaseNameOf(artifactName, namingConvention, csn) {
|
|
|
921
926
|
throw new Error('Unknown naming convention: ' + namingConvention);
|
|
922
927
|
}
|
|
923
928
|
else {
|
|
924
|
-
const namespace = csn;
|
|
925
929
|
console.error(`This invocation of "getArtifactCdsPersistenceName" is deprecated, as it doesn't produce correct output with definition names containing dots - please provide a CSN as the third parameter.`);
|
|
926
930
|
if (namingConvention === 'hdbcds') {
|
|
927
|
-
if (
|
|
931
|
+
if (csn) {
|
|
932
|
+
const namespace = String(csn);
|
|
928
933
|
return `${namespace}::${artifactName.substring(namespace.length + 1)}`;
|
|
929
934
|
}
|
|
930
935
|
return artifactName;
|
|
@@ -1048,109 +1053,6 @@ function getElementDatabaseNameOf(elemName, namingConvention) {
|
|
|
1048
1053
|
}
|
|
1049
1054
|
}
|
|
1050
1055
|
|
|
1051
|
-
|
|
1052
|
-
/**
|
|
1053
|
-
* Loop through the model, applying the custom transformations on the node's matching.
|
|
1054
|
-
*
|
|
1055
|
-
* Each transformer gets:
|
|
1056
|
-
* - the parent having the property
|
|
1057
|
-
* - the name of the property
|
|
1058
|
-
* - the value of the property
|
|
1059
|
-
* - the path to the property
|
|
1060
|
-
*
|
|
1061
|
-
* @param {object} csn CSN to enrich in-place
|
|
1062
|
-
* @param {object} customTransformers Map of prop to transform and function to apply
|
|
1063
|
-
* @param {Function[]} [artifactTransformers=[]] Transformations to run on the artifacts, like forEachDefinition
|
|
1064
|
-
* @param {Boolean} [skipIgnore=true] Wether to skip _ignore elements or not
|
|
1065
|
-
* @param {object} [options={}] "skipArtifact": (artifact, name) => Boolean to skip certain artifacts, drillRef: boolean - whether to drill into infix/args
|
|
1066
|
-
* @returns {object} CSN with transformations applied
|
|
1067
|
-
*/
|
|
1068
|
-
function applyTransformations( csn, customTransformers={}, artifactTransformers=[], skipIgnore = true, options = {} ) {
|
|
1069
|
-
const transformers = {
|
|
1070
|
-
elements: dictionary,
|
|
1071
|
-
definitions: dictionary,
|
|
1072
|
-
actions: dictionary,
|
|
1073
|
-
params: dictionary,
|
|
1074
|
-
enum: dictionary,
|
|
1075
|
-
mixin: dictionary,
|
|
1076
|
-
ref: pathRef,
|
|
1077
|
-
//type: simpleRef,
|
|
1078
|
-
//target: simpleRef,
|
|
1079
|
-
//includes: simpleRef,
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
|
-
const csnPath = [];
|
|
1083
|
-
if (csn.definitions)
|
|
1084
|
-
definitions( csn, 'definitions', csn.definitions );
|
|
1085
|
-
return csn;
|
|
1086
|
-
|
|
1087
|
-
function standard( parent, prop, node ) {
|
|
1088
|
-
if (!node || typeof node !== 'object' || !{}.propertyIsEnumerable.call( parent, prop ) || (typeof prop === 'string' && prop.startsWith('@')) || (skipIgnore && node._ignore))
|
|
1089
|
-
return;
|
|
1090
|
-
|
|
1091
|
-
csnPath.push( prop );
|
|
1092
|
-
|
|
1093
|
-
if (Array.isArray(node)) {
|
|
1094
|
-
node.forEach( (n, i) => standard( node, i, n ) );
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
else {
|
|
1098
|
-
for (let name of Object.getOwnPropertyNames( node )) {
|
|
1099
|
-
const trans = transformers[name] || standard;
|
|
1100
|
-
if(customTransformers[name])
|
|
1101
|
-
customTransformers[name](node, name, node[name], csnPath, parent, prop);
|
|
1102
|
-
|
|
1103
|
-
trans( node, name, node[name], csnPath );
|
|
1104
|
-
}
|
|
1105
|
-
}
|
|
1106
|
-
csnPath.pop();
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1109
|
-
function dictionary( node, prop, dict ) {
|
|
1110
|
-
csnPath.push( prop );
|
|
1111
|
-
for (let name of Object.getOwnPropertyNames( dict )) {
|
|
1112
|
-
standard( dict, name, dict[name] );
|
|
1113
|
-
}
|
|
1114
|
-
if (!Object.prototype.propertyIsEnumerable.call( node, prop ))
|
|
1115
|
-
setProp(node, '$' + prop, dict);
|
|
1116
|
-
csnPath.pop();
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
function definitions( node, prop, dict ) {
|
|
1120
|
-
csnPath.push( prop );
|
|
1121
|
-
for (let name of Object.getOwnPropertyNames( dict )) {
|
|
1122
|
-
const skip = options && options.skipArtifact && options.skipArtifact(dict[name], name) || false;
|
|
1123
|
-
if(!skip) {
|
|
1124
|
-
artifactTransformers.forEach(fn => fn(dict, name, dict[name]));
|
|
1125
|
-
standard( dict, name, dict[name] );
|
|
1126
|
-
}
|
|
1127
|
-
}
|
|
1128
|
-
if (!Object.prototype.propertyIsEnumerable.call( node, prop ))
|
|
1129
|
-
setProp(node, '$' + prop, dict);
|
|
1130
|
-
csnPath.pop();
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
//Keep looping through the pathRef
|
|
1134
|
-
function pathRef( node, prop, path ) {
|
|
1135
|
-
csnPath.push( prop );
|
|
1136
|
-
path.forEach( function step( s, i ) {
|
|
1137
|
-
if (s && typeof s === 'object') {
|
|
1138
|
-
csnPath.push( i );
|
|
1139
|
-
if(options.drillRef) {
|
|
1140
|
-
standard(path, i, s);
|
|
1141
|
-
} else {
|
|
1142
|
-
if (s.args)
|
|
1143
|
-
standard( s, 'args', s.args );
|
|
1144
|
-
if (s.where)
|
|
1145
|
-
standard( s, 'where', s.where );
|
|
1146
|
-
}
|
|
1147
|
-
csnPath.pop();
|
|
1148
|
-
}
|
|
1149
|
-
} );
|
|
1150
|
-
csnPath.pop();
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
1056
|
const _dependencies = Symbol('_dependencies');
|
|
1155
1057
|
const _dependents = Symbol('_dependents');
|
|
1156
1058
|
|
|
@@ -1529,7 +1431,7 @@ function sortCsnDefinitionsForTests(csn, options) {
|
|
|
1529
1431
|
if (!options.testMode)
|
|
1530
1432
|
return;
|
|
1531
1433
|
const sorted = Object.create(null);
|
|
1532
|
-
Object.keys(csn.definitions).sort().forEach((name) => {
|
|
1434
|
+
Object.keys(csn.definitions || {}).sort().forEach((name) => {
|
|
1533
1435
|
sorted[name] = csn.definitions[name];
|
|
1534
1436
|
});
|
|
1535
1437
|
csn.definitions = sorted;
|
|
@@ -1539,7 +1441,7 @@ function sortCsnDefinitionsForTests(csn, options) {
|
|
|
1539
1441
|
* Return an array of non-abstract service names contained in CSN
|
|
1540
1442
|
*
|
|
1541
1443
|
* @param {CSN.Model} csn
|
|
1542
|
-
* @returns {
|
|
1444
|
+
* @returns {string[]}
|
|
1543
1445
|
*/
|
|
1544
1446
|
function getServiceNames(csn) {
|
|
1545
1447
|
let result = [];
|
|
@@ -1553,8 +1455,8 @@ function getServiceNames(csn) {
|
|
|
1553
1455
|
|
|
1554
1456
|
/**
|
|
1555
1457
|
* Check wether the artifact is @cds.persistence.skip
|
|
1556
|
-
*
|
|
1557
|
-
* @param {CSN.Artifact} artifact
|
|
1458
|
+
*
|
|
1459
|
+
* @param {CSN.Artifact} artifact
|
|
1558
1460
|
* @returns {Boolean}
|
|
1559
1461
|
*/
|
|
1560
1462
|
function isSkipped(artifact) {
|
|
@@ -1563,9 +1465,9 @@ function isSkipped(artifact) {
|
|
|
1563
1465
|
|
|
1564
1466
|
/**
|
|
1565
1467
|
* Walk path in the CSN and return the result.
|
|
1566
|
-
*
|
|
1567
|
-
* @param {CSN.Model} csn
|
|
1568
|
-
* @param {CSN.Path} path
|
|
1468
|
+
*
|
|
1469
|
+
* @param {CSN.Model} csn
|
|
1470
|
+
* @param {CSN.Path} path
|
|
1569
1471
|
* @returns {object} Whatever is at the end of path
|
|
1570
1472
|
*/
|
|
1571
1473
|
function walkCsnPath(csn, path) {
|
|
@@ -1578,6 +1480,34 @@ function walkCsnPath(csn, path) {
|
|
|
1578
1480
|
return obj;
|
|
1579
1481
|
}
|
|
1580
1482
|
|
|
1483
|
+
/**
|
|
1484
|
+
* If provided, get the replacement string for the given magic variable ref.
|
|
1485
|
+
* No validation is done that the ref is actually magic!
|
|
1486
|
+
*
|
|
1487
|
+
* @param {array} ref
|
|
1488
|
+
* @param {CSN.Options} options
|
|
1489
|
+
* @returns {string|null}
|
|
1490
|
+
*/
|
|
1491
|
+
function getVariableReplacement(ref, options) {
|
|
1492
|
+
if(options && options.variableReplacements) {
|
|
1493
|
+
let replacement = options.variableReplacements;
|
|
1494
|
+
for(let i = 0; i < ref.length; i++) {
|
|
1495
|
+
replacement = replacement[ref[i]];
|
|
1496
|
+
if(replacement === undefined)
|
|
1497
|
+
return null;
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
if(replacement === undefined)
|
|
1501
|
+
return null; // no valid replacement found
|
|
1502
|
+
else if(typeof replacement === 'string')
|
|
1503
|
+
return replacement; // valid replacement
|
|
1504
|
+
else
|
|
1505
|
+
return null; // $user.foo, but we only have configured $user.foo.bar -> error
|
|
1506
|
+
} else {
|
|
1507
|
+
return null;
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1581
1511
|
module.exports = {
|
|
1582
1512
|
getUtils,
|
|
1583
1513
|
cloneCsn,
|
|
@@ -1598,6 +1528,7 @@ module.exports = {
|
|
|
1598
1528
|
getUnderscoredName,
|
|
1599
1529
|
getElementDatabaseNameOf,
|
|
1600
1530
|
applyTransformations,
|
|
1531
|
+
applyTransformationsOnNonDictionary,
|
|
1601
1532
|
setDependencies,
|
|
1602
1533
|
isPersistedOnDatabase,
|
|
1603
1534
|
generatedByCompilerVersion,
|
|
@@ -1618,4 +1549,5 @@ module.exports = {
|
|
|
1618
1549
|
getServiceNames,
|
|
1619
1550
|
isSkipped,
|
|
1620
1551
|
walkCsnPath,
|
|
1552
|
+
getVariableReplacement
|
|
1621
1553
|
};
|