@sap/cds-compiler 2.4.4 → 2.10.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 +241 -1
- package/bin/.eslintrc.json +17 -0
- package/bin/cds_update_identifiers.js +8 -7
- package/bin/cdsc.js +180 -132
- package/bin/cdshi.js +18 -11
- package/bin/cdsse.js +38 -32
- package/bin/cdsv2m.js +8 -7
- package/doc/CHANGELOG_BETA.md +36 -1
- package/lib/api/main.js +81 -100
- package/lib/api/options.js +17 -11
- package/lib/api/validate.js +12 -8
- package/lib/backends.js +0 -81
- package/lib/base/keywords.js +32 -2
- package/lib/base/location.js +2 -2
- package/lib/base/message-registry.js +66 -4
- package/lib/base/messages.js +84 -27
- package/lib/base/model.js +2 -61
- package/lib/checks/arrayOfs.js +0 -1
- package/lib/checks/defaultValues.js +27 -2
- package/lib/checks/elements.js +1 -6
- package/lib/checks/enricher.js +8 -2
- package/lib/checks/foreignKeys.js +0 -6
- package/lib/checks/managedWithoutKeys.js +17 -0
- package/lib/checks/nonexpandableStructured.js +38 -0
- package/lib/checks/onConditions.js +9 -45
- package/lib/checks/queryNoDbArtifacts.js +27 -9
- package/lib/checks/selectItems.js +25 -2
- package/lib/checks/types.js +26 -2
- package/lib/checks/unknownMagic.js +38 -0
- package/lib/checks/utils.js +61 -0
- package/lib/checks/validator.js +66 -13
- package/lib/compiler/assert-consistency.js +24 -12
- package/lib/compiler/builtins.js +2 -0
- package/lib/compiler/checks.js +6 -4
- package/lib/compiler/definer.js +101 -39
- package/lib/compiler/index.js +88 -59
- package/lib/compiler/resolver.js +455 -209
- package/lib/compiler/shared.js +57 -33
- package/lib/edm/annotations/genericTranslation.js +183 -187
- package/lib/edm/csn2edm.js +128 -99
- package/lib/edm/edm.js +18 -21
- package/lib/edm/edmPreprocessor.js +361 -127
- package/lib/edm/edmUtils.js +103 -33
- package/lib/gen/Dictionary.json +74 -28
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +18 -4
- package/lib/gen/language.tokens +124 -118
- package/lib/gen/languageLexer.interp +13 -1
- package/lib/gen/languageLexer.js +870 -839
- package/lib/gen/languageLexer.tokens +116 -111
- package/lib/gen/languageParser.js +5894 -5614
- package/lib/json/from-csn.js +152 -67
- package/lib/json/to-csn.js +334 -135
- package/lib/language/antlrParser.js +4 -3
- package/lib/language/errorStrategy.js +1 -0
- package/lib/language/genericAntlrParser.js +24 -14
- package/lib/language/language.g4 +188 -128
- package/lib/main.d.ts +435 -0
- package/lib/main.js +31 -7
- package/lib/model/api.js +78 -0
- package/lib/model/csnRefs.js +463 -187
- package/lib/model/csnUtils.js +280 -136
- package/lib/model/enrichCsn.js +75 -4
- package/lib/model/revealInternalProperties.js +2 -1
- package/lib/modelCompare/compare.js +70 -25
- package/lib/optionProcessor.js +13 -10
- package/lib/render/.eslintrc.json +4 -1
- package/lib/render/DuplicateChecker.js +8 -5
- package/lib/render/toCdl.js +123 -40
- package/lib/render/toHdbcds.js +156 -65
- package/lib/render/toSql.js +87 -11
- package/lib/render/utils/common.js +55 -9
- package/lib/render/utils/sql.js +3 -3
- package/lib/sql-identifier.js +6 -1
- package/lib/transform/{sql → db}/.eslintrc.json +0 -0
- package/lib/transform/{sql → db}/assertUnique.js +7 -8
- package/lib/transform/{sql → db}/constraints.js +35 -20
- package/lib/transform/db/draft.js +353 -0
- package/lib/transform/db/expansion.js +582 -0
- package/lib/transform/db/flattening.js +325 -0
- package/lib/transform/{sql → db}/groupByOrderBy.js +8 -16
- package/lib/transform/{sql → db}/helpers.js +0 -0
- package/lib/transform/{sql → db}/transformExists.js +256 -60
- package/lib/transform/forHanaNew.js +216 -765
- package/lib/transform/forOdataNew.js +60 -56
- package/lib/transform/localized.js +48 -26
- package/lib/transform/odata/attachPath.js +19 -4
- package/lib/transform/odata/expandStructKeysInAssociations.js +2 -2
- package/lib/transform/odata/generateForeignKeyElements.js +13 -12
- package/lib/transform/odata/referenceFlattener.js +60 -36
- package/lib/transform/odata/sortByAssociationDependency.js +4 -4
- package/lib/transform/odata/structuralPath.js +76 -0
- package/lib/transform/odata/structureFlattener.js +21 -22
- package/lib/transform/odata/toFinalBaseType.js +5 -5
- package/lib/transform/odata/typesExposure.js +27 -17
- package/lib/transform/odata/utils.js +2 -2
- package/lib/transform/transformUtilsNew.js +141 -77
- package/lib/transform/translateAssocsToJoins.js +17 -14
- package/lib/transform/universalCsnEnricher.js +67 -0
- package/lib/utils/file.js +0 -11
- package/lib/utils/moduleResolve.js +6 -8
- package/lib/utils/timetrace.js +6 -1
- package/package.json +2 -1
- package/lib/base/deepCopy.js +0 -66
- package/lib/json/walker.js +0 -26
- package/lib/utils/string.js +0 -17
package/lib/json/to-csn.js
CHANGED
|
@@ -12,14 +12,21 @@
|
|
|
12
12
|
'use strict';
|
|
13
13
|
|
|
14
14
|
const { locationString } = require('../base/messages');
|
|
15
|
-
const { isDeprecatedEnabled } = require('../base/model');
|
|
15
|
+
const { isBetaEnabled, isDeprecatedEnabled } = require('../base/model');
|
|
16
16
|
|
|
17
17
|
const compilerVersion = require('../../package.json').version;
|
|
18
18
|
const creator = `CDS Compiler v${ compilerVersion }`;
|
|
19
19
|
const csnVersion = '2.0';
|
|
20
20
|
|
|
21
|
+
const normalizedKind = {
|
|
22
|
+
param: 'param',
|
|
23
|
+
action: 'action',
|
|
24
|
+
function: 'action',
|
|
25
|
+
};
|
|
26
|
+
|
|
21
27
|
/** @type {boolean|string} */
|
|
22
28
|
let gensrcFlavor = true; // good enough here...
|
|
29
|
+
let universalCsn = false;
|
|
23
30
|
let strictMode = false; // whether to dump with unknown properties (in standard)
|
|
24
31
|
let parensAsStrings = false;
|
|
25
32
|
let projectionAsQuery = false;
|
|
@@ -31,6 +38,7 @@ let dictionaryPrototype = null;
|
|
|
31
38
|
const transformers = {
|
|
32
39
|
// early and modifiers (without null / not null) ---------------------------
|
|
33
40
|
kind,
|
|
41
|
+
_outer: ( _, csn, node ) => addOrigin( csn, node ),
|
|
34
42
|
id: n => n, // in path item
|
|
35
43
|
doc: value,
|
|
36
44
|
'@': value,
|
|
@@ -50,7 +58,7 @@ const transformers = {
|
|
|
50
58
|
all: ignore, // XSN TODO use quantifier
|
|
51
59
|
// type properties (without 'elements') ------------------------------------
|
|
52
60
|
localized: value,
|
|
53
|
-
type
|
|
61
|
+
type,
|
|
54
62
|
length: value,
|
|
55
63
|
precision: value,
|
|
56
64
|
scale: value,
|
|
@@ -67,11 +75,12 @@ const transformers = {
|
|
|
67
75
|
columns,
|
|
68
76
|
expand: ignore, // do not list for select items as elements
|
|
69
77
|
inline: ignore, // do not list for select items as elements
|
|
70
|
-
excludingDict
|
|
78
|
+
excludingDict,
|
|
71
79
|
groupBy: arrayOf( expression ),
|
|
72
80
|
where: condition, // also pathItem after 'cardinality' before 'args'
|
|
73
81
|
having: condition,
|
|
74
82
|
args, // also pathItem after 'where', before 'on'/'orderBy'
|
|
83
|
+
suffix: node => [].concat( ...node.suffix.map( xprArg ) ),
|
|
75
84
|
orderBy: arrayOf( orderBy ), // TODO XSN: make `sort` and `nulls` sibling properties
|
|
76
85
|
sort: value,
|
|
77
86
|
nulls: value,
|
|
@@ -80,14 +89,14 @@ const transformers = {
|
|
|
80
89
|
offset: expression,
|
|
81
90
|
on: onCondition,
|
|
82
91
|
// definitions, extensions, members ----------------------------------------
|
|
83
|
-
returns:
|
|
92
|
+
returns: definition, // storing the return type of actions
|
|
84
93
|
notNull: value,
|
|
85
94
|
default: expression,
|
|
86
95
|
// targetElement: ignore, // special display of foreign key, renameTo: select
|
|
87
96
|
value: enumValue, // do not list for select items as elements
|
|
88
97
|
query,
|
|
89
98
|
elements,
|
|
90
|
-
actions
|
|
99
|
+
actions, // TODO: just normal dictionary
|
|
91
100
|
// special: top-level, cardinality -----------------------------------------
|
|
92
101
|
sources,
|
|
93
102
|
definitions: sortedDict,
|
|
@@ -128,7 +137,7 @@ const transformers = {
|
|
|
128
137
|
// which should appear at that place in order.
|
|
129
138
|
const csnPropertyNames = {
|
|
130
139
|
virtual: [ 'abstract' ], // abstract is compiler v1 CSN property
|
|
131
|
-
kind: [ 'annotate', 'extend' ],
|
|
140
|
+
kind: [ 'annotate', 'extend', '$origin' ],
|
|
132
141
|
op: [ 'join', 'func', 'xpr' ], // TODO: 'func','xpr' into 'quantifier'? TODO: 'global'(scope)?
|
|
133
142
|
quantifier: [
|
|
134
143
|
'some', 'any', 'distinct', // 'all' explicitly listed
|
|
@@ -148,7 +157,7 @@ const csnPropertyNames = {
|
|
|
148
157
|
name: [ 'as', 'cast' ],
|
|
149
158
|
location: [ '$env', '$location' ], // --enrich-csn
|
|
150
159
|
expectedKind: [
|
|
151
|
-
'_type', '_targetAspect', '_target', '_includes', '_links', '_art', '_scope',
|
|
160
|
+
'_origin', '_type', '_targetAspect', '_target', '_includes', '_links', '_art', '_scope',
|
|
152
161
|
], // --enrich-csn
|
|
153
162
|
};
|
|
154
163
|
|
|
@@ -183,6 +192,13 @@ const operators = {
|
|
|
183
192
|
notLike: ternary( [ 'not', 'like' ], [ 'escape' ] ),
|
|
184
193
|
when: exprs => [ 'when', ...exprs[0], 'then', ...exprs[1] ],
|
|
185
194
|
case: exprs => [ 'case' ].concat( ...exprs, [ 'end' ] ),
|
|
195
|
+
over: exprs => [ 'over', { xpr: [].concat( ...exprs ) } ],
|
|
196
|
+
orderBy: exprs => [
|
|
197
|
+
'order', 'by', ...exprs[0].concat( ...exprs.slice(1).map( e => [ ',', ...e ] ) ),
|
|
198
|
+
],
|
|
199
|
+
partitionBy: exprs => [
|
|
200
|
+
'partition', 'by', ...exprs[0].concat( ...exprs.slice(1).map( e => [ ',', ...e ] ) ),
|
|
201
|
+
],
|
|
186
202
|
// xpr: (exprs) => [].concat( ...exprs ), see below - handled extra
|
|
187
203
|
};
|
|
188
204
|
|
|
@@ -194,7 +210,7 @@ const csnDirectValues = [ 'val' ]; // + all starting with '@' - TODO: still rele
|
|
|
194
210
|
/**
|
|
195
211
|
* Sort property names of CSN according to sequence which is also used by the compactModel function
|
|
196
212
|
* Only returns enumerable properties, except for certain hidden properties
|
|
197
|
-
* if requested (cloneOptions != false): $location,
|
|
213
|
+
* if requested (cloneOptions != false): $location, elements.
|
|
198
214
|
*
|
|
199
215
|
* If cloneOptions is false or if either cloneOptions.testMode or cloneOptions.testSortCsn
|
|
200
216
|
* are set, definitions are also sorted.
|
|
@@ -224,24 +240,36 @@ function sortCsn( csn, cloneOptions = false ) {
|
|
|
224
240
|
r[n] = sortCsn(val, cloneOptions);
|
|
225
241
|
}
|
|
226
242
|
if (cloneOptions && typeof csn === 'object') {
|
|
227
|
-
if (csn
|
|
228
|
-
setHidden(r, '$sources', csn.$sources);
|
|
229
|
-
if (csn
|
|
230
|
-
setHidden(r, '$location', csn.$location);
|
|
231
|
-
if (csn
|
|
232
|
-
setHidden(r, '$
|
|
233
|
-
if (csn
|
|
234
|
-
setHidden(r, '$
|
|
235
|
-
if (csn
|
|
236
|
-
setHidden(r, '
|
|
237
|
-
if (csn
|
|
238
|
-
setHidden(r, '
|
|
239
|
-
if (csn.$tableConstraints && !r.$tableConstraints)
|
|
240
|
-
setHidden(r, '$tableConstraints', csn.$tableConstraints);
|
|
243
|
+
if ({}.hasOwnProperty.call( csn, '$sources' ) && !r.$sources)
|
|
244
|
+
setHidden( r, '$sources', csn.$sources );
|
|
245
|
+
if ({}.hasOwnProperty.call( csn, '$location' ) && !r.$location)
|
|
246
|
+
setHidden( r, '$location', csn.$location );
|
|
247
|
+
if ({}.hasOwnProperty.call( csn, '$path' )) // used in generic reference flattener
|
|
248
|
+
setHidden( r, '$path', csn.$path );
|
|
249
|
+
if ({}.hasOwnProperty.call( csn, '$paths' )) // used in generic reference flattener
|
|
250
|
+
setHidden( r, '$paths', csn.$paths );
|
|
251
|
+
if (hasNonEnumerable( csn, 'elements' ) && !r.elements) // non-enumerable 'elements'
|
|
252
|
+
setHidden( r, 'elements', csnDictionary( csn.elements, false, cloneOptions ) );
|
|
253
|
+
if (hasNonEnumerable( csn, '$tableConstraints' ) && !r.$tableConstraints)
|
|
254
|
+
setHidden( r, '$tableConstraints', csn.$tableConstraints );
|
|
241
255
|
}
|
|
242
256
|
return r;
|
|
243
257
|
}
|
|
244
258
|
|
|
259
|
+
/**
|
|
260
|
+
* Check wether the given object has non enumerable property.
|
|
261
|
+
* Ensure that we don't take it from the prototype, only "directly" - we accidentally
|
|
262
|
+
* cloned elements with a cds.linked input otherwise.
|
|
263
|
+
*
|
|
264
|
+
* @param {object} object
|
|
265
|
+
* @param {string} property
|
|
266
|
+
* @returns
|
|
267
|
+
*/
|
|
268
|
+
function hasNonEnumerable(object, property) {
|
|
269
|
+
return {}.hasOwnProperty.call( object, property ) &&
|
|
270
|
+
!{}.propertyIsEnumerable.call( object, property );
|
|
271
|
+
}
|
|
272
|
+
|
|
245
273
|
/**
|
|
246
274
|
* @param {object} csn
|
|
247
275
|
* @param {boolean} sort
|
|
@@ -283,6 +311,7 @@ function compactModel( model, options = model.options || {} ) {
|
|
|
283
311
|
csn.requires = using;
|
|
284
312
|
}
|
|
285
313
|
// 'namespace' for complete model is 'namespace' of first source
|
|
314
|
+
// (not a really useful property at all, avoids XSN inspection by Umbrella)
|
|
286
315
|
for (const first in srcDict) {
|
|
287
316
|
const { namespace } = srcDict[first];
|
|
288
317
|
if (namespace && namespace.path)
|
|
@@ -352,10 +381,12 @@ function usings( srcDict ) {
|
|
|
352
381
|
* @param {object} csn
|
|
353
382
|
* @param {object} model
|
|
354
383
|
*/
|
|
384
|
+
|
|
385
|
+
|
|
355
386
|
function extensions( node, csn, model ) {
|
|
356
387
|
if (model.kind && model.kind !== 'source')
|
|
357
388
|
return undefined;
|
|
358
|
-
const exts = node.map(
|
|
389
|
+
const exts = node.map( definition );
|
|
359
390
|
|
|
360
391
|
// builtins are non-enumerable for smaller display
|
|
361
392
|
for (const name of Object.getOwnPropertyNames( model.definitions || {} ).sort()) {
|
|
@@ -370,17 +401,21 @@ function extensions( node, csn, model ) {
|
|
|
370
401
|
}
|
|
371
402
|
else if (gensrcFlavor) {
|
|
372
403
|
// From definitions (without redefinitions) with potential inferred elements:
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
if (
|
|
380
|
-
annotate.
|
|
381
|
-
|
|
382
|
-
|
|
404
|
+
const annotate = { annotate: name };
|
|
405
|
+
if (art.$inferred)
|
|
406
|
+
Object.assign( annotate, annotationsAndDocComment( art, true ) );
|
|
407
|
+
if (art.$expand === 'annotate') {
|
|
408
|
+
if (art.actions)
|
|
409
|
+
attachAnnotations( annotate, 'actions', art.actions, art.$inferred );
|
|
410
|
+
else if (art.params)
|
|
411
|
+
attachAnnotations( annotate, 'params', art.params, art.$inferred );
|
|
412
|
+
const obj = art.returns || art;
|
|
413
|
+
const elems = (obj.items || obj).elements; // no targetAspect here
|
|
414
|
+
if (elems)
|
|
415
|
+
attachAnnotations( annotate, 'elements', elems, art.$inferred, art.returns );
|
|
383
416
|
}
|
|
417
|
+
if (Object.keys( annotate ).length > 1)
|
|
418
|
+
exts.push( annotate );
|
|
384
419
|
}
|
|
385
420
|
}
|
|
386
421
|
|
|
@@ -388,12 +423,64 @@ function extensions( node, csn, model ) {
|
|
|
388
423
|
(a, b) => (a.annotate || a.extend).localeCompare( b.annotate || b.extend )
|
|
389
424
|
);
|
|
390
425
|
|
|
426
|
+
/*
|
|
427
|
+
function attachElementAnnos( annotate, art ) {
|
|
428
|
+
while (art.items)
|
|
429
|
+
art = art.items;
|
|
430
|
+
if (art.elements) {
|
|
431
|
+
const elems = inferred( art.elements, art.$inferred );
|
|
432
|
+
if (Object.keys( elems ).length)
|
|
433
|
+
annotate.elements = elems;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function attachParamAnnos( annotate, art ) {
|
|
438
|
+
const inferredParent = art.$inferred;
|
|
439
|
+
if (art.params) {
|
|
440
|
+
const ext = Object.create( dictionaryPrototype );
|
|
441
|
+
for (const name in art.params) {
|
|
442
|
+
const par = art.params[name];
|
|
443
|
+
if (!inferredParent && !par.$inferred && par.$expand !== 'annotate')
|
|
444
|
+
continue;
|
|
445
|
+
const render = annotationsAndDocComment( par, true );
|
|
446
|
+
const subElems = par.$expand !== 'origin' && (par.items || par).elements;
|
|
447
|
+
if (subElems) {
|
|
448
|
+
const sub = inferred( subElems, par.$inferred );
|
|
449
|
+
if (Object.keys( sub ).length)
|
|
450
|
+
render.elements = sub;
|
|
451
|
+
}
|
|
452
|
+
if (Object.keys(render).length)
|
|
453
|
+
ext[name] = render;
|
|
454
|
+
}
|
|
455
|
+
if (obj.keys( ext ))
|
|
456
|
+
annotate.params = ext;
|
|
457
|
+
}
|
|
458
|
+
if (art.returns) {
|
|
459
|
+
const par = art.returns;
|
|
460
|
+
if (!inferredParent && !par.$inferred && par.$expand !== 'annotate')
|
|
461
|
+
return;
|
|
462
|
+
const render = annotationsAndDocComment( par, true );
|
|
463
|
+
const subElems = par.$expand !== 'origin' && (par.items || par).elements;
|
|
464
|
+
if (subElems) {
|
|
465
|
+
const sub = inferred( subElems, par.$inferred );
|
|
466
|
+
if (Object.keys( sub ).length)
|
|
467
|
+
render.elements = sub;
|
|
468
|
+
}
|
|
469
|
+
if (Object.keys(render).length)
|
|
470
|
+
const sub = inferred( subElems, par.$inferred );
|
|
471
|
+
if (Object.keys( sub ).length)
|
|
472
|
+
render.elements = sub;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return ext;
|
|
476
|
+
*/
|
|
477
|
+
|
|
391
478
|
// extract namespace/builtin annotations
|
|
392
479
|
function extractAnnotationsToExtension( art ) {
|
|
393
480
|
const name = art.name.absolute;
|
|
394
481
|
// 'true' because annotations on namespaces and builtins can only
|
|
395
482
|
// happen through extensions.
|
|
396
|
-
const annos =
|
|
483
|
+
const annos = annotationsAndDocComment( art, true );
|
|
397
484
|
const annotate = Object.assign( { annotate: name }, annos );
|
|
398
485
|
if (Object.keys( annotate ).length > 1) {
|
|
399
486
|
const loc = locationForAnnotationExtension();
|
|
@@ -433,8 +520,13 @@ function i18n( i18nNode ) {
|
|
|
433
520
|
}
|
|
434
521
|
|
|
435
522
|
function sources( srcDict, csn ) {
|
|
523
|
+
const names = Object.keys( srcDict );
|
|
524
|
+
const $sources = names.length && srcDict[names[0]].$sources;
|
|
525
|
+
if ($sources) {
|
|
526
|
+
setHidden( csn, '$sources', $sources );
|
|
527
|
+
return undefined;
|
|
528
|
+
}
|
|
436
529
|
// TODO: sort according to some layering order, see #6368
|
|
437
|
-
const names = Object.keys( srcDict);
|
|
438
530
|
setHidden( csn, '$sources', (!strictMode) ? names : names.map( relativeName ) );
|
|
439
531
|
return undefined;
|
|
440
532
|
|
|
@@ -444,17 +536,29 @@ function sources( srcDict, csn ) {
|
|
|
444
536
|
}
|
|
445
537
|
}
|
|
446
538
|
|
|
447
|
-
function
|
|
448
|
-
const
|
|
449
|
-
for (const name in
|
|
450
|
-
const elem =
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
539
|
+
function attachAnnotations( annotate, prop, dict, inferred, returns = false ) {
|
|
540
|
+
const annoDict = Object.create( dictionaryPrototype );
|
|
541
|
+
for (const name in dict) {
|
|
542
|
+
const elem = dict[name];
|
|
543
|
+
const inf = inferred || elem.$inferred; // is probably always inferred if parent was
|
|
544
|
+
const sub = (inf) ? annotationsAndDocComment( elem, true ) : {};
|
|
545
|
+
if (elem.$expand === 'annotate') {
|
|
546
|
+
if (elem.params)
|
|
547
|
+
attachAnnotations( sub, 'params', elem.params, inf );
|
|
548
|
+
const obj = elem.returns || elem;
|
|
549
|
+
const elems = (obj.items || obj.targetAspect || obj).elements;
|
|
550
|
+
if (elems)
|
|
551
|
+
attachAnnotations( sub, 'elements', elems, inf, elem.returns );
|
|
552
|
+
}
|
|
553
|
+
if (Object.keys( sub ).length)
|
|
554
|
+
annoDict[name] = sub;
|
|
555
|
+
}
|
|
556
|
+
if (Object.keys( annoDict ).length) {
|
|
557
|
+
if (returns)
|
|
558
|
+
annotate.returns = { elements: annoDict };
|
|
559
|
+
else
|
|
560
|
+
annotate[prop] = annoDict;
|
|
456
561
|
}
|
|
457
|
-
return ext;
|
|
458
562
|
}
|
|
459
563
|
|
|
460
564
|
function standard( node ) {
|
|
@@ -493,54 +597,79 @@ function set( prop, csn, node ) {
|
|
|
493
597
|
}
|
|
494
598
|
|
|
495
599
|
function targetAspect( val, csn, node ) {
|
|
600
|
+
const ta = (val.elements)
|
|
601
|
+
? addLocation( val.location, standard( val ) )
|
|
602
|
+
: artifactRef( val, true );
|
|
496
603
|
if (!gensrcFlavor || node.target && !node.target.$inferred)
|
|
497
|
-
return
|
|
604
|
+
return ta;
|
|
498
605
|
// For compatibility, put aspect in 'target' with parse.cdl and csn flavor 'gensrc'
|
|
499
|
-
csn.target =
|
|
606
|
+
csn.target = ta;
|
|
500
607
|
return undefined;
|
|
501
608
|
}
|
|
502
609
|
|
|
503
610
|
function target( val, _csn, node ) {
|
|
504
611
|
if (gensrcFlavor && node._origin && node._origin.$inferred === 'REDIRECTED')
|
|
505
612
|
val = node._origin.target;
|
|
506
|
-
if (
|
|
613
|
+
if (val.elements)
|
|
614
|
+
return standard( val ); // elements in target (parse-cdl)
|
|
615
|
+
if (!universalCsn || node.on)
|
|
507
616
|
return artifactRef( val, true );
|
|
508
|
-
|
|
617
|
+
const tref = artifactRef( val, true );
|
|
618
|
+
const proto = node.type && !node.type.$inferred ? node.type._artifact : node._origin;
|
|
619
|
+
return (proto && proto.target && artifactRef( proto.target, true ) === tref)
|
|
620
|
+
? undefined
|
|
621
|
+
: tref;
|
|
509
622
|
}
|
|
510
623
|
|
|
511
624
|
function items( obj, csn, node ) {
|
|
512
|
-
if (!keepElements( node )
|
|
513
|
-
// no 'elements' with SELECT or inferred elements with gensrc;
|
|
514
|
-
// hidden 'elements' will be set in query()
|
|
625
|
+
if (!keepElements( node ))
|
|
515
626
|
return undefined;
|
|
516
|
-
return standard( obj );
|
|
627
|
+
return standard( obj ); // no 'elements' with inferred elements with gensrc
|
|
517
628
|
}
|
|
518
629
|
|
|
519
630
|
function elements( dict, csn, node ) {
|
|
520
|
-
if (
|
|
631
|
+
if (node.from || // do not directly show query elements here
|
|
521
632
|
gensrcFlavor && (node.query || node.type) ||
|
|
522
|
-
|
|
633
|
+
!keepElements( node ))
|
|
523
634
|
// no 'elements' with SELECT or inferred elements with gensrc;
|
|
524
|
-
// hidden 'elements' will be set in query()
|
|
635
|
+
// hidden or visible 'elements' will be set in query()
|
|
525
636
|
return undefined;
|
|
526
637
|
return insertOrderDict( dict );
|
|
527
638
|
}
|
|
528
639
|
|
|
529
|
-
|
|
530
|
-
|
|
640
|
+
function enumerableQueryElements( select ) {
|
|
641
|
+
if (!universalCsn || select === select._main._leadingQuery)
|
|
642
|
+
return false;
|
|
643
|
+
if (select.orderBy || select.$orderBy)
|
|
644
|
+
return true;
|
|
645
|
+
const alias = select._parent;
|
|
646
|
+
return alias.query && (alias.query._leadingQuery || alias.query) === select;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// Should we render the elements? (and items?)
|
|
531
650
|
function keepElements( node ) {
|
|
651
|
+
if (universalCsn)
|
|
652
|
+
// $expand = null/undefined: not elements not via expansion
|
|
653
|
+
// $expand = 'target'/'annotate': with redirections / individual annotations
|
|
654
|
+
return node.$expand !== 'origin';
|
|
655
|
+
if (!node.type || node.kind === 'type')
|
|
656
|
+
return true;
|
|
657
|
+
// even if expanded elements have no new target or direct annotation,
|
|
658
|
+
// they might have got one via propagation – any new target/annos during their
|
|
659
|
+
// way from the original structure type definition to the current usage
|
|
532
660
|
while (node) {
|
|
533
661
|
if (node.$expand !== 'origin')
|
|
534
662
|
return true;
|
|
535
663
|
node = node._origin;
|
|
536
664
|
}
|
|
537
|
-
|
|
665
|
+
// all in _origin chain only have expanded elements with 'origin':
|
|
666
|
+
return false; // no need to render elements
|
|
538
667
|
}
|
|
539
668
|
|
|
540
669
|
// for gensrcFlavor and namespace/builtin annotation extraction:
|
|
541
670
|
// return annotations from definition (annotated==false)
|
|
542
671
|
// or annotations (annotated==true)
|
|
543
|
-
function
|
|
672
|
+
function annotationsAndDocComment( node, annotated ) {
|
|
544
673
|
const csn = {};
|
|
545
674
|
const transformer = transformers['@'];
|
|
546
675
|
const keys = Object.keys( node ).filter( a => a.charAt(0) === '@' ).sort();
|
|
@@ -557,6 +686,8 @@ function annotations( node, annotated ) {
|
|
|
557
686
|
csn[prop] = sub;
|
|
558
687
|
}
|
|
559
688
|
}
|
|
689
|
+
if (node.doc)
|
|
690
|
+
csn.doc = transformers.doc(node.doc);
|
|
560
691
|
return csn;
|
|
561
692
|
}
|
|
562
693
|
|
|
@@ -618,17 +749,17 @@ function sortedDict( dict ) {
|
|
|
618
749
|
return dictionary( dict, keys );
|
|
619
750
|
}
|
|
620
751
|
|
|
621
|
-
function
|
|
752
|
+
function actions( dict ) {
|
|
622
753
|
const keys = Object.keys( dict );
|
|
623
754
|
return (keys.length)
|
|
624
|
-
? dictionary( dict, keys )
|
|
755
|
+
? dictionary( dict, keys, 'actions' )
|
|
625
756
|
: undefined;
|
|
626
757
|
}
|
|
627
758
|
|
|
628
|
-
function dictionary( dict, keys ) {
|
|
759
|
+
function dictionary( dict, keys, prop ) {
|
|
629
760
|
const csn = Object.create( dictionaryPrototype );
|
|
630
761
|
for (const name of keys) {
|
|
631
|
-
const def = definition( dict[name] );
|
|
762
|
+
const def = definition( dict[name], null, null, prop );
|
|
632
763
|
if (def !== undefined)
|
|
633
764
|
csn[name] = def;
|
|
634
765
|
}
|
|
@@ -636,6 +767,8 @@ function dictionary( dict, keys ) {
|
|
|
636
767
|
}
|
|
637
768
|
|
|
638
769
|
function foreignKeys( dict, csn, node ) {
|
|
770
|
+
if (universalCsn && !target( node.target, csn, node ))
|
|
771
|
+
return;
|
|
639
772
|
if (gensrcFlavor && node._origin && node._origin.$inferred === 'REDIRECTED')
|
|
640
773
|
dict = node._origin.foreignKeys;
|
|
641
774
|
const keys = [];
|
|
@@ -649,7 +782,7 @@ function foreignKeys( dict, csn, node ) {
|
|
|
649
782
|
csn.keys = keys;
|
|
650
783
|
}
|
|
651
784
|
|
|
652
|
-
function definition( art ) {
|
|
785
|
+
function definition( art, _csn, _node, prop ) {
|
|
653
786
|
if (!art || typeof art !== 'object')
|
|
654
787
|
return undefined; // TODO: complain with strict
|
|
655
788
|
// Do not include namespace definitions or inferred construct (in gensrc):
|
|
@@ -661,22 +794,79 @@ function definition( art ) {
|
|
|
661
794
|
addLocation( art.targetElement.location, key );
|
|
662
795
|
return extra( key, art );
|
|
663
796
|
}
|
|
664
|
-
|
|
797
|
+
const c = standard( art );
|
|
798
|
+
// The XSN of actions in extensions do not contain a returns yet - TODO?
|
|
799
|
+
const elems = c.elements;
|
|
800
|
+
if (elems && (prop === 'actions' || art.$syntax === 'returns')) {
|
|
801
|
+
delete c.elements;
|
|
802
|
+
c.returns = { elements: elems };
|
|
803
|
+
}
|
|
804
|
+
return c;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
function addOrigin( csn, xsn ) {
|
|
808
|
+
if (!universalCsn)
|
|
809
|
+
return csn;
|
|
810
|
+
if (xsn._from) {
|
|
811
|
+
csn.$origin = originRef( xsn._from[0]._origin );
|
|
812
|
+
}
|
|
813
|
+
else if (xsn.includes && xsn.includes.length > 1) {
|
|
814
|
+
csn.$origin = { $origin: originRef( xsn.includes[0]._artifact ) };
|
|
815
|
+
}
|
|
816
|
+
else if (xsn._origin && !hasExplicitProp( xsn.type ) && xsn._origin.kind !== 'builtin') {
|
|
817
|
+
let origin = xsn._origin;
|
|
818
|
+
while (origin._parent && origin._parent.$expand === 'origin')
|
|
819
|
+
origin = origin._origin || origin.type._artifact;
|
|
820
|
+
csn.$origin = originRef( origin );
|
|
821
|
+
}
|
|
822
|
+
return csn;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
function hasExplicitProp( ref ) {
|
|
826
|
+
return ref && !ref.$inferred;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
function originRef( art ) {
|
|
830
|
+
const r = [];
|
|
831
|
+
// do not use name.element, as we allow `.`s in name
|
|
832
|
+
let main = art;
|
|
833
|
+
while (main._main && main.kind !== 'select') {
|
|
834
|
+
const nkind = normalizedKind[main.kind];
|
|
835
|
+
if (main.name.id || !r.length) // { param: "" } only for return, not elements inside
|
|
836
|
+
r.push( nkind ? { [nkind]: main.name.id } : main.name.id );
|
|
837
|
+
main = main._parent;
|
|
838
|
+
}
|
|
839
|
+
if (main._main) // well, an element of an query in FROM
|
|
840
|
+
return definition( art ); // use $origin: {}
|
|
841
|
+
// for sub query in FROM in sub query in FROM, we could condense the info
|
|
842
|
+
r.push( art.name.absolute );
|
|
843
|
+
r.reverse();
|
|
844
|
+
return r;
|
|
665
845
|
}
|
|
666
846
|
|
|
667
847
|
function kind( k, csn, node ) {
|
|
668
|
-
if (
|
|
848
|
+
if (k === 'annotate' || k === 'extend') {
|
|
669
849
|
// We just use `name.absolute` because it is very likely a "constructed"
|
|
670
850
|
// extensions. The CSN parser must produce name.path like for other refs.
|
|
671
|
-
|
|
672
|
-
|
|
851
|
+
if (!node._main)
|
|
852
|
+
csn[k] = node.name.absolute || artifactRef( node.name, true );
|
|
853
|
+
else if (k === 'extend')
|
|
854
|
+
csn.kind = k;
|
|
673
855
|
}
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
856
|
+
else {
|
|
857
|
+
if (![
|
|
858
|
+
'element', 'key', 'param', 'enum', 'select', '$join',
|
|
859
|
+
'$tableAlias', 'annotation', 'mixin',
|
|
860
|
+
].includes(k))
|
|
861
|
+
csn.kind = k;
|
|
862
|
+
addOrigin( csn, node );
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
function type( node, csn, xsn ) {
|
|
867
|
+
if (universalCsn && node.$inferred && xsn._origin)
|
|
678
868
|
return undefined;
|
|
679
|
-
return
|
|
869
|
+
return artifactRef( node, !node.$extra );
|
|
680
870
|
}
|
|
681
871
|
|
|
682
872
|
function artifactRef( node, terse ) {
|
|
@@ -778,10 +968,12 @@ function args( node ) {
|
|
|
778
968
|
return dict;
|
|
779
969
|
}
|
|
780
970
|
|
|
781
|
-
// "Short" value form, e.g. for annotation assignments
|
|
782
971
|
function value( node ) {
|
|
972
|
+
// "Short" value form, e.g. for annotation assignments
|
|
783
973
|
if (!node)
|
|
784
974
|
return true; // `@aBool` short for `@aBool: true`
|
|
975
|
+
if (universalCsn && node.$inferred === 'prop') // via propagator.js
|
|
976
|
+
return undefined;
|
|
785
977
|
if (node.$inferred && gensrcFlavor)
|
|
786
978
|
return undefined;
|
|
787
979
|
if (node.path) {
|
|
@@ -792,6 +984,8 @@ function value( node ) {
|
|
|
792
984
|
return extra( { '#': node.sym.id }, node );
|
|
793
985
|
if (node.literal === 'array')
|
|
794
986
|
return node.val.map( value );
|
|
987
|
+
if (node.literal === 'token' && node.val === '...')
|
|
988
|
+
return extra( { '...': true } );
|
|
795
989
|
if (node.literal !== 'struct')
|
|
796
990
|
// no val (undefined) as true only for annotation values (and struct elem values)
|
|
797
991
|
return node.name && !('val' in node) || node.val;
|
|
@@ -821,23 +1015,8 @@ function onCondition( cond, csn, node ) {
|
|
|
821
1015
|
|
|
822
1016
|
function condition( node ) {
|
|
823
1017
|
const expr = expression( node );
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
// TODO: quoted magic names like $now should be complained about in the compiler
|
|
828
|
-
|
|
829
|
-
function pathRef( path ) {
|
|
830
|
-
const ref = { ref: path.map( pathItem ) };
|
|
831
|
-
const nav = path[0]._navigation;
|
|
832
|
-
if (nav && nav.kind !== '$self' && nav.kind !== 'element' && nav.name.select != null) {
|
|
833
|
-
setHidden( ref, '$env', (nav.kind === '$navElement')
|
|
834
|
-
? nav.name.alias
|
|
835
|
-
: nav.name.select );
|
|
836
|
-
}
|
|
837
|
-
else if ( path[0]._artifact && path[0]._artifact.query ) {
|
|
838
|
-
setHidden( ref, '$env', true );
|
|
839
|
-
}
|
|
840
|
-
return ref;
|
|
1018
|
+
// we do not set a hidden $parens on array - we could still do it if requested
|
|
1019
|
+
return !expr.cast && !expr.func && expr.xpr || [ expr ];
|
|
841
1020
|
}
|
|
842
1021
|
|
|
843
1022
|
function expression( node, dollarExtra ) {
|
|
@@ -852,8 +1031,8 @@ function expression( node, dollarExtra ) {
|
|
|
852
1031
|
return { ref: [ node.param.val ], param: true }; // CDL rule for runtimes
|
|
853
1032
|
}
|
|
854
1033
|
if (node.path) {
|
|
855
|
-
//
|
|
856
|
-
return extra(
|
|
1034
|
+
// we would need to consider node.global here if we introduce that
|
|
1035
|
+
return extra( { ref: node.path.map( pathItem ) }, dollarExtraNode );
|
|
857
1036
|
}
|
|
858
1037
|
if (node.literal) {
|
|
859
1038
|
if (typeof node.val === node.literal || node.val === null)
|
|
@@ -877,37 +1056,32 @@ function expression( node, dollarExtra ) {
|
|
|
877
1056
|
arg0.xpr.unshift( quantifier.val );
|
|
878
1057
|
}
|
|
879
1058
|
}
|
|
1059
|
+
if (node.suffix)
|
|
1060
|
+
call.xpr = [].concat( ...node.suffix.map( xprArg ) );
|
|
880
1061
|
return extra( call, dollarExtraNode );
|
|
881
1062
|
}
|
|
882
1063
|
if (node.query)
|
|
883
|
-
return query( node.query );
|
|
1064
|
+
return query( node.query, null, null, null, 1 );
|
|
884
1065
|
if (!node.op) // parse error
|
|
885
1066
|
return { xpr: [] };
|
|
886
1067
|
else if (node.op.val === 'xpr')
|
|
887
1068
|
// do not use xpr() for xpr, as it would flatten inner xpr's
|
|
888
|
-
return extra({ xpr: node.args.map( expression ) }, dollarExtraNode );
|
|
1069
|
+
return extra({ xpr: node.args.map( expression ) }, dollarExtraNode, 1 );
|
|
889
1070
|
else if (node.op.val === 'cast')
|
|
890
1071
|
return cast( expression( node.args[0] ), dollarExtraNode );
|
|
891
1072
|
// from here on: CDL input (no $extra possible - but $parens)
|
|
892
1073
|
else if (node.op.val !== ',')
|
|
893
|
-
return extra( { xpr: xpr( node ) }, dollarExtraNode );
|
|
1074
|
+
return extra( { xpr: xpr( node ) }, dollarExtraNode, (dollarExtra === 'sub-xpr' ? 1 : 0) );
|
|
894
1075
|
return (parensAsStrings)
|
|
895
1076
|
? { xpr: [ '(', ...xpr( node ), ')' ] }
|
|
896
|
-
|
|
1077
|
+
// the inner parens belong to the tuple construct, i.e. won't count as parens
|
|
1078
|
+
: extra( { list: node.args.map( expression ) }, dollarExtraNode, 0 );
|
|
897
1079
|
}
|
|
898
1080
|
|
|
899
1081
|
function xpr( node ) {
|
|
900
1082
|
// if (!node.op) console.log(node)
|
|
901
1083
|
const op = operators[node.op.val] || node.op.val.split(' ');
|
|
902
|
-
const exprs = node.args.map(
|
|
903
|
-
const expr = expression( sub );
|
|
904
|
-
// return !sub.$parens && !expr.cast && expr.xpr || [ expr ]; if parensAsStrings is gone
|
|
905
|
-
if (expr.cast || !expr.xpr || sub.$parens && !parensAsStrings)
|
|
906
|
-
return [ expr ];
|
|
907
|
-
else if (sub.$parens && sub.op.val !== ',')
|
|
908
|
-
return [ '(', ...expr.xpr, ')' ];
|
|
909
|
-
return expr.xpr;
|
|
910
|
-
} );
|
|
1084
|
+
const exprs = node.args.map( xprArg );
|
|
911
1085
|
if (op instanceof Function)
|
|
912
1086
|
return op( exprs );
|
|
913
1087
|
if (node.quantifier)
|
|
@@ -917,6 +1091,27 @@ function xpr( node ) {
|
|
|
917
1091
|
return exprs[0].concat( ...exprs.slice(1).map( a => [ ...op, ...a ] ) );
|
|
918
1092
|
}
|
|
919
1093
|
|
|
1094
|
+
function xprArg( sub ) {
|
|
1095
|
+
const realXpr = sub.op && sub.op.val === 'xpr';
|
|
1096
|
+
const expr = expression( sub, 'sub-xpr' );
|
|
1097
|
+
// `sort`/`nulls` will be attached to arguments of orderBy
|
|
1098
|
+
// which might be either `path`s or `xpr`s
|
|
1099
|
+
const sortAndNulls = [];
|
|
1100
|
+
if (sub.sort)
|
|
1101
|
+
sortAndNulls.push( sub.sort.val );
|
|
1102
|
+
if (sub.nulls)
|
|
1103
|
+
sortAndNulls.push( ...[ 'nulls', sub.nulls.val ] );
|
|
1104
|
+
// return !sub.$parens && !expr.cast && !expr.func && expr.xpr || [ expr ];
|
|
1105
|
+
// if parensAsStrings is gone
|
|
1106
|
+
if (realXpr || expr.cast || expr.func || !expr.xpr || sub.$parens && !parensAsStrings)
|
|
1107
|
+
return [ expr, ...sortAndNulls ];
|
|
1108
|
+
else if (sub.$parens && sub.op.val !== ',')
|
|
1109
|
+
return [ '(', ...expr.xpr, ')' ];
|
|
1110
|
+
|
|
1111
|
+
expr.xpr.push( ...sortAndNulls );
|
|
1112
|
+
return expr.xpr;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
920
1115
|
function ternary( op1, op2 ) {
|
|
921
1116
|
return function ternaryOp( exprs ) {
|
|
922
1117
|
return (exprs[2])
|
|
@@ -940,16 +1135,15 @@ function binaryRightParen( op ) {
|
|
|
940
1135
|
};
|
|
941
1136
|
}
|
|
942
1137
|
|
|
943
|
-
function query( node, csn, xsn ) {
|
|
944
|
-
while (Array.isArray(node)) // in parentheses -> remove
|
|
945
|
-
node = node[0];
|
|
1138
|
+
function query( node, csn, xsn, _prop, expectedParens = 0 ) {
|
|
946
1139
|
if (node.op.val === 'SELECT') {
|
|
947
1140
|
if (xsn && xsn.query === node && xsn.$syntax === 'projection' &&
|
|
948
1141
|
node.from && node.from.path && !projectionAsQuery) {
|
|
949
1142
|
csn.projection = standard( node );
|
|
950
1143
|
return undefined;
|
|
951
1144
|
}
|
|
952
|
-
const select = { SELECT: standard( node ) };
|
|
1145
|
+
const select = { SELECT: extra( standard( node ), node, expectedParens ) };
|
|
1146
|
+
// one paren pair is not put into XSN - TODO: change that?
|
|
953
1147
|
const elems = node.elements;
|
|
954
1148
|
if (elems && node._main && node !== node._main._leadingQuery && gensrcFlavor !== true) {
|
|
955
1149
|
// Set hidden 'elements' for csnRefs.js. In select-item subqueries,
|
|
@@ -958,7 +1152,10 @@ function query( node, csn, xsn ) {
|
|
|
958
1152
|
const gensrcSaved = gensrcFlavor;
|
|
959
1153
|
try {
|
|
960
1154
|
gensrcFlavor = false;
|
|
961
|
-
|
|
1155
|
+
if (enumerableQueryElements( node ))
|
|
1156
|
+
select.SELECT.elements = insertOrderDict( elems );
|
|
1157
|
+
else
|
|
1158
|
+
setHidden( select.SELECT, 'elements', insertOrderDict( elems ) );
|
|
962
1159
|
}
|
|
963
1160
|
finally {
|
|
964
1161
|
gensrcFlavor = gensrcSaved;
|
|
@@ -995,11 +1192,13 @@ function columns( xsnColumns, csn, xsn ) {
|
|
|
995
1192
|
return csnColumns;
|
|
996
1193
|
}
|
|
997
1194
|
|
|
1195
|
+
function excludingDict( xsnDict, csn, xsn ) {
|
|
1196
|
+
if (xsn.kind !== 'element')
|
|
1197
|
+
csn.excluding = Object.keys( xsnDict );
|
|
1198
|
+
}
|
|
1199
|
+
|
|
998
1200
|
function from( node ) {
|
|
999
|
-
|
|
1000
|
-
node = node[0];
|
|
1001
|
-
// TODO: CSN: FROM ((SELECT...)) as -> also add 'subquery' op? - Together
|
|
1002
|
-
// with []-elimination in FROM... -> normal standard()
|
|
1201
|
+
// TODO: can we use the normal standard(), at least with JOIN?
|
|
1003
1202
|
if (node.join) {
|
|
1004
1203
|
const join = { join: node.join.val };
|
|
1005
1204
|
set( 'cardinality', join, node );
|
|
@@ -1008,7 +1207,7 @@ function from( node ) {
|
|
|
1008
1207
|
return extra( join, node );
|
|
1009
1208
|
}
|
|
1010
1209
|
else if (node.query) {
|
|
1011
|
-
return addExplicitAs( query( node.query ), node.name );
|
|
1210
|
+
return addExplicitAs( query( node.query, null, null, null, 1 ), node.name );
|
|
1012
1211
|
}
|
|
1013
1212
|
else if (!node._artifact || node._artifact._main) { // CQL or follow assoc
|
|
1014
1213
|
return extra( addExplicitAs( artifactRef( node, false ), node.name ), node );
|
|
@@ -1024,7 +1223,7 @@ function addElementAsColumn( elem, cols ) {
|
|
|
1024
1223
|
if (elem.$inferred === '*')
|
|
1025
1224
|
return;
|
|
1026
1225
|
// only list annotations here which are provided directly with definition
|
|
1027
|
-
const col = (gensrcFlavor) ?
|
|
1226
|
+
const col = (gensrcFlavor) ? annotationsAndDocComment( elem, false ) : {};
|
|
1028
1227
|
// with `client` flavor, assignments are available at the element
|
|
1029
1228
|
const gensrcSaved = gensrcFlavor;
|
|
1030
1229
|
|
|
@@ -1034,33 +1233,29 @@ function addElementAsColumn( elem, cols ) {
|
|
|
1034
1233
|
set( 'key', col, elem );
|
|
1035
1234
|
const expr = expression( elem.value, true );
|
|
1036
1235
|
Object.assign( col, (expr.cast ? { xpr: [ expr ] } : expr) );
|
|
1236
|
+
gensrcFlavor = gensrcSaved; // for not having annotations in inline etc
|
|
1037
1237
|
if (elem.expand)
|
|
1038
1238
|
col.expand = columns( elem.expand );
|
|
1039
1239
|
if (elem.inline)
|
|
1040
1240
|
col.inline = columns( elem.inline );
|
|
1241
|
+
gensrcFlavor = gensrcFlavor || 'column';
|
|
1242
|
+
if (elem.excludingDict)
|
|
1243
|
+
col.excluding = Object.keys( elem.excludingDict );
|
|
1041
1244
|
// yes, the AS comes after the EXPAND
|
|
1042
1245
|
addExplicitAs( col, elem.name, neqPath( elem.value ) );
|
|
1043
|
-
//
|
|
1044
|
-
if (!expr.cast)
|
|
1045
|
-
|
|
1046
|
-
setHidden( col, '$env', expr.$env );
|
|
1047
|
-
if (expr.elements)
|
|
1048
|
-
setHidden( col, 'elements', expr.elements );
|
|
1049
|
-
}
|
|
1246
|
+
// elements of sub queries (in expr) are hidden (not set via Object.assign):
|
|
1247
|
+
if (!expr.cast && expr.elements)
|
|
1248
|
+
setHidden( col, 'elements', expr.elements );
|
|
1050
1249
|
if (elem.type && !elem.type.$inferred || elem.target && !elem.target.$inferred)
|
|
1051
1250
|
cast( col, elem );
|
|
1052
1251
|
}
|
|
1053
1252
|
finally {
|
|
1054
1253
|
gensrcFlavor = gensrcSaved;
|
|
1055
1254
|
}
|
|
1056
|
-
// FIXME: Currently toHana requires that an '_ignore' property on the elem is
|
|
1057
|
-
// also visible on the column. Don't ignore virtual columns, let the
|
|
1058
|
-
// renderer decide how to render that column.
|
|
1059
|
-
if (!elem.virtual && elem._ignore)
|
|
1060
|
-
col._ignore = true;
|
|
1061
|
-
|
|
1062
1255
|
if (elem.value && !elem.$inferred) {
|
|
1063
1256
|
const parens = elem.value.$parens;
|
|
1257
|
+
if (parens)
|
|
1258
|
+
setHidden( col, '$parens', parens.length );
|
|
1064
1259
|
addLocation( (parens ? parens[parens.length - 1] : elem.value.location), col );
|
|
1065
1260
|
}
|
|
1066
1261
|
cols.push( extra( col, elem ) );
|
|
@@ -1075,12 +1270,13 @@ function orderBy( node ) {
|
|
|
1075
1270
|
return extra( expr, node ); // extra properties after sort/nulls
|
|
1076
1271
|
}
|
|
1077
1272
|
|
|
1078
|
-
function extra( csn, node ) {
|
|
1273
|
+
function extra( csn, node, expectedParens = 0 ) {
|
|
1079
1274
|
if (node) {
|
|
1080
1275
|
if (node.$extra)
|
|
1081
1276
|
Object.assign( csn, node.$extra );
|
|
1082
|
-
|
|
1083
|
-
|
|
1277
|
+
const parens = (node.$parens ? node.$parens.length : 0);
|
|
1278
|
+
if (parens !== expectedParens)
|
|
1279
|
+
setHidden( csn, '$parens', parens );
|
|
1084
1280
|
}
|
|
1085
1281
|
return csn;
|
|
1086
1282
|
}
|
|
@@ -1142,6 +1338,9 @@ function compactExpr( e ) { // TODO: options
|
|
|
1142
1338
|
function initModuleVars( options = { csnFlavor: 'gensrc' } ) {
|
|
1143
1339
|
gensrcFlavor = options.parseCdl || options.csnFlavor === 'gensrc' ||
|
|
1144
1340
|
options.toCsn && options.toCsn.flavor === 'gensrc';
|
|
1341
|
+
universalCsn = (options.csnFlavor === 'universal' ||
|
|
1342
|
+
options.toCsn && options.toCsn.flavor === 'universal' ) &&
|
|
1343
|
+
isBetaEnabled( options, 'enableUniversalCsn' ) && !options.parseCdl;
|
|
1145
1344
|
strictMode = options.testMode;
|
|
1146
1345
|
const proto = options.dictionaryPrototype;
|
|
1147
1346
|
// eslint-disable-next-line no-nested-ternary
|
|
@@ -1154,7 +1353,7 @@ function initModuleVars( options = { csnFlavor: 'gensrc' } ) {
|
|
|
1154
1353
|
}
|
|
1155
1354
|
|
|
1156
1355
|
module.exports = {
|
|
1157
|
-
cloneCsnDictionary: csnDictionary,
|
|
1356
|
+
cloneCsnDictionary: (csn, options) => csnDictionary(csn, false, options),
|
|
1158
1357
|
compactModel,
|
|
1159
1358
|
compactQuery,
|
|
1160
1359
|
compactExpr,
|