@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
|
@@ -49,6 +49,8 @@ GenericAntlrParser.prototype = Object.assign(
|
|
|
49
49
|
attachLocation,
|
|
50
50
|
startLocation,
|
|
51
51
|
tokenLocation,
|
|
52
|
+
multiLineTokenLocation,
|
|
53
|
+
previousTokenAtLocation,
|
|
52
54
|
combinedLocation,
|
|
53
55
|
surroundByParens,
|
|
54
56
|
unaryOpForParens,
|
|
@@ -245,9 +247,12 @@ function prepareGenericKeywords( pathItem ) {
|
|
|
245
247
|
// TODO: If not just at the beginning, we need a stack for $genericKeywords,
|
|
246
248
|
// as we can have nested special functions
|
|
247
249
|
this.$genericKeywords.argFull = Object.keys( spec );
|
|
250
|
+
// @ts-ignore
|
|
248
251
|
const token = this.getCurrentToken() || { text: '' };
|
|
249
|
-
if (spec[token.text.toUpperCase()] === 'argFull')
|
|
252
|
+
if (spec[token.text.toUpperCase()] === 'argFull') {
|
|
253
|
+
// @ts-ignore
|
|
250
254
|
token.type = this.constructor.GenericArgFull;
|
|
255
|
+
}
|
|
251
256
|
}
|
|
252
257
|
|
|
253
258
|
// Attach location matched by current rule to node `art`. If a location is
|
|
@@ -297,7 +302,7 @@ function tokenLocation( token, endToken, val ) {
|
|
|
297
302
|
file: this.filename,
|
|
298
303
|
line: token.line,
|
|
299
304
|
col: token.column + 1,
|
|
300
|
-
// we only have single-line tokens
|
|
305
|
+
// we only have single-line tokens, except for docComments
|
|
301
306
|
endLine: endToken.line,
|
|
302
307
|
endCol: endToken.stop - endToken.start + endToken.column + 2, // after the last char (special for EOF?)
|
|
303
308
|
};
|
|
@@ -306,6 +311,52 @@ function tokenLocation( token, endToken, val ) {
|
|
|
306
311
|
return r;
|
|
307
312
|
}
|
|
308
313
|
|
|
314
|
+
/**
|
|
315
|
+
* Return location of `token`. In contrast to `tokenLocation()`, this function
|
|
316
|
+
* can handle multiline tokens.
|
|
317
|
+
*/
|
|
318
|
+
function multiLineTokenLocation(token, val) {
|
|
319
|
+
if (!token)
|
|
320
|
+
return undefined;
|
|
321
|
+
|
|
322
|
+
// Count the number of newlines in the token.
|
|
323
|
+
const source = token.source[1].data;
|
|
324
|
+
let newLineCount = 0;
|
|
325
|
+
let lastNewlineIndex = token.start;
|
|
326
|
+
for (let i = token.start; i < token.stop; i++) {
|
|
327
|
+
// Note: We do NOT check for CR, LS, and PS (/[\r\u2028\u2029]/)
|
|
328
|
+
// because ANTLR only uses LF for line break detection.
|
|
329
|
+
if (source[i] === 10) { // ASCII code for '\n'
|
|
330
|
+
newLineCount++;
|
|
331
|
+
lastNewlineIndex = i;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (newLineCount === 0)
|
|
335
|
+
// endCol calculation below requires at least one newLine.
|
|
336
|
+
return this.tokenLocation(token, token, val);
|
|
337
|
+
|
|
338
|
+
/** @type {CSN.Location} */
|
|
339
|
+
const r = {
|
|
340
|
+
file: this.filename,
|
|
341
|
+
line: token.line,
|
|
342
|
+
col: token.column + 1,
|
|
343
|
+
endLine: token.line + newLineCount,
|
|
344
|
+
endCol: token.stop - lastNewlineIndex + 1, // after the last char (special for EOF?)
|
|
345
|
+
};
|
|
346
|
+
if (val !== undefined)
|
|
347
|
+
return { location: r, val };
|
|
348
|
+
return r;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function previousTokenAtLocation( location ) {
|
|
352
|
+
let k = -1;
|
|
353
|
+
let token = this._input.LT(k);
|
|
354
|
+
while (token.line > location.line ||
|
|
355
|
+
token.line === location.line && token.column >= location.col)
|
|
356
|
+
token = this._input.LT(--k);
|
|
357
|
+
return (token.line === location.line && token.column + 1 === location.col) && token;
|
|
358
|
+
}
|
|
359
|
+
|
|
309
360
|
// Create a location with location properties `filename` and `start` from
|
|
310
361
|
// argument `start`, and location property `end` from argument `end`.
|
|
311
362
|
function combinedLocation( start, end ) {
|
|
@@ -342,16 +393,20 @@ function unaryOpForParens( query, val ) {
|
|
|
342
393
|
// - would influence the prediction, probably even induce adaptivePredict() calls,
|
|
343
394
|
// - is only slightly "more declarative" in the grammar.
|
|
344
395
|
function docComment( node ) {
|
|
345
|
-
if (!this.options.docComment)
|
|
346
|
-
return;
|
|
347
396
|
const token = this._input.getHiddenTokenToLeft( this.constructor.DocComment );
|
|
348
397
|
if (!token)
|
|
349
398
|
return;
|
|
399
|
+
|
|
400
|
+
// This token is actually used by / assigned to an artifact.
|
|
401
|
+
token.isUsed = true;
|
|
402
|
+
|
|
403
|
+
if (!this.options.docComment)
|
|
404
|
+
return;
|
|
350
405
|
if (node.doc) {
|
|
351
406
|
this.warning( 'syntax-duplicate-doc-comment', token, {},
|
|
352
407
|
'Repeated doc comment - previous doc is replaced' );
|
|
353
408
|
}
|
|
354
|
-
node.doc = this.
|
|
409
|
+
node.doc = this.multiLineTokenLocation( token, parseDocComment( token.text ) );
|
|
355
410
|
}
|
|
356
411
|
|
|
357
412
|
// Classify token (identifier category) for implicit names,
|
|
@@ -435,14 +490,18 @@ function valuePathAst( ref ) {
|
|
|
435
490
|
path.length = 1;
|
|
436
491
|
}
|
|
437
492
|
const { args, id, location } = path[0];
|
|
438
|
-
if (args
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
493
|
+
if (args
|
|
494
|
+
? path[0].$syntax === ':'
|
|
495
|
+
: path[0].$delimited || !functionsWithoutParens.includes( id.toUpperCase() ))
|
|
496
|
+
return ref;
|
|
497
|
+
|
|
498
|
+
const implicit = this.previousTokenAtLocation( location );
|
|
499
|
+
if (implicit && implicit.isIdentifier)
|
|
500
|
+
implicit.isIdentifier = 'func';
|
|
501
|
+
const op = { location, val: 'call' };
|
|
502
|
+
return (args)
|
|
503
|
+
? { op, func: ref, location: ref.location, args }
|
|
504
|
+
: { op, func: ref, location: ref.location };
|
|
446
505
|
}
|
|
447
506
|
|
|
448
507
|
// If a '-' is directly before an unsigned number, consider it part of the number;
|
|
@@ -601,7 +660,7 @@ function addDef( parent, env, kind, name, annos, props, location ) {
|
|
|
601
660
|
// which could be tested in name search (then no undefined-ref error)
|
|
602
661
|
return art;
|
|
603
662
|
}
|
|
604
|
-
else if (env === 'artifacts') {
|
|
663
|
+
else if (env === 'artifacts' || env === 'vocabularies') {
|
|
605
664
|
dictAddArray( parent[env], art.name.id, art );
|
|
606
665
|
}
|
|
607
666
|
else if (kind || this.options.parseOnly) {
|
package/lib/language/language.g4
CHANGED
|
@@ -498,6 +498,8 @@ projectionSpec returns[ query ] locals[ src ]
|
|
|
498
498
|
fromPath[ $src, 'ref']
|
|
499
499
|
)?
|
|
500
500
|
( AS aliasName=ident['FromAlias'] { $src.name = $aliasName.id } )?
|
|
501
|
+
// ANTLR errors are better if we use ( A )? instead of ( A | ):
|
|
502
|
+
{ if (!$src.name) this.classifyImplicitName( $src.scope ? 'FromAlias' : 'Without' ); }
|
|
501
503
|
bracedSelectItemListDef[ $query ]?
|
|
502
504
|
excludingClause[ $query ]?
|
|
503
505
|
;
|
|
@@ -1499,7 +1501,8 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
|
|
|
1499
1501
|
{ $art.enum = Object.create(null); }
|
|
1500
1502
|
enumSymbolDef[ $art ]*
|
|
1501
1503
|
'}'
|
|
1502
|
-
optionalSemi
|
|
1504
|
+
optionalSemi
|
|
1505
|
+
| requiredSemi
|
|
1503
1506
|
)
|
|
1504
1507
|
|
|
|
1505
1508
|
':' // with element, e.g. `type T : E:elem enum { ... }`
|
|
@@ -1511,7 +1514,8 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
|
|
|
1511
1514
|
{ $art.enum = Object.create(null); }
|
|
1512
1515
|
enumSymbolDef[ $art ]*
|
|
1513
1516
|
'}'
|
|
1514
|
-
optionalSemi
|
|
1517
|
+
optionalSemi
|
|
1518
|
+
| requiredSemi
|
|
1515
1519
|
)
|
|
1516
1520
|
|
|
|
1517
1521
|
{ this.docComment( $annos ); }
|
|
@@ -1520,7 +1524,8 @@ typeSpecSemi[ art, annos ] // with 'includes', for type and annotation defs
|
|
|
1520
1524
|
{ $art.enum = Object.create(null); }
|
|
1521
1525
|
enumSymbolDef[ $art ]*
|
|
1522
1526
|
'}'
|
|
1523
|
-
optionalSemi
|
|
1527
|
+
optionalSemi
|
|
1528
|
+
| requiredSemi
|
|
1524
1529
|
)
|
|
1525
1530
|
|
|
|
1526
1531
|
// TODO: complain if used in anno def?
|
|
@@ -1776,6 +1781,62 @@ partitionByClause returns [ expr ]
|
|
|
1776
1781
|
( ',' en=expression { $expr.args.push( $en.expr ); } )*
|
|
1777
1782
|
;
|
|
1778
1783
|
|
|
1784
|
+
windowFrameClause returns [ wf ]
|
|
1785
|
+
:
|
|
1786
|
+
r=ROWS { $wf = { op: this.tokenLocation($r, null, 'rows' ) , args: [] }}
|
|
1787
|
+
wfe=windowFrameExtentSpec { $wf.args.push( $wfe.wfe ); }
|
|
1788
|
+
;
|
|
1789
|
+
|
|
1790
|
+
windowFrameExtentSpec returns[ wfe ]
|
|
1791
|
+
:
|
|
1792
|
+
{ $wfe = {} }
|
|
1793
|
+
windowFrameStartSpec [ $wfe ]
|
|
1794
|
+
|
|
|
1795
|
+
b=BETWEEN
|
|
1796
|
+
{ $wfe = { op: this.tokenLocation( $b, null, 'frameBetween' ), args: [] } }
|
|
1797
|
+
wfb1=windowFrameBoundSpec { $wfe.args.push( $wfb1.wfb ); }
|
|
1798
|
+
AND
|
|
1799
|
+
wfb2=windowFrameBoundSpec { $wfe.args.push( $wfb2.wfb ); }
|
|
1800
|
+
;
|
|
1801
|
+
|
|
1802
|
+
windowFrameBoundSpec returns [ wfb ]
|
|
1803
|
+
@after{ /* #ATN 1 */ }
|
|
1804
|
+
:
|
|
1805
|
+
// #ATN: Not ll1 because `UNBOUNDED` could also be part of the windowFrameStartSpec
|
|
1806
|
+
// `UNBOUNDED` would then be immediately followed by `PRECEDING`
|
|
1807
|
+
u=UNBOUNDED f=FOLLOWING
|
|
1808
|
+
{ $wfb = { op: this.tokenLocation($u, $f, 'unboundedFollowing' ), args: []} }
|
|
1809
|
+
|
|
|
1810
|
+
// #ATN: Not ll1 because `Number` could also be part of the windowFrameStartSpec
|
|
1811
|
+
// `Number` would then be immediately followed by `PRECEDING`
|
|
1812
|
+
n=Number f=FOLLOWING
|
|
1813
|
+
{ $wfb = { op: this.tokenLocation($n, $f, 'following' ), args: [ this.numberLiteral( $n ) ]} }
|
|
1814
|
+
|
|
|
1815
|
+
{ $wfb = {} }
|
|
1816
|
+
windowFrameStartSpec [ $wfb ]
|
|
1817
|
+
;
|
|
1818
|
+
|
|
1819
|
+
windowFrameStartSpec [ wf ]
|
|
1820
|
+
:
|
|
1821
|
+
u=UNBOUNDED p=PRECEDING
|
|
1822
|
+
{
|
|
1823
|
+
$wf.op = this.tokenLocation($u, $p, 'unboundedPreceding' );
|
|
1824
|
+
$wf.args = [];
|
|
1825
|
+
}
|
|
1826
|
+
|
|
|
1827
|
+
n=Number p=PRECEDING
|
|
1828
|
+
{
|
|
1829
|
+
$wf.op = this.tokenLocation($p, null, 'preceding' );
|
|
1830
|
+
$wf.args = [ this.numberLiteral( $n ) ];
|
|
1831
|
+
}
|
|
1832
|
+
|
|
|
1833
|
+
c=CURRENT r=ROW
|
|
1834
|
+
{
|
|
1835
|
+
$wf.op = this.tokenLocation($c, $r, 'currentRow' );
|
|
1836
|
+
$wf.args = [];
|
|
1837
|
+
}
|
|
1838
|
+
;
|
|
1839
|
+
|
|
1779
1840
|
overClause returns [ over ]
|
|
1780
1841
|
@after { this.attachLocation($over); }
|
|
1781
1842
|
:
|
|
@@ -1783,6 +1844,7 @@ overClause returns [ over ]
|
|
|
1783
1844
|
'('
|
|
1784
1845
|
( pb=partitionByClause { $over.args.push( $pb.expr ); } )?
|
|
1785
1846
|
( ob=overOrderByClause { $over.args.push( $ob.expr ); } )?
|
|
1847
|
+
( wf=windowFrameClause { $over.args.push( $wf.wf ); } )?
|
|
1786
1848
|
')'
|
|
1787
1849
|
;
|
|
1788
1850
|
|
|
@@ -1948,6 +2010,8 @@ tableTerm returns [ table ]
|
|
|
1948
2010
|
// if we would use rule `ident`, we would either had to make all JOIN
|
|
1949
2011
|
// kinds reserved or introduce ATN
|
|
1950
2012
|
)?
|
|
2013
|
+
// ANTLR errors are better if we use ( A | B )? instead of ( A | B | ):
|
|
2014
|
+
{ if (!$table.name) this.classifyImplicitName( $table.scope ? 'FromAlias' : 'Without' ); }
|
|
1951
2015
|
|
|
|
1952
2016
|
open='('
|
|
1953
2017
|
// #ATN: The following alternative is not LL1, because both can start with
|
|
@@ -2602,6 +2666,7 @@ ident[ category ] returns[ id ]
|
|
|
2602
2666
|
| COMPOSITION
|
|
2603
2667
|
| CONTEXT
|
|
2604
2668
|
| CROSS
|
|
2669
|
+
| CURRENT
|
|
2605
2670
|
| DAY
|
|
2606
2671
|
| DEFAULT
|
|
2607
2672
|
| DEFINE
|
|
@@ -2619,6 +2684,7 @@ ident[ category ] returns[ id ]
|
|
|
2619
2684
|
| EXTEND
|
|
2620
2685
|
| FIRST
|
|
2621
2686
|
| FLOATING
|
|
2687
|
+
| FOLLOWING
|
|
2622
2688
|
| FULL
|
|
2623
2689
|
| FUNCTION
|
|
2624
2690
|
| GROUP
|
|
@@ -2650,10 +2716,13 @@ ident[ category ] returns[ id ]
|
|
|
2650
2716
|
| OUTER
|
|
2651
2717
|
| PARAMETERS
|
|
2652
2718
|
| PARTITION
|
|
2719
|
+
| PRECEDING
|
|
2653
2720
|
| PROJECTION
|
|
2654
2721
|
| REDIRECTED
|
|
2655
2722
|
| RETURNS
|
|
2656
2723
|
| RIGHT
|
|
2724
|
+
| ROW
|
|
2725
|
+
| ROWS
|
|
2657
2726
|
| SECOND
|
|
2658
2727
|
| SERVICE
|
|
2659
2728
|
| THEN
|
|
@@ -2662,6 +2731,7 @@ ident[ category ] returns[ id ]
|
|
|
2662
2731
|
| TO
|
|
2663
2732
|
| TYPE
|
|
2664
2733
|
| USING
|
|
2734
|
+
| UNBOUNDED
|
|
2665
2735
|
| VARIABLE
|
|
2666
2736
|
| VIEW
|
|
2667
2737
|
| YEAR
|
|
@@ -2763,6 +2833,7 @@ BOTH : [bB][oO][tT][hH] ;
|
|
|
2763
2833
|
COMPOSITION : [cC][oO][mM][pP][oO][sS][iI][tT][iI][oO][nN] ;
|
|
2764
2834
|
CONTEXT : [cC][oO][nN][tT][eE][xX][tT] ;
|
|
2765
2835
|
CROSS : [cC][rR][oO][sS][sS] ;
|
|
2836
|
+
CURRENT : [cC][uU][rR][rR][eE][nN][tT] ;
|
|
2766
2837
|
DAY : [dD][aA][yY] ;
|
|
2767
2838
|
DEFAULT : [dD][eE][fF][aA][uU][lL][tT] ;
|
|
2768
2839
|
DEFINE : [dD][eE][fF][iI][nN][eE] ;
|
|
@@ -2780,6 +2851,7 @@ EXCLUDING : [eE][xX][cC][lL][uU][dD][iI][nN][gG] ;
|
|
|
2780
2851
|
EXTEND : [eE][xX][tT][eE][nN][dD] ;
|
|
2781
2852
|
FIRST : [fF][iI][rR][sS][tT] ;
|
|
2782
2853
|
FLOATING : [fF][lL][oO][aA][tT][iI][nN][gG] ;
|
|
2854
|
+
FOLLOWING : [fF][oO][lL][lL][oO][wW][iI][nN][gG] ;
|
|
2783
2855
|
FULL : [fF][uU][lL][lL] ;
|
|
2784
2856
|
FUNCTION : [fF][uU][nN][cC][tT][iI][oO][nN] ;
|
|
2785
2857
|
GROUP : [gG][rR][oO][uU][pP] ;
|
|
@@ -2812,10 +2884,13 @@ OUTER : [oO][uU][tT][eE][rR] ;
|
|
|
2812
2884
|
// OVER : [oO][vV][eE][rR] ;
|
|
2813
2885
|
PARAMETERS : [pP][aA][rR][aA][mM][eE][tT][eE][rR][sS] ;
|
|
2814
2886
|
PARTITION: [pP][aA][rR][tT][iI][tT][iI][oO][nN] ;
|
|
2887
|
+
PRECEDING: [pP][rR][eE][cC][eE][dD][iI][nN][gG] ;
|
|
2815
2888
|
PROJECTION : [pP][rR][oO][jJ][eE][cC][tT][iI][oO][nN] ;
|
|
2816
2889
|
REDIRECTED : [rR][eE][dD][iI][rR][eE][cC][tT][eE][dD] ;
|
|
2817
2890
|
RETURNS : [rR][eE][tT][uU][rR][nN][sS] ;
|
|
2818
2891
|
RIGHT : [rR][iI][gG][hH][tT] ;
|
|
2892
|
+
ROW : [rR][oO][wW] ;
|
|
2893
|
+
ROWS : [rR][oO][wW][sS] ;
|
|
2819
2894
|
SECOND : [sS][eE][cC][oO][nN][dD] ;
|
|
2820
2895
|
SERVICE : [sS][eE][rR][vV][iI][cC][eE] ;
|
|
2821
2896
|
THEN : [tT][hH][eE][nN] ;
|
|
@@ -2823,6 +2898,7 @@ TRAILING : [tT][rR][aA][iI][lL][iI][nN][gG] ;
|
|
|
2823
2898
|
TO : [tT][oO] ; // or make reserved? (is in SQL-92)
|
|
2824
2899
|
TYPE : [tT][yY][pP][eE] ;
|
|
2825
2900
|
UNION : [uU][nN][iI][oO][nN] ;
|
|
2901
|
+
UNBOUNDED : [uU][nN][bB][oO][uU][nN][dD][eE][dD] ;
|
|
2826
2902
|
USING : [uU][sS][iI][nN][gG] ;
|
|
2827
2903
|
VARIABLE : [vV][aA][rR][iI][aA][bB][lL][eE] ;
|
|
2828
2904
|
VIEW : [vV][iI][eE][wW] ;
|
package/lib/main.d.ts
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
//
|
|
5
5
|
// These types are improved step by step and use a lot any types at the moment.
|
|
6
6
|
|
|
7
|
+
// Author's note: All "options" interfaces should actually be types. However, due to
|
|
8
|
+
// https://github.com/TypeStrong/typedoc/issues/1519 we can't use
|
|
9
|
+
// intersection types at the moment.
|
|
10
|
+
|
|
7
11
|
export = compiler;
|
|
8
12
|
|
|
9
13
|
declare namespace compiler {
|
|
@@ -11,7 +15,7 @@ declare namespace compiler {
|
|
|
11
15
|
/**
|
|
12
16
|
* Options used by the core compiler and all backends.
|
|
13
17
|
*/
|
|
14
|
-
export
|
|
18
|
+
export interface Options {
|
|
15
19
|
[option: string]: any,
|
|
16
20
|
|
|
17
21
|
/**
|
|
@@ -57,6 +61,180 @@ declare namespace compiler {
|
|
|
57
61
|
dictionaryPrototype?: any
|
|
58
62
|
}
|
|
59
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Options used by OData backends. Includes options for the OData
|
|
66
|
+
* transformer as well as for rendering EDM and EDMX.
|
|
67
|
+
*/
|
|
68
|
+
export interface ODataOptions extends Options {
|
|
69
|
+
/**
|
|
70
|
+
* OData version for output files. Either 'v4' or 'v2'.
|
|
71
|
+
*
|
|
72
|
+
* @default 'v4'
|
|
73
|
+
*/
|
|
74
|
+
odataVersion?: string | 'v4' | 'v2'
|
|
75
|
+
/**
|
|
76
|
+
* Whether to generate OData as flat or as structured.
|
|
77
|
+
* Structured is only supported for OData v4.
|
|
78
|
+
*
|
|
79
|
+
* @default 'flat'
|
|
80
|
+
*/
|
|
81
|
+
odataFormat?: string | 'flat' | 'structured'
|
|
82
|
+
/**
|
|
83
|
+
* Naming mode used by the corresponding SQL.
|
|
84
|
+
*
|
|
85
|
+
* @default 'plain'
|
|
86
|
+
*/
|
|
87
|
+
sqlMapping?: string | 'plain' | 'quoted' | 'hdbcds'
|
|
88
|
+
/**
|
|
89
|
+
* If `true`, `cds.Compositions` are rendered as `edm:NavigationProperty` with the additional
|
|
90
|
+
* attribute `ContainsTarget="true"` and all contained entities (composition targets) have no
|
|
91
|
+
* `edm.EntitySet`.
|
|
92
|
+
*
|
|
93
|
+
* @note Only available for OData v4 EDM(X) rendering.
|
|
94
|
+
* @default false
|
|
95
|
+
*/
|
|
96
|
+
odataContainment?: boolean
|
|
97
|
+
/**
|
|
98
|
+
* If `true`, render generated foreign keys for managed associations.
|
|
99
|
+
* By default foreign keys are never visible in structured OData APIs.
|
|
100
|
+
*
|
|
101
|
+
* @note Only available for structured OData v4 EDM(X) rendering.
|
|
102
|
+
* @default false
|
|
103
|
+
*/
|
|
104
|
+
odataForeignKeys?: boolean
|
|
105
|
+
/**
|
|
106
|
+
* If `true`, association targets outside of the current service are added as
|
|
107
|
+
* `edm.EntityType` that only exposes their primary keys and have no `edm.EntitySet`.
|
|
108
|
+
* If the original association target is a service member, a corresponding `edm.Schema`
|
|
109
|
+
* representing the namespace of that service is added to `edm.Services`. All association
|
|
110
|
+
* targets that are no service members are collected in an `edm.Schema` with namespace `root`.
|
|
111
|
+
*
|
|
112
|
+
* @note Only valid for structured OData v4 EDM(X) rendering.
|
|
113
|
+
* @default false
|
|
114
|
+
* @since v2.1.0
|
|
115
|
+
*/
|
|
116
|
+
odataProxies?: boolean
|
|
117
|
+
/**
|
|
118
|
+
* This option is an extension to `odataProxies`.
|
|
119
|
+
* If `true`, an `edm:Reference` instead of a proxy `edm.EntityType` is rendered for each
|
|
120
|
+
* association target that is a service member outside the current service instead of proxies.
|
|
121
|
+
*
|
|
122
|
+
* @note Only valid for structured OData v4 EDM(X) rendering.
|
|
123
|
+
* @default false
|
|
124
|
+
* @since v2.1.0
|
|
125
|
+
*/
|
|
126
|
+
odataXServiceRefs?: boolean
|
|
127
|
+
/**
|
|
128
|
+
* The OData specification requires that all primary keys of the principal must be used as
|
|
129
|
+
* referential constraints. If an association is modelled with only a partial key, no
|
|
130
|
+
* referential constraints are added. If `true`, partial constraints are rendered for
|
|
131
|
+
* backwards compatibility and mocking scenarios. A spec violation warning is raised for
|
|
132
|
+
* each incomplete constraint.
|
|
133
|
+
*
|
|
134
|
+
* @note Only valid for OData v2 CSN transformation.
|
|
135
|
+
* @default false
|
|
136
|
+
* @since v2.2.6
|
|
137
|
+
*/
|
|
138
|
+
odataV2PartialConstr?: boolean
|
|
139
|
+
/**
|
|
140
|
+
* Service name for which EDMX or EDM shall be rendered.
|
|
141
|
+
*
|
|
142
|
+
* @note Only available for `to.edmx()` and `to.edm()`. For `to.edmx.all()`
|
|
143
|
+
* and `to.edm.all()`, use `serviceNames` instead.
|
|
144
|
+
*
|
|
145
|
+
* @see serviceNames
|
|
146
|
+
*/
|
|
147
|
+
service?: string
|
|
148
|
+
/**
|
|
149
|
+
* Array of service names for which EDMX or EDM shall be rendered.
|
|
150
|
+
* If unspecified, all services are rendered.
|
|
151
|
+
*
|
|
152
|
+
* @note Only available for `to.edmx.all()` and `to.edm.all()`. For `to.edmx()`
|
|
153
|
+
* and `to.edm()`, use `service` instead.
|
|
154
|
+
*
|
|
155
|
+
* @see service
|
|
156
|
+
*/
|
|
157
|
+
serviceNames?: string[]
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Options used by SQL `to.sql()` backend.
|
|
162
|
+
*
|
|
163
|
+
* @see to.sql()
|
|
164
|
+
*/
|
|
165
|
+
export interface SqlOptions extends Options {
|
|
166
|
+
/**
|
|
167
|
+
* The SQL naming mode decides how names are represented.
|
|
168
|
+
* Among others, this includes whether identifiers are quoted or not (note
|
|
169
|
+
* that "smart quoting" is handled by `sqlDialect`).
|
|
170
|
+
*
|
|
171
|
+
* - `plain`:
|
|
172
|
+
* In this naming mode, dots are replaced by underscores.
|
|
173
|
+
* Names are neither upper-cased nor quoted, unless "smart-quoting" is used.
|
|
174
|
+
* This mode can be used with all SQL dialects.
|
|
175
|
+
* - `quoted`:
|
|
176
|
+
* In this mode, all identifiers are quoted. Dots are not replaced in table
|
|
177
|
+
* and view names but are still replaced by underscores in element names.
|
|
178
|
+
* This mode can only be used with SQL dialect `hana`.
|
|
179
|
+
* - `hdbcds`:
|
|
180
|
+
* This mode uses names that are compatible to SAP HANA CDS.
|
|
181
|
+
* In this mode, all identifiers are quoted. Dots are neither replaced in table
|
|
182
|
+
* nor element names. Namespace identifiers are separated from the remaining
|
|
183
|
+
* identifier by `::`, i.e. the dot is replaced. For example `Ns.Books`
|
|
184
|
+
* becomes `"Ns::Books"`.
|
|
185
|
+
* This mode can only be used with SQL dialect `hana`.
|
|
186
|
+
*
|
|
187
|
+
* @default 'plain'
|
|
188
|
+
*/
|
|
189
|
+
sqlMapping?: string | 'plain' | 'quoted' | 'hdbcds'
|
|
190
|
+
/**
|
|
191
|
+
* Use this option to specify what dialect of SQL you want.
|
|
192
|
+
*
|
|
193
|
+
* Different databases may support different feature sets of SQL.
|
|
194
|
+
* For example, timestamps are handled differently. Furthermore, "smart-quoting"
|
|
195
|
+
* is enabled for `sqlite` and `hana`. This is useful if identifiers
|
|
196
|
+
* collide with reserved keywords.
|
|
197
|
+
*
|
|
198
|
+
* - `plain`:
|
|
199
|
+
* Use this option for best compatibility with standard SQL.
|
|
200
|
+
* Note that "smart-quoting" is not available for this mode.
|
|
201
|
+
* Requires `sqlMapping: 'plain'`.
|
|
202
|
+
* - `sqlite`:
|
|
203
|
+
* This SQL dialect ensures compatibility with SQLite, which may not support
|
|
204
|
+
* all SQL features used in your CDS files. For example, `$at.from`/`$at.to` are
|
|
205
|
+
* handled differently to ensure correctness for SQLite. "smart-quoting"
|
|
206
|
+
* quotes identifiers that are reserved keywords, but does not upper-case them.
|
|
207
|
+
* Requires `sqlMapping: 'plain'`.
|
|
208
|
+
* - `hana`:
|
|
209
|
+
* Use this SQL dialect for best compatibility with SAP HANA.
|
|
210
|
+
* "smart-quoting" upper-cases and quotes identifiers.
|
|
211
|
+
*
|
|
212
|
+
* @default 'plain'
|
|
213
|
+
*/
|
|
214
|
+
sqlDialect?: string | 'plain' | 'sqlite' | 'hana'
|
|
215
|
+
/**
|
|
216
|
+
* Object containing magic variables. These magic variables are
|
|
217
|
+
* used as placeholder values.
|
|
218
|
+
*
|
|
219
|
+
* @since 2.11.0
|
|
220
|
+
*/
|
|
221
|
+
variableReplacements?: {
|
|
222
|
+
[option: string]: string | object,
|
|
223
|
+
/**
|
|
224
|
+
* Commonly used placeholders for user's name and locale.
|
|
225
|
+
*/
|
|
226
|
+
$user?: {
|
|
227
|
+
[option: string]: string | object,
|
|
228
|
+
id?: string
|
|
229
|
+
locale?: string
|
|
230
|
+
},
|
|
231
|
+
/**
|
|
232
|
+
* Commonly used placeholders for session variables.
|
|
233
|
+
*/
|
|
234
|
+
$session?: Record<string, string | object>
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
60
238
|
/**
|
|
61
239
|
* The compiler's package version.
|
|
62
240
|
* For more details on versioning and SemVer, see `doc/Versioning.md`
|
|
@@ -83,6 +261,7 @@ declare namespace compiler {
|
|
|
83
261
|
* {@link CompilationError} containing a vector of individual errors.
|
|
84
262
|
*
|
|
85
263
|
* @param filenames Array of files that should be compiled.
|
|
264
|
+
* @param dir Working directory. Relative paths in `filenames` will be resolved relatively to this directory.
|
|
86
265
|
* @param options Compiler options. If you do not set `messages`, they will be printed to console.
|
|
87
266
|
* @param fileCache A dictionary of absolute file names to the file content with values:
|
|
88
267
|
* - false: the file does not exist
|
|
@@ -138,7 +317,7 @@ declare namespace compiler {
|
|
|
138
317
|
* _Note_: Sorting is done in-place.
|
|
139
318
|
*
|
|
140
319
|
* Example of sorted messages:
|
|
141
|
-
* ```
|
|
320
|
+
* ```
|
|
142
321
|
* A.cds:1:11: Info id-3: First message text (in entity:“E”/element:“c”)
|
|
143
322
|
* A.cds:8:11: Error id-5: Another message text (in entity:“C”/element:“g”)
|
|
144
323
|
* B.cds:3:10: Debug id-7: First message text (in entity:“B”/element:“e”)
|
|
@@ -188,10 +367,11 @@ declare namespace compiler {
|
|
|
188
367
|
* form (i.e. one line)
|
|
189
368
|
*
|
|
190
369
|
* Example:
|
|
191
|
-
* ```
|
|
370
|
+
* ```
|
|
192
371
|
* <source>.cds:3:11: Error message-id: Can't find type `nu` in this scope (in entity:“E”/element:“e”)
|
|
193
372
|
* ```
|
|
194
373
|
*
|
|
374
|
+
* @param msg Compiler message which shall be stringified.
|
|
195
375
|
* @param normalizeFilename If true, the file path will be normalized to use `/` as the path separator.
|
|
196
376
|
* @param noMessageId If true, the message ID will _not_ be part of the string.
|
|
197
377
|
* @param noHome If true, the semantic location will _not_ be part of the string.
|
|
@@ -201,26 +381,30 @@ declare namespace compiler {
|
|
|
201
381
|
/**
|
|
202
382
|
* Returns a message string with file- and semantic location if present
|
|
203
383
|
* in multiline form.
|
|
204
|
-
* The error (+ message id)
|
|
205
|
-
* run on a TTY.
|
|
384
|
+
* The error (+ message id) can colored according to their severity.
|
|
206
385
|
*
|
|
207
386
|
* Example:
|
|
208
|
-
* ```
|
|
209
|
-
* Error[message-id]: Can't find type `nu` in this scope
|
|
387
|
+
* ```
|
|
388
|
+
* Error[message-id]: Can't find type `nu` in this scope
|
|
210
389
|
* |
|
|
211
|
-
* <source>.cds:3:11, at entity:“E”
|
|
390
|
+
* <source>.cds:3:11, at entity:“E”/element:“e”
|
|
212
391
|
* ```
|
|
213
392
|
*
|
|
214
393
|
* @param config.normalizeFilename If true, the file path will be normalized to use `/` as the path separator.
|
|
215
394
|
* @param config.noMessageId If true, no messages id (in brackets) will be shown.
|
|
216
395
|
* @param config.hintExplanation If true, messages with explanations will get a "…" marker, see {@link hasMessageExplanation}.
|
|
217
396
|
* @param config.withLineSpacer If true, an additional line (with `|`) will be inserted between message and location.
|
|
397
|
+
* @param config.color If true, ANSI escape codes will be used for coloring the severity. If false, no
|
|
398
|
+
* coloring will be used. If 'auto', we will decide based on certain factors such
|
|
399
|
+
* as whether the shell is a TTY and whether the environment variable 'NO_COLOR' is
|
|
400
|
+
* unset.
|
|
218
401
|
*/
|
|
219
402
|
export function messageStringMultiline(msg: CompileMessage, config?: {
|
|
220
403
|
normalizeFilename?: boolean
|
|
221
404
|
noMessageId?: boolean
|
|
222
405
|
hintExplanation?: boolean
|
|
223
406
|
withLineSpacer?: boolean
|
|
407
|
+
color?: boolean | 'auto'
|
|
224
408
|
}): string;
|
|
225
409
|
|
|
226
410
|
/**
|
|
@@ -233,16 +417,24 @@ declare namespace compiler {
|
|
|
233
417
|
* All lines are prepended by a pipe (`|`) and show the corresponding line number.
|
|
234
418
|
*
|
|
235
419
|
* Example Output:
|
|
236
|
-
* ```
|
|
420
|
+
* ```
|
|
237
421
|
* |
|
|
238
422
|
* 13 | num * nu
|
|
239
423
|
* | ^^
|
|
240
424
|
* ```
|
|
241
425
|
*
|
|
242
|
-
* @param sourceLines
|
|
243
|
-
* @param msg
|
|
426
|
+
* @param sourceLines The source code split up into lines, e.g. by `str.split(/\r\n?|\n/);`.
|
|
427
|
+
* @param msg Message whose location is used to print the message context.
|
|
428
|
+
* @param config Configuration for the message context.
|
|
429
|
+
* @param config.color If true, ANSI escape codes will be used for coloring the severity. If false, no
|
|
430
|
+
* coloring will be used. If 'auto', we will decide based on certain factors such
|
|
431
|
+
* as whether the shell is a TTY and whether the environment variable 'NO_COLOR' is
|
|
432
|
+
* unset.
|
|
433
|
+
|
|
244
434
|
*/
|
|
245
|
-
export function messageContext(sourceLines: string[], msg: CompileMessage
|
|
435
|
+
export function messageContext(sourceLines: string[], msg: CompileMessage, config?: {
|
|
436
|
+
color?: boolean | 'auto'
|
|
437
|
+
}): string;
|
|
246
438
|
|
|
247
439
|
/**
|
|
248
440
|
* Get an explanatory text for a complicated compiler message with ID
|
|
@@ -316,21 +508,26 @@ declare namespace compiler {
|
|
|
316
508
|
* @alias for
|
|
317
509
|
*/
|
|
318
510
|
export namespace For {
|
|
319
|
-
|
|
511
|
+
/**
|
|
512
|
+
* Transform the given (generic) CSN into one that is used for OData.
|
|
513
|
+
* Changes include flattening, type resolution and more, according to
|
|
514
|
+
* the provided options.
|
|
515
|
+
*/
|
|
516
|
+
function odata(csn: CSN, options: ODataOptions): any;
|
|
320
517
|
}
|
|
321
518
|
|
|
322
519
|
export namespace to {
|
|
323
520
|
function cdl(csn: CSN, options: Options): object;
|
|
324
|
-
function sql(csn: CSN, options:
|
|
521
|
+
function sql(csn: CSN, options: SqlOptions): any;
|
|
325
522
|
|
|
326
|
-
function edm(csn: CSN, options:
|
|
523
|
+
function edm(csn: CSN, options: ODataOptions): any;
|
|
327
524
|
namespace edm {
|
|
328
|
-
function all(csn: CSN, options:
|
|
525
|
+
function all(csn: CSN, options: ODataOptions): any;
|
|
329
526
|
}
|
|
330
527
|
|
|
331
|
-
function edmx(csn: CSN, options:
|
|
528
|
+
function edmx(csn: CSN, options: ODataOptions): any;
|
|
332
529
|
namespace edmx {
|
|
333
|
-
function all(csn: CSN, options:
|
|
530
|
+
function all(csn: CSN, options: ODataOptions): any;
|
|
334
531
|
}
|
|
335
532
|
|
|
336
533
|
function hdbcds(csn: CSN, options: Options): any;
|
package/lib/main.js
CHANGED
|
@@ -21,6 +21,7 @@ const { createMessageFunctions, sortMessages, sortMessagesSeverityAware, dedupli
|
|
|
21
21
|
|
|
22
22
|
const parseLanguage = require('./language/antlrParser');
|
|
23
23
|
const { parseX, compileX, compileSyncX, compileSourcesX, InvocationError } = require('./compiler');
|
|
24
|
+
const { fns } = require('./compiler/shared');
|
|
24
25
|
const { define } = require('./compiler/definer');
|
|
25
26
|
|
|
26
27
|
// The compiler version (taken from package.json)
|
|
@@ -43,13 +44,14 @@ const { compactModel, compactQuery, compactExpr } = require('./json/to-csn')
|
|
|
43
44
|
function parseCdl( cdl, filename, options = {} ) {
|
|
44
45
|
options = Object.assign( {}, options, { parseCdl: true } );
|
|
45
46
|
const sources = Object.create(null);
|
|
46
|
-
const model = { sources, options };
|
|
47
|
+
const model = { sources, options, $functions: {}, $volatileFunctions: {} };
|
|
47
48
|
const messageFunctions = createMessageFunctions( options, 'parse', model );
|
|
48
49
|
model.$messageFunctions = messageFunctions;
|
|
49
50
|
|
|
50
51
|
const xsn = parseLanguage( cdl, filename, Object.assign( { parseOnly: true }, options ),
|
|
51
52
|
messageFunctions );
|
|
52
53
|
sources[filename] = xsn;
|
|
54
|
+
fns( model );
|
|
53
55
|
define( model );
|
|
54
56
|
messageFunctions.throwWithError();
|
|
55
57
|
return compactModel( model );
|