@sap/cds-compiler 4.7.6 → 4.9.0
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 +63 -3
- package/bin/cds_remove_invalid_whitespace.js +135 -0
- package/bin/cds_update_annotations.js +180 -0
- package/bin/cds_update_identifiers.js +3 -4
- package/bin/cdsc.js +28 -1
- package/bin/cdshi.js +13 -3
- package/doc/CHANGELOG_BETA.md +24 -1
- package/lib/api/main.js +119 -46
- package/lib/api/options.js +51 -0
- package/lib/api/validate.js +1 -5
- package/lib/base/builtins.js +116 -0
- package/lib/base/keywords.js +5 -1
- package/lib/base/location.js +91 -14
- package/lib/base/message-registry.js +76 -46
- package/lib/base/messages.js +121 -35
- package/lib/base/model.js +4 -7
- package/lib/checks/actionsFunctions.js +3 -3
- package/lib/checks/annotationsOData.js +3 -0
- package/lib/checks/defaultValues.js +5 -2
- package/lib/checks/elements.js +2 -1
- package/lib/checks/enricher.js +2 -2
- package/lib/checks/queryNoDbArtifacts.js +5 -3
- package/lib/checks/utils.js +1 -1
- package/lib/checks/validator.js +8 -56
- package/lib/compiler/assert-consistency.js +11 -7
- package/lib/compiler/builtins.js +0 -74
- package/lib/compiler/checks.js +105 -29
- package/lib/compiler/define.js +37 -25
- package/lib/compiler/extend.js +35 -12
- package/lib/compiler/index.js +9 -10
- package/lib/compiler/lsp-api.js +5 -0
- package/lib/compiler/populate.js +13 -5
- package/lib/compiler/propagator.js +24 -18
- package/lib/compiler/resolve.js +47 -45
- package/lib/compiler/shared.js +61 -21
- package/lib/compiler/tweak-assocs.js +15 -90
- package/lib/compiler/utils.js +3 -3
- package/lib/compiler/xpr-rewrite.js +689 -0
- package/lib/compiler/{classes.js → xsn-model.js} +0 -16
- package/lib/edm/annotations/edmJson.js +7 -5
- package/lib/edm/annotations/genericTranslation.js +149 -71
- package/lib/edm/csn2edm.js +25 -9
- package/lib/edm/edm.js +7 -7
- package/lib/edm/edmInboundChecks.js +57 -5
- package/lib/edm/edmPreprocessor.js +54 -25
- package/lib/edm/edmUtils.js +3 -16
- package/lib/gen/Dictionary.json +138 -14
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +2085 -1989
- package/lib/json/csnVersion.js +7 -4
- package/lib/json/from-csn.js +21 -11
- package/lib/json/to-csn.js +8 -4
- package/lib/language/antlrParser.js +1 -1
- package/lib/language/genericAntlrParser.js +23 -16
- package/lib/language/multiLineStringParser.js +2 -2
- package/lib/language/textUtils.js +1 -1
- package/lib/main.d.ts +90 -14
- package/lib/main.js +9 -1
- package/lib/model/cloneCsn.js +21 -9
- package/lib/model/csnRefs.js +153 -42
- package/lib/model/csnUtils.js +14 -11
- package/lib/model/enrichCsn.js +4 -2
- package/lib/model/revealInternalProperties.js +2 -1
- package/lib/model/sortViews.js +14 -6
- package/lib/modelCompare/compare.js +135 -122
- package/lib/optionProcessor.js +49 -2
- package/lib/render/DuplicateChecker.js +6 -6
- package/lib/render/manageConstraints.js +1 -0
- package/lib/render/toCdl.js +6 -3
- package/lib/render/toHdbcds.js +4 -48
- package/lib/render/toSql.js +6 -3
- package/lib/transform/addTenantFields.js +58 -35
- package/lib/transform/db/applyTransformations.js +34 -1
- package/lib/transform/db/constraints.js +1 -1
- package/lib/transform/db/expansion.js +11 -3
- package/lib/transform/db/flattening.js +71 -46
- package/lib/transform/db/groupByOrderBy.js +2 -2
- package/lib/transform/db/temporal.js +6 -3
- package/lib/transform/db/transformExists.js +2 -2
- package/lib/transform/db/views.js +1 -4
- package/lib/transform/effective/annotations.js +194 -0
- package/lib/transform/effective/main.js +11 -10
- package/lib/transform/effective/misc.js +45 -14
- package/lib/transform/effective/types.js +4 -3
- package/lib/transform/forOdata.js +29 -12
- package/lib/transform/forRelationalDB.js +104 -113
- package/lib/transform/localized.js +7 -6
- package/lib/transform/odata/flattening.js +228 -107
- package/lib/transform/odata/toFinalBaseType.js +10 -26
- package/lib/transform/odata/typesExposure.js +41 -25
- package/lib/transform/parseExpr.js +4 -7
- package/lib/transform/transformUtils.js +50 -43
- package/lib/transform/translateAssocsToJoins.js +48 -48
- package/lib/transform/universalCsn/coreComputed.js +2 -1
- package/lib/transform/universalCsn/universalCsnEnricher.js +12 -16
- package/package.json +2 -2
- package/share/messages/README.md +4 -0
- package/share/messages/anno-duplicate-unrelated-layer.md +1 -1
- package/share/messages/anno-missing-rewrite.md +45 -0
- package/share/messages/check-proper-type-of.md +1 -1
- package/share/messages/def-duplicate-autoexposed.md +1 -1
- package/share/messages/extend-repeated-intralayer.md +3 -16
- package/share/messages/extend-unrelated-layer.md +1 -1
- package/share/messages/message-explanations.json +2 -0
- package/share/messages/redirected-to-ambiguous.md +1 -1
- package/share/messages/redirected-to-complex.md +1 -1
- package/share/messages/redirected-to-unrelated.md +1 -1
- package/share/messages/rewrite-not-supported.md +1 -1
- package/share/messages/syntax-expecting-unsigned-int.md +2 -2
- package/share/messages/type-missing-enum-value.md +59 -0
- package/share/messages/wildcard-excluding-one.md +1 -1
- package/bin/.eslintrc.json +0 -17
- package/lib/api/.eslintrc.json +0 -37
- package/lib/checks/.eslintrc.json +0 -31
- package/lib/compiler/.eslintrc.json +0 -8
- package/lib/edm/.eslintrc.json +0 -46
- package/lib/inspect/.eslintrc.json +0 -4
- package/lib/json/.eslintrc.json +0 -4
- package/lib/language/.eslintrc.json +0 -4
- package/lib/model/.eslintrc.json +0 -13
- package/lib/modelCompare/utils/.eslintrc.json +0 -22
- package/lib/render/.eslintrc.json +0 -22
- package/lib/transform/.eslintrc.json +0 -13
- package/lib/transform/db/.eslintrc.json +0 -41
- package/lib/transform/draft/.eslintrc.json +0 -4
- package/lib/transform/effective/.eslintrc.json +0 -4
- package/lib/transform/universalCsn/.eslintrc.json +0 -37
- package/lib/utils/.eslintrc.json +0 -7
package/lib/json/csnVersion.js
CHANGED
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
// (Note: the SQL name mapping mode is not reflected in the content of the csn, the version only
|
|
9
9
|
// signals which default name mapping a backend has to use)
|
|
10
10
|
// Historic versions:
|
|
11
|
-
// 0.0.1 : Used by HANA CDS for its CSN output
|
|
12
|
-
//
|
|
11
|
+
// 0.0.1 : Used by SAP HANA CDS for its CSN output
|
|
12
|
+
// (incomplete, not well defined, quite different from CDX ...)
|
|
13
|
+
// 0.0.2 : CDX in the initial versions with old-style CSN, default for SQL
|
|
14
|
+
// name mapping is 'quoted'
|
|
13
15
|
// 0.0.99 : Like 0.0.2, but with new-style CSN
|
|
14
16
|
// Versions that are currently produced by compiler:
|
|
15
17
|
// 0.1.0 : Like 0.0.2, default for SQL name mapping is 'plain'
|
|
@@ -21,15 +23,16 @@
|
|
|
21
23
|
const newCSNVersions = [ '0.1.99', '0.2', '0.2.0', '1.0', '2.0' ];
|
|
22
24
|
|
|
23
25
|
// Check if new-style CSN is requested, i.e. versions >= 0.1.99
|
|
24
|
-
function isNewCSN(csn, options) {
|
|
26
|
+
function isNewCSN( csn, options ) {
|
|
25
27
|
return !( options?.newCsn === false ||
|
|
26
28
|
(csn.version && !newCSNVersions.includes(csn.version.csn)) ||
|
|
27
29
|
(csn.$version && !newCSNVersions.includes(csn.$version)));
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
function checkCSNVersion(csn, options) {
|
|
32
|
+
function checkCSNVersion( csn, options ) {
|
|
31
33
|
if (!isNewCSN(csn, options)) {
|
|
32
34
|
// the new transformer works only with new CSN
|
|
35
|
+
// eslint-disable-next-line global-require
|
|
33
36
|
const { makeMessageFunction } = require('../base/messages');
|
|
34
37
|
const { error, throwWithAnyError } = makeMessageFunction(csn, options);
|
|
35
38
|
|
package/lib/json/from-csn.js
CHANGED
|
@@ -119,10 +119,11 @@
|
|
|
119
119
|
*/
|
|
120
120
|
|
|
121
121
|
const { dictAdd } = require('../base/dictionaries');
|
|
122
|
-
|
|
123
|
-
const { isAnnotationExpression
|
|
122
|
+
const { quotedLiteralPatterns } = require('../compiler/builtins');
|
|
123
|
+
const { isAnnotationExpression } = require('../base/builtins');
|
|
124
124
|
const { CompilerAssertion } = require('../base/error');
|
|
125
|
-
const {
|
|
125
|
+
const { Location } = require('../base/location');
|
|
126
|
+
const { XsnSource } = require('../compiler/xsn-model');
|
|
126
127
|
|
|
127
128
|
const $location = Symbol.for('cds.$location');
|
|
128
129
|
|
|
@@ -648,7 +649,8 @@ const schema = compileSchema( {
|
|
|
648
649
|
noPrefix: false, // just '@' is no CSN property
|
|
649
650
|
prop: '@‹anno›', // which property name do messages use for annotation assignments?
|
|
650
651
|
type: annotation,
|
|
651
|
-
|
|
652
|
+
// allowed in all definitions except mixins (including columns and extensions)
|
|
653
|
+
inKind: _kind => true, // TODO(v5): (kind !== 'mixin')
|
|
652
654
|
schema: {
|
|
653
655
|
'-expr': { // '-expr' and '-' must not exist top-level
|
|
654
656
|
prop: '@‹anno›',
|
|
@@ -744,7 +746,7 @@ const schema = compileSchema( {
|
|
|
744
746
|
ignore: true, type: ignore, // TODO: do we need to do something?
|
|
745
747
|
},
|
|
746
748
|
namespace: {
|
|
747
|
-
type:
|
|
749
|
+
type: namespace,
|
|
748
750
|
},
|
|
749
751
|
meta: { // meta information
|
|
750
752
|
type: ignore, // TODO: should we test s/th here?
|
|
@@ -1042,6 +1044,11 @@ function definition( def, spec, xsn, csn, name ) {
|
|
|
1042
1044
|
}
|
|
1043
1045
|
}
|
|
1044
1046
|
|
|
1047
|
+
function namespace( ref, spec ) {
|
|
1048
|
+
const ns = stringRef(ref, spec);
|
|
1049
|
+
return ns ? { kind: 'namespace', name: ns } : null;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1045
1052
|
function couldNotBeEnumProperty( prop ) {
|
|
1046
1053
|
// returns true for `value` (which we allow with warning when extending an enum with `elements`)
|
|
1047
1054
|
const inKind = schema[prop]?.inKind; // undefined for annotations, $location, …
|
|
@@ -1485,9 +1492,12 @@ function annoValue( val, spec ) {
|
|
|
1485
1492
|
function annotation( val, spec, xsn, csn, name ) {
|
|
1486
1493
|
// not used for the value
|
|
1487
1494
|
const id = (xsn ? name.substring(1) : name);
|
|
1488
|
-
if (!id)
|
|
1495
|
+
if (!id) // `"@": …` is already syntax-unknown-property
|
|
1489
1496
|
message( 'syntax-invalid-name', location(true), { '#': '{}' } );
|
|
1490
|
-
|
|
1497
|
+
|
|
1498
|
+
if (xsn && xsn.kind === 'mixin') // TODO(v5): Remove, adapt spec['@'].inKind
|
|
1499
|
+
message('anno-unexpected-mixin', location(true));
|
|
1500
|
+
|
|
1491
1501
|
const n = { id, location: location() };
|
|
1492
1502
|
const r = annoValue( val, spec );
|
|
1493
1503
|
r.name = n;
|
|
@@ -1997,7 +2007,7 @@ function replaceZeroValue( spec, msgVariant, newValue ) {
|
|
|
1997
2007
|
function location( enforceJsonPos ) {
|
|
1998
2008
|
return !enforceJsonPos && dollarLocations.length &&
|
|
1999
2009
|
dollarLocations[dollarLocations.length - 1] || {
|
|
2000
|
-
__proto__:
|
|
2010
|
+
__proto__: Location.prototype,
|
|
2001
2011
|
file: csnFilename,
|
|
2002
2012
|
line: virtualLine,
|
|
2003
2013
|
col: 0,
|
|
@@ -2010,7 +2020,7 @@ function pushLocation( obj ) {
|
|
|
2010
2020
|
if (loc === undefined)
|
|
2011
2021
|
return;
|
|
2012
2022
|
if (loc && typeof loc === 'object' && !Array.isArray( loc )) {
|
|
2013
|
-
dollarLocations.push( loc.line ? { __proto__:
|
|
2023
|
+
dollarLocations.push( loc.line ? { __proto__: Location.prototype, ...loc } : null );
|
|
2014
2024
|
return;
|
|
2015
2025
|
}
|
|
2016
2026
|
else if (!loc || typeof loc !== 'string') {
|
|
@@ -2028,7 +2038,7 @@ function pushLocation( obj ) {
|
|
|
2028
2038
|
const column = m[2] && Number( m[2] ) || 0;
|
|
2029
2039
|
const file = loc.substring( 0, m.index );
|
|
2030
2040
|
dollarLocations.push({
|
|
2031
|
-
__proto__:
|
|
2041
|
+
__proto__: Location.prototype, file, line, col: column,
|
|
2032
2042
|
} );
|
|
2033
2043
|
}
|
|
2034
2044
|
}
|
|
@@ -2123,7 +2133,7 @@ function parse( source, filename = 'csn.json', options = {}, messageFunctions =
|
|
|
2123
2133
|
}
|
|
2124
2134
|
column = end - eol + 1;
|
|
2125
2135
|
}
|
|
2126
|
-
const loc = new
|
|
2136
|
+
const loc = new Location(
|
|
2127
2137
|
filename,
|
|
2128
2138
|
line,
|
|
2129
2139
|
column
|
package/lib/json/to-csn.js
CHANGED
|
@@ -236,8 +236,8 @@ function compactModel( model, options = model.options || {} ) {
|
|
|
236
236
|
// (not a really useful property at all, avoids XSN inspection by Umbrella)
|
|
237
237
|
for (const first in srcDict) {
|
|
238
238
|
const { namespace } = srcDict[first];
|
|
239
|
-
if (namespace
|
|
240
|
-
csn.namespace = pathName( namespace.path );
|
|
239
|
+
if (namespace?.name?.path)
|
|
240
|
+
csn.namespace = pathName( namespace.name.path );
|
|
241
241
|
break;
|
|
242
242
|
}
|
|
243
243
|
set( 'definitions', csn, model );
|
|
@@ -1008,8 +1008,9 @@ function artifactRef( node, terse ) {
|
|
|
1008
1008
|
return undefined;
|
|
1009
1009
|
// Works also on XSN directly coming from parser and with XSN from CDL->CSN transformation
|
|
1010
1010
|
// Shortcut for many cases:
|
|
1011
|
-
|
|
1012
|
-
|
|
1011
|
+
const art = node._artifact;
|
|
1012
|
+
if (art && (!art._main || art.kind === '$self') && terse && terse !== '.path')
|
|
1013
|
+
return art.name.id;
|
|
1013
1014
|
let { path } = node;
|
|
1014
1015
|
if (!path)
|
|
1015
1016
|
return undefined; // TODO: complain with strict
|
|
@@ -1408,6 +1409,9 @@ function addElementAsColumn( elem, cols ) {
|
|
|
1408
1409
|
setHidden( col, '$parens', parens.length );
|
|
1409
1410
|
addLocation( (parens ? parens[parens.length - 1] : elem.value.location), col );
|
|
1410
1411
|
}
|
|
1412
|
+
else if (elem.name && !elem.name.$inferred) {
|
|
1413
|
+
addLocation( elem.name.location, col );
|
|
1414
|
+
}
|
|
1411
1415
|
cols.push( extra( col, elem ) );
|
|
1412
1416
|
}
|
|
1413
1417
|
|
|
@@ -12,7 +12,7 @@ const antlr4 = require('antlr4');
|
|
|
12
12
|
|
|
13
13
|
const { CompileMessage } = require('../base/messages');
|
|
14
14
|
const errorStrategy = require('./errorStrategy');
|
|
15
|
-
const { XsnSource } = require('../compiler/
|
|
15
|
+
const { XsnSource } = require('../compiler/xsn-model');
|
|
16
16
|
|
|
17
17
|
const Parser = require('../gen/languageParser').default;
|
|
18
18
|
const Lexer = require('../gen/languageLexer').default;
|
|
@@ -14,14 +14,13 @@ const locUtils = require('../base/location');
|
|
|
14
14
|
const { parseDocComment } = require('./docCommentParser');
|
|
15
15
|
const { parseMultiLineStringLiteral } = require('./multiLineStringParser');
|
|
16
16
|
const {
|
|
17
|
-
functionsWithoutParens,
|
|
18
17
|
specialFunctions,
|
|
19
18
|
quotedLiteralPatterns,
|
|
20
19
|
} = require('../compiler/builtins');
|
|
20
|
+
const { functionsWithoutParens } = require('../base/builtins');
|
|
21
|
+
const { Location } = require('../base/location');
|
|
21
22
|
const { pathName } = require('../compiler/utils');
|
|
22
|
-
const {
|
|
23
|
-
XsnArtifact, XsnName, CsnLocation, XsnSource,
|
|
24
|
-
} = require('../compiler/classes');
|
|
23
|
+
const { XsnArtifact, XsnName, XsnSource } = require('../compiler/xsn-model');
|
|
25
24
|
const { isBetaEnabled } = require('../base/model');
|
|
26
25
|
const { weakLocation } = require('../base/location');
|
|
27
26
|
const { normalizeNewLine, normalizeNumberString } = require('./textUtils');
|
|
@@ -500,10 +499,10 @@ function handleDuplicateExtension( ext, name, numDefines ) {
|
|
|
500
499
|
* Return start location of `token`, or the first token matched by the current
|
|
501
500
|
* rule if `token` is undefined
|
|
502
501
|
*
|
|
503
|
-
* @returns {
|
|
502
|
+
* @returns {Location}
|
|
504
503
|
*/
|
|
505
504
|
function startLocation( token = this._ctx.start ) {
|
|
506
|
-
return new
|
|
505
|
+
return new Location(
|
|
507
506
|
this.filename,
|
|
508
507
|
token.line,
|
|
509
508
|
token.column + 1
|
|
@@ -516,7 +515,7 @@ function startLocation( token = this._ctx.start ) {
|
|
|
516
515
|
*
|
|
517
516
|
* @param {object} token
|
|
518
517
|
* @param {object} endToken
|
|
519
|
-
* @return {
|
|
518
|
+
* @return {Location}
|
|
520
519
|
*/
|
|
521
520
|
function tokenLocation( token, endToken = null ) {
|
|
522
521
|
if (!token)
|
|
@@ -528,7 +527,7 @@ function tokenLocation( token, endToken = null ) {
|
|
|
528
527
|
const endLine = endToken.line;
|
|
529
528
|
// after the last char (special for EOF?)
|
|
530
529
|
const endCol = endToken.stop - endToken.start + endToken.column + 2;
|
|
531
|
-
const loc = new
|
|
530
|
+
const loc = new Location( this.filename, token.line, token.column + 1, endLine, endCol );
|
|
532
531
|
|
|
533
532
|
// This check is done for performance reason. No need to access a token's
|
|
534
533
|
// data if we know that it spans only one single line.
|
|
@@ -629,7 +628,7 @@ function secureParens( expr ) {
|
|
|
629
628
|
return {
|
|
630
629
|
op: { val: 'xpr', location: this.startLocation() },
|
|
631
630
|
args: [ expr ],
|
|
632
|
-
location: { __proto__:
|
|
631
|
+
location: { __proto__: Location.prototype, ...expr.location },
|
|
633
632
|
$parens,
|
|
634
633
|
};
|
|
635
634
|
}
|
|
@@ -725,11 +724,11 @@ function fragileAlias( ast, safe = false ) {
|
|
|
725
724
|
return ast;
|
|
726
725
|
if (safe || ast.$delimited || !/^[a-zA-Z][a-zA-Z_]+$/.test( ast.id )) {
|
|
727
726
|
this.warning( 'syntax-deprecated-auto-as', ast.location, { keyword: 'as' },
|
|
728
|
-
'
|
|
727
|
+
'Add keyword $(KEYWORD) in front of the alias name' );
|
|
729
728
|
}
|
|
730
729
|
else { // configurable error
|
|
731
730
|
this.message( 'syntax-missing-as', ast.location, { keyword: 'as' },
|
|
732
|
-
'
|
|
731
|
+
'Add keyword $(KEYWORD) in front of the alias name' );
|
|
733
732
|
}
|
|
734
733
|
return ast;
|
|
735
734
|
}
|
|
@@ -760,10 +759,16 @@ function identAst( token, category, noTokenTypeCheck = false ) {
|
|
|
760
759
|
|
|
761
760
|
// $delimited is used to complain about ![$self] and other magic vars usage;
|
|
762
761
|
// we might complain about that already here via @arg{category}
|
|
763
|
-
|
|
762
|
+
|
|
763
|
+
const ast = { id, $delimited: true, location: this.tokenLocation( token ) };
|
|
764
|
+
ast.location.tokenIndex = token.tokenIndex;
|
|
765
|
+
return ast;
|
|
766
|
+
}
|
|
767
|
+
if (token.text[0] !== '"') {
|
|
768
|
+
const ast = { id, location: this.tokenLocation(token) };
|
|
769
|
+
ast.location.tokenIndex = token.tokenIndex;
|
|
770
|
+
return ast;
|
|
764
771
|
}
|
|
765
|
-
if (token.text[0] !== '"')
|
|
766
|
-
return { id, location: this.tokenLocation( token ) };
|
|
767
772
|
// delimited:
|
|
768
773
|
id = id.slice( 1, -1 ).replace( /""/g, '"' );
|
|
769
774
|
if (!id) {
|
|
@@ -774,7 +779,9 @@ function identAst( token, category, noTokenTypeCheck = false ) {
|
|
|
774
779
|
// eslint-disable-next-line max-len
|
|
775
780
|
'Deprecated delimited identifier syntax, use $(DELIMITED) - strings are delimited by single quotes' );
|
|
776
781
|
}
|
|
777
|
-
|
|
782
|
+
const ast = { id, $delimited: true, location: this.tokenLocation( token ) };
|
|
783
|
+
ast.location.tokenIndex = token.tokenIndex;
|
|
784
|
+
return ast;
|
|
778
785
|
}
|
|
779
786
|
|
|
780
787
|
function pushXprToken( args ) {
|
|
@@ -1346,7 +1353,7 @@ function argsExpression( args, nary ) {
|
|
|
1346
1353
|
return args[0];
|
|
1347
1354
|
const $parens = args[0]?.$parens;
|
|
1348
1355
|
const loc = ($parens) ? $parens[$parens.length - 1] : args[0]?.location;
|
|
1349
|
-
const location = loc ? { __proto__:
|
|
1356
|
+
const location = loc ? { __proto__: Location.prototype, ...loc } : this.startLocation();
|
|
1350
1357
|
// console.log('AE:',args);
|
|
1351
1358
|
const op = {
|
|
1352
1359
|
// eslint-disable-next-line no-nested-ternary
|
|
@@ -6,7 +6,7 @@ const {
|
|
|
6
6
|
cdlNewLineRegEx,
|
|
7
7
|
} = require('./textUtils');
|
|
8
8
|
const { CompilerAssertion } = require('../base/error');
|
|
9
|
-
const {
|
|
9
|
+
const { Location } = require('../base/location');
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Strips and counts the indentation from the given string.
|
|
@@ -463,7 +463,7 @@ class MultiLineStringParser {
|
|
|
463
463
|
*/
|
|
464
464
|
_locationForCharacters(i, width) {
|
|
465
465
|
return {
|
|
466
|
-
__proto__:
|
|
466
|
+
__proto__: Location.prototype,
|
|
467
467
|
file: this.parser.filename,
|
|
468
468
|
line: this.token.line + this._lineInString,
|
|
469
469
|
endLine: this.token.line + this._lineInString,
|
|
@@ -45,7 +45,7 @@ function isWhitespaceCharacterNoNewline( char ) {
|
|
|
45
45
|
* @return {string}
|
|
46
46
|
*/
|
|
47
47
|
function normalizeNewLine( str ) {
|
|
48
|
-
// Note: cdlNewLineRegEx does not have `g
|
|
48
|
+
// Note: cdlNewLineRegEx does not have `g`.
|
|
49
49
|
return str.replace(new RegExp(cdlNewLineRegEx, 'ug'), '\n');
|
|
50
50
|
}
|
|
51
51
|
|
package/lib/main.d.ts
CHANGED
|
@@ -150,6 +150,22 @@ declare namespace compiler {
|
|
|
150
150
|
* @since v2.12.1
|
|
151
151
|
*/
|
|
152
152
|
$xsnObjects?: boolean
|
|
153
|
+
/**
|
|
154
|
+
* Internal option for LSP only!
|
|
155
|
+
* If set, each AST gets a `tokenStream` property containing all lexed tokens.
|
|
156
|
+
*
|
|
157
|
+
* @private
|
|
158
|
+
*/
|
|
159
|
+
attachTokens?: boolean
|
|
160
|
+
/**
|
|
161
|
+
* Internal option for LSP only!
|
|
162
|
+
* If set, enables some extra checks/work for the CDS LSP.
|
|
163
|
+
* May be implicitly set by `$lsp.<api>` functions.
|
|
164
|
+
*
|
|
165
|
+
* @private
|
|
166
|
+
* @since v4.9
|
|
167
|
+
*/
|
|
168
|
+
lspMode?: boolean
|
|
153
169
|
}
|
|
154
170
|
|
|
155
171
|
/**
|
|
@@ -246,18 +262,48 @@ declare namespace compiler {
|
|
|
246
262
|
* @see service
|
|
247
263
|
*/
|
|
248
264
|
serviceNames?: string[]
|
|
265
|
+
/**
|
|
266
|
+
* If set, certain OData errors that are not relevant for OpenAPI generation
|
|
267
|
+
* are downgraded to warnings when generating EDM JSON.
|
|
268
|
+
*
|
|
269
|
+
* @default true
|
|
270
|
+
* @since v4.8.0
|
|
271
|
+
* @private
|
|
272
|
+
*/
|
|
273
|
+
edm4OpenAPI?: boolean
|
|
249
274
|
}
|
|
250
275
|
|
|
251
276
|
/**
|
|
252
277
|
* Options used by the `for.effective()` CSN transformation.
|
|
253
278
|
*
|
|
254
|
-
* WORK IN PROGRESS
|
|
255
|
-
*
|
|
256
279
|
* @internal
|
|
257
280
|
* @see _for.effective()
|
|
258
281
|
*/
|
|
259
282
|
export interface EffectiveCsnOptions extends SqlOptions {
|
|
260
|
-
|
|
283
|
+
/**
|
|
284
|
+
* If true, resolve simple type references to their simple base type.
|
|
285
|
+
*
|
|
286
|
+
* @default true
|
|
287
|
+
*/
|
|
288
|
+
resolveSimpleTypes?: boolean
|
|
289
|
+
/**
|
|
290
|
+
* If true, transform projections into ordinary views with SELECT.
|
|
291
|
+
*
|
|
292
|
+
* @default true
|
|
293
|
+
*/
|
|
294
|
+
resolveProjections?: boolean
|
|
295
|
+
/**
|
|
296
|
+
* If true, remap OData annotations to ABAP annotations.
|
|
297
|
+
*
|
|
298
|
+
* @default false
|
|
299
|
+
*/
|
|
300
|
+
remapOdataAnnotations?: boolean
|
|
301
|
+
/**
|
|
302
|
+
* If true, keep '.localized' property in the CSN.
|
|
303
|
+
*
|
|
304
|
+
* @default false
|
|
305
|
+
*/
|
|
306
|
+
keepLocalized?: boolean
|
|
261
307
|
}
|
|
262
308
|
|
|
263
309
|
/**
|
|
@@ -538,11 +584,6 @@ declare namespace compiler {
|
|
|
538
584
|
* @internal
|
|
539
585
|
*/
|
|
540
586
|
model?: CSN;
|
|
541
|
-
/**
|
|
542
|
-
* Used by `cdsc` to indicate whether the message was already printed to stderr.
|
|
543
|
-
* @private
|
|
544
|
-
*/
|
|
545
|
-
hasBeenReported: boolean;
|
|
546
587
|
}
|
|
547
588
|
|
|
548
589
|
/**
|
|
@@ -657,16 +698,23 @@ declare namespace compiler {
|
|
|
657
698
|
* @param config.noMessageId
|
|
658
699
|
* If true, will _not_ show the message ID (+ explanation hint) in the output.
|
|
659
700
|
*
|
|
701
|
+
* @param config.idInBrackets
|
|
702
|
+
* If true, the message ID (if there is one and noMessageId is falsey) will be put in brackets.
|
|
703
|
+
* This will be the default in cds-compiler v5.
|
|
704
|
+
*
|
|
660
705
|
* @param config.noHome
|
|
661
706
|
* If true, will _not_ show message's semantic location.
|
|
662
707
|
*
|
|
663
|
-
* @param config.
|
|
708
|
+
* @param config.moduleForMarker
|
|
664
709
|
* If set, downgradable error messages will get a '‹↓›' marker, depending on whether
|
|
665
|
-
* the message can be downgraded for the given module.
|
|
710
|
+
* the message can be downgraded for the given module. A `‹↑›` is used if the message
|
|
711
|
+
* will be an error in the next major cds-compiler release.
|
|
712
|
+
* Was called `module` in v4.8.0 and earlier.
|
|
666
713
|
*/
|
|
667
714
|
export function messageString(msg: CompileMessage, config?: {
|
|
668
715
|
normalizeFilename?: boolean
|
|
669
716
|
noMessageId?: boolean
|
|
717
|
+
idInBrackets?: boolean
|
|
670
718
|
noHome?: boolean
|
|
671
719
|
module?: string
|
|
672
720
|
}): string;
|
|
@@ -704,9 +752,11 @@ declare namespace compiler {
|
|
|
704
752
|
* @param config.hintExplanation
|
|
705
753
|
* If true, messages with explanations will get a "…" marker, see {@link hasMessageExplanation}.
|
|
706
754
|
*
|
|
707
|
-
* @param config.
|
|
755
|
+
* @param config.moduleForMarker
|
|
708
756
|
* If set, downgradable error messages will get a '‹↓›' marker, depending on whether
|
|
709
|
-
* the message can be downgraded for the given module.
|
|
757
|
+
* the message can be downgraded for the given module. A `‹↑›` is used if the message
|
|
758
|
+
* will be an error in the next major cds-compiler release.
|
|
759
|
+
* Was called `module` in v4.8.0 and earlier.
|
|
710
760
|
*
|
|
711
761
|
* @param config.sourceMap
|
|
712
762
|
* A dictionary of filename<->source-code entries. You can pass the fileCache that is used
|
|
@@ -733,7 +783,7 @@ declare namespace compiler {
|
|
|
733
783
|
normalizeFilename?: boolean
|
|
734
784
|
noMessageId?: boolean
|
|
735
785
|
hintExplanation?: boolean
|
|
736
|
-
|
|
786
|
+
moduleForMarker?: string
|
|
737
787
|
sourceMap?: Record<string, string>
|
|
738
788
|
sourceLineMap?: Record<string, number[]>
|
|
739
789
|
cwd?: string
|
|
@@ -848,6 +898,12 @@ declare namespace compiler {
|
|
|
848
898
|
* @internal
|
|
849
899
|
*/
|
|
850
900
|
function effective(csn: CSN, options?: EffectiveCsnOptions): CSN;
|
|
901
|
+
/**
|
|
902
|
+
* Transform the given CSN into one that has the properties required for SEAL
|
|
903
|
+
*
|
|
904
|
+
* @internal
|
|
905
|
+
*/
|
|
906
|
+
function seal(csn: CSN, options?: EffectiveCsnOptions): CSN;
|
|
851
907
|
}
|
|
852
908
|
|
|
853
909
|
export { _for as for };
|
|
@@ -951,6 +1007,20 @@ declare namespace compiler {
|
|
|
951
1007
|
*/
|
|
952
1008
|
const keywords: string[];
|
|
953
1009
|
}
|
|
1010
|
+
namespace h2 {
|
|
1011
|
+
/**
|
|
1012
|
+
* Immutable list of reserved keywords for H2. The list is used by {@link to.sql}.
|
|
1013
|
+
* Taken from <http://www.h2database.com/html/advanced.html#keywords>.
|
|
1014
|
+
*/
|
|
1015
|
+
const keywords: string[];
|
|
1016
|
+
}
|
|
1017
|
+
namespace postgres {
|
|
1018
|
+
/**
|
|
1019
|
+
* Immutable list of reserved keywords for PostgreSQL. The list is used by {@link to.sql}.
|
|
1020
|
+
* Taken from <https://www.postgresql.org/docs/current/sql-keywords-appendix.html>.
|
|
1021
|
+
*/
|
|
1022
|
+
const keywords: string[];
|
|
1023
|
+
}
|
|
954
1024
|
|
|
955
1025
|
/**
|
|
956
1026
|
* If the given `name` requires quoting for SQL dialect `dialect`,
|
|
@@ -1246,7 +1316,13 @@ declare namespace compiler {
|
|
|
1246
1316
|
* The functions in `userFunctions` are usually transformer functions, which
|
|
1247
1317
|
* change the input CSN destructively.
|
|
1248
1318
|
*/
|
|
1249
|
-
export function traverseCsn(userFunctions: Record<string,
|
|
1319
|
+
export function traverseCsn(userFunctions: Record<string, TraverseCsnCallback>, csn: object|any[]): void;
|
|
1320
|
+
export type TraverseCsnCallback = (
|
|
1321
|
+
userFunctions: Record<string, TraverseCsnCallback>,
|
|
1322
|
+
value: any,
|
|
1323
|
+
csn: any,
|
|
1324
|
+
prop: string
|
|
1325
|
+
) => any;
|
|
1250
1326
|
|
|
1251
1327
|
/**
|
|
1252
1328
|
* CSN Model related functions.
|
package/lib/main.js
CHANGED
|
@@ -26,7 +26,7 @@ const parseLanguage = lazyload('./language/antlrParser');
|
|
|
26
26
|
const compiler = lazyload('./compiler');
|
|
27
27
|
const shared = lazyload('./compiler/shared');
|
|
28
28
|
const define = lazyload('./compiler/define');
|
|
29
|
-
const builtins = lazyload('./
|
|
29
|
+
const builtins = lazyload('./base/builtins');
|
|
30
30
|
const base = lazyload('./compiler/base');
|
|
31
31
|
const finalizeParseCdl = lazyload('./compiler/finalize-parse-cdl');
|
|
32
32
|
|
|
@@ -126,7 +126,9 @@ module.exports = {
|
|
|
126
126
|
// SNAPI
|
|
127
127
|
for: {
|
|
128
128
|
odata: (...args) => snapi.odata(...args),
|
|
129
|
+
java: (...args) => snapi.java(...args),
|
|
129
130
|
effective: (...args) => snapi.for_effective(...args),
|
|
131
|
+
seal: (...args) => snapi.for_seal(...args),
|
|
130
132
|
},
|
|
131
133
|
to: {
|
|
132
134
|
cdl: Object.assign((...args) => snapi.cdl(...args), {
|
|
@@ -141,6 +143,12 @@ module.exports = {
|
|
|
141
143
|
sqlite: {
|
|
142
144
|
keywords: Object.freeze([ ...keywords.sqlite ] )
|
|
143
145
|
},
|
|
146
|
+
postgres: {
|
|
147
|
+
keywords: Object.freeze([ ...keywords.postgres ] )
|
|
148
|
+
},
|
|
149
|
+
h2: {
|
|
150
|
+
keywords: Object.freeze([ ...keywords.h2 ] )
|
|
151
|
+
},
|
|
144
152
|
smartId: (...args) => sqlIdentifier.smartId(...args),
|
|
145
153
|
smartFunctionId: (...args) => sqlIdentifier.smartFuncId(...args),
|
|
146
154
|
delimitedId: (...args) => sqlIdentifier.delimitedId(...args),
|
package/lib/model/cloneCsn.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const { csnPropertyOrder } = require('../json/to-csn');
|
|
4
4
|
const { ModelError } = require('../base/error');
|
|
5
5
|
const { setHidden } = require('../utils/objectUtils');
|
|
6
|
-
const { isAnnotationExpression } = require('../
|
|
6
|
+
const { isAnnotationExpression } = require('../base/builtins');
|
|
7
7
|
|
|
8
8
|
const csnDictionaries = [
|
|
9
9
|
'args',
|
|
@@ -21,16 +21,22 @@ function shallowCopy( val, _options, _sort ) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
const internalCsnProps = {
|
|
24
|
+
__proto__: null,
|
|
24
25
|
$sources: shallowCopy,
|
|
25
26
|
$location: shallowCopy,
|
|
26
27
|
$path: shallowCopy,
|
|
27
28
|
$paths: shallowCopy,
|
|
28
29
|
elements: cloneCsnDict,
|
|
29
30
|
$tableConstraints: shallowCopy,
|
|
31
|
+
$default: shallowCopy, // used for HANA CSN migrations
|
|
32
|
+
$notNull: shallowCopy, // used for HANA CSN migrations
|
|
33
|
+
};
|
|
34
|
+
const internalEnumerableCsnProps = {
|
|
35
|
+
__proto__: null,
|
|
36
|
+
$tableConstraints: shallowCopy, // enumerable for HANA CSN for migrations
|
|
30
37
|
};
|
|
31
38
|
const internalCsnPropertyNames = Object.keys(internalCsnProps);
|
|
32
39
|
|
|
33
|
-
|
|
34
40
|
/**
|
|
35
41
|
* Deeply clone the given CSN model and return it.
|
|
36
42
|
* In testMode (or with testSortCsn), definitions are sorted.
|
|
@@ -41,9 +47,12 @@ const internalCsnPropertyNames = Object.keys(internalCsnProps);
|
|
|
41
47
|
* @see cloneAnnotationValue()
|
|
42
48
|
* @see cloneCsnDict()
|
|
43
49
|
*
|
|
44
|
-
* @param {object} csn
|
|
45
|
-
*
|
|
46
|
-
* @param {
|
|
50
|
+
* @param {object} csn
|
|
51
|
+
* Top-level CSN. You can pass non-dictionary values.
|
|
52
|
+
* @param {CSN.Options} options
|
|
53
|
+
* CSN Options, only used for `dictionaryPrototype`, `testMode`, and `testSortCsn`.
|
|
54
|
+
* @param {boolean} sort
|
|
55
|
+
* Whether to sort CSN properties.
|
|
47
56
|
*/
|
|
48
57
|
function cloneCsn( csn, options, sort ) {
|
|
49
58
|
if (!csn || typeof csn !== 'object')
|
|
@@ -58,18 +67,21 @@ function cloneCsn( csn, options, sort ) {
|
|
|
58
67
|
const r = {};
|
|
59
68
|
for (const n of keys) {
|
|
60
69
|
const val = csn[n];
|
|
61
|
-
if (
|
|
62
|
-
r[n] = val;
|
|
63
|
-
}
|
|
64
|
-
else if (n.charAt(0) === '@') {
|
|
70
|
+
if (n.charAt(0) === '@') {
|
|
65
71
|
r[n] = cloneAnnotationValue(val, options, false); // TODO: pass 'sort'
|
|
66
72
|
}
|
|
73
|
+
else if (!val || typeof val !== 'object') {
|
|
74
|
+
r[n] = val;
|
|
75
|
+
}
|
|
67
76
|
else if (csnDictionaries.includes(n) && !Array.isArray(val)) {
|
|
68
77
|
const sortDict = n === 'definitions' &&
|
|
69
78
|
(!options || options.testMode || options.testSortCsn);
|
|
70
79
|
// Array check for property `args` which may either be a dictionary or an array.
|
|
71
80
|
r[n] = cloneCsnDict(val, options, sort, sortDict);
|
|
72
81
|
}
|
|
82
|
+
else if (n in internalEnumerableCsnProps) {
|
|
83
|
+
r[n] = internalEnumerableCsnProps[n](val, options, sort);
|
|
84
|
+
}
|
|
73
85
|
else {
|
|
74
86
|
r[n] = cloneCsn(val, options, sort);
|
|
75
87
|
}
|