@sap/cds-compiler 2.12.0 → 2.15.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 +221 -15
- package/bin/cdsc.js +125 -50
- package/bin/cdsse.js +2 -2
- package/doc/CHANGELOG_BETA.md +13 -6
- package/doc/CHANGELOG_DEPRECATED.md +22 -6
- package/doc/NameResolution.md +21 -16
- package/lib/api/main.js +47 -84
- package/lib/api/options.js +5 -6
- package/lib/api/validate.js +6 -11
- package/lib/backends.js +15 -23
- package/lib/base/dictionaries.js +0 -8
- package/lib/base/error.js +26 -0
- package/lib/base/keywords.js +7 -17
- package/lib/base/location.js +9 -4
- package/lib/base/message-registry.js +114 -18
- package/lib/base/messages.js +101 -90
- package/lib/base/model.js +2 -63
- package/lib/base/optionProcessorHelper.js +177 -123
- package/lib/checks/annotationsOData.js +12 -33
- package/lib/checks/arrayOfs.js +1 -34
- package/lib/checks/cdsPersistence.js +2 -1
- package/lib/checks/enricher.js +17 -1
- package/lib/checks/invalidTarget.js +3 -1
- package/lib/checks/managedWithoutKeys.js +3 -1
- package/lib/checks/selectItems.js +4 -4
- package/lib/checks/sql-snippets.js +27 -26
- package/lib/checks/types.js +1 -1
- package/lib/checks/validator.js +6 -11
- package/lib/compiler/assert-consistency.js +6 -3
- package/lib/compiler/base.js +1 -0
- package/lib/compiler/builtins.js +19 -6
- package/lib/compiler/checks.js +23 -60
- package/lib/compiler/cycle-detector.js +1 -1
- package/lib/compiler/define.js +1151 -0
- package/lib/compiler/extend.js +1000 -0
- package/lib/compiler/finalize-parse-cdl.js +237 -0
- package/lib/compiler/index.js +107 -39
- package/lib/compiler/kick-start.js +190 -0
- package/lib/compiler/moduleLayers.js +4 -4
- package/lib/compiler/populate.js +1227 -0
- package/lib/compiler/propagator.js +114 -46
- package/lib/compiler/resolve.js +1521 -0
- package/lib/compiler/shared.js +126 -65
- package/lib/compiler/tweak-assocs.js +535 -0
- package/lib/compiler/utils.js +197 -33
- package/lib/edm/.eslintrc.json +5 -0
- package/lib/edm/annotations/genericTranslation.js +38 -24
- package/lib/edm/annotations/preprocessAnnotations.js +2 -2
- package/lib/edm/csn2edm.js +219 -100
- package/lib/edm/edm.js +302 -230
- package/lib/edm/edmPreprocessor.js +554 -419
- package/lib/edm/edmUtils.js +138 -44
- package/lib/gen/Dictionary.json +100 -19
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +11 -1
- package/lib/gen/language.tokens +86 -83
- package/lib/gen/languageLexer.interp +10 -1
- package/lib/gen/languageLexer.js +860 -833
- package/lib/gen/languageLexer.tokens +78 -75
- package/lib/gen/languageParser.js +5765 -4480
- package/lib/json/csnVersion.js +10 -11
- package/lib/json/from-csn.js +15 -3
- package/lib/json/to-csn.js +126 -68
- package/lib/language/docCommentParser.js +4 -4
- package/lib/language/genericAntlrParser.js +123 -5
- package/lib/language/language.g4 +355 -156
- package/lib/language/multiLineStringParser.js +5 -5
- package/lib/main.d.ts +486 -59
- package/lib/main.js +41 -9
- package/lib/model/api.js +3 -1
- package/lib/model/csnRefs.js +252 -156
- package/lib/model/csnUtils.js +384 -297
- package/lib/model/enrichCsn.js +71 -29
- package/lib/model/revealInternalProperties.js +29 -8
- package/lib/model/sortViews.js +2 -1
- package/lib/modelCompare/compare.js +23 -18
- package/lib/optionProcessor.js +63 -26
- package/lib/render/manageConstraints.js +35 -32
- package/lib/render/toCdl.js +897 -947
- package/lib/render/toHdbcds.js +205 -257
- package/lib/render/toSql.js +264 -225
- package/lib/render/utils/common.js +136 -25
- package/lib/render/utils/sql.js +4 -3
- package/lib/render/utils/stringEscapes.js +111 -0
- package/lib/sql-identifier.js +1 -1
- package/lib/transform/.eslintrc.json +5 -0
- package/lib/transform/db/.eslintrc.json +3 -1
- package/lib/transform/db/applyTransformations.js +35 -12
- package/lib/transform/db/assertUnique.js +1 -1
- package/lib/transform/db/associations.js +104 -306
- package/lib/transform/db/cdsPersistence.js +2 -2
- package/lib/transform/db/constraints.js +58 -53
- package/lib/transform/db/expansion.js +60 -33
- package/lib/transform/db/flattening.js +582 -104
- package/lib/transform/db/groupByOrderBy.js +3 -1
- package/lib/transform/db/transformExists.js +66 -13
- package/lib/transform/db/views.js +11 -7
- package/lib/transform/draft/.eslintrc.json +38 -0
- package/lib/transform/{db/draft.js → draft/db.js} +6 -5
- package/lib/transform/draft/odata.js +227 -0
- package/lib/transform/forHanaNew.js +109 -208
- package/lib/transform/forOdataNew.js +59 -212
- package/lib/transform/localized.js +46 -26
- package/lib/transform/odata/toFinalBaseType.js +85 -11
- package/lib/transform/odata/typesExposure.js +147 -199
- package/lib/transform/odata/utils.js +2 -2
- package/lib/transform/transformUtilsNew.js +44 -33
- package/lib/transform/translateAssocsToJoins.js +3 -20
- package/lib/transform/universalCsn/.eslintrc.json +36 -0
- package/lib/transform/universalCsn/coreComputed.js +172 -0
- package/lib/transform/universalCsn/universalCsnEnricher.js +737 -0
- package/lib/transform/universalCsn/utils.js +63 -0
- package/lib/utils/moduleResolve.js +13 -6
- package/lib/utils/objectUtils.js +30 -0
- package/package.json +1 -1
- package/share/messages/README.md +26 -0
- package/share/messages/message-explanations.json +2 -1
- package/share/messages/syntax-expected-integer.md +37 -0
- package/lib/compiler/definer.js +0 -2361
- package/lib/compiler/resolver.js +0 -3079
- package/lib/transform/odata/attachPath.js +0 -96
- package/lib/transform/odata/expandStructKeysInAssociations.js +0 -59
- package/lib/transform/odata/generateForeignKeyElements.js +0 -261
- package/lib/transform/odata/referenceFlattener.js +0 -290
- package/lib/transform/odata/sortByAssociationDependency.js +0 -105
- package/lib/transform/odata/structuralPath.js +0 -72
- package/lib/transform/odata/structureFlattener.js +0 -171
- package/lib/transform/universalCsnEnricher.js +0 -237
|
@@ -14,6 +14,7 @@ const { parseDocComment } = require('./docCommentParser');
|
|
|
14
14
|
const { parseMultiLineStringLiteral } = require('./multiLineStringParser');
|
|
15
15
|
const { functionsWithoutParens, specialFunctions } = require('../compiler/builtins');
|
|
16
16
|
|
|
17
|
+
const $location = Symbol.for('cds.$location');
|
|
17
18
|
|
|
18
19
|
// Push message `msg` with location `loc` to array of errors:
|
|
19
20
|
function _message( parser, severity, id, loc, ...args ) {
|
|
@@ -35,6 +36,19 @@ function GenericAntlrParser( ...args ) {
|
|
|
35
36
|
// ANTLR restriction: we cannot add parameters to the constructor.
|
|
36
37
|
antlr4.Parser.call( this, ...args );
|
|
37
38
|
this.buildParseTrees = false;
|
|
39
|
+
|
|
40
|
+
// Common properties.
|
|
41
|
+
// We set them here so that they are available in the prototype.
|
|
42
|
+
// This improved performance by 25% for certain scenario tests.
|
|
43
|
+
// Probably because there was no need to look up the prototype chain anymore.
|
|
44
|
+
this.$adaptExpectedToken = null;
|
|
45
|
+
this.$adaptExpectedExcludes = [ ];
|
|
46
|
+
this.$nextTokensToken = null;
|
|
47
|
+
this.$nextTokensContext = null;
|
|
48
|
+
|
|
49
|
+
this.prepareGenericKeywords();
|
|
50
|
+
this.options = {};
|
|
51
|
+
|
|
38
52
|
return this;
|
|
39
53
|
}
|
|
40
54
|
|
|
@@ -55,6 +69,8 @@ GenericAntlrParser.prototype = Object.assign(
|
|
|
55
69
|
valueWithTokenLocation,
|
|
56
70
|
previousTokenAtLocation,
|
|
57
71
|
combinedLocation,
|
|
72
|
+
createDict,
|
|
73
|
+
setDictEndLocation,
|
|
58
74
|
surroundByParens,
|
|
59
75
|
unaryOpForParens,
|
|
60
76
|
leftAssocBinaryOp,
|
|
@@ -70,15 +86,19 @@ GenericAntlrParser.prototype = Object.assign(
|
|
|
70
86
|
docComment,
|
|
71
87
|
addDef,
|
|
72
88
|
addItem,
|
|
89
|
+
artifactForElementAnnotateOrExtend,
|
|
73
90
|
assignProps,
|
|
74
91
|
createPrefixOp,
|
|
75
92
|
setOnce,
|
|
76
93
|
setMaxCardinality,
|
|
77
94
|
pushIdent,
|
|
78
95
|
handleComposition,
|
|
96
|
+
associationInSelectItem,
|
|
79
97
|
reportExpandInline,
|
|
98
|
+
checkTypeFacet,
|
|
80
99
|
notSupportedYet,
|
|
81
100
|
csnParseOnly,
|
|
101
|
+
disallowElementExtension,
|
|
82
102
|
noAssignmentInSameLine,
|
|
83
103
|
noSemicolonHere,
|
|
84
104
|
setLocalToken,
|
|
@@ -213,6 +233,22 @@ function setLocalTokenIfBefore( string, tokenName, before, inSameLine ) {
|
|
|
213
233
|
// // throw new antlr4.error.InputMismatchException(this);
|
|
214
234
|
// }
|
|
215
235
|
|
|
236
|
+
/**
|
|
237
|
+
* For element extensions (`extend E:elem` syntax).
|
|
238
|
+
* If `elemName.path` is set, remove the last extension from `$outer` and
|
|
239
|
+
* emit an error that the extension is invalid.
|
|
240
|
+
*
|
|
241
|
+
* @param {object} elemName
|
|
242
|
+
* @param {object} outer
|
|
243
|
+
* @param {string} extensionVariant
|
|
244
|
+
*/
|
|
245
|
+
function disallowElementExtension(elemName, outer, extensionVariant) {
|
|
246
|
+
if (elemName.path) {
|
|
247
|
+
this.message( 'syntax-invalid-extend', this.tokenLocation(this.getCurrentToken()), { 'kind': extensionVariant } );
|
|
248
|
+
outer.extensions.length = outer.extensions.length - 1; // remove last, i.e. new extension
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
216
252
|
function noAssignmentInSameLine() {
|
|
217
253
|
const t = this.getCurrentToken();
|
|
218
254
|
if (t.text === '@' && t.line <= this._input.LT(-1).line) {
|
|
@@ -373,6 +409,20 @@ function combinedLocation( start, end ) {
|
|
|
373
409
|
return locUtils.combinedLocation( start, end );
|
|
374
410
|
}
|
|
375
411
|
|
|
412
|
+
function createDict( location = null ) {
|
|
413
|
+
const dict = Object.create(null);
|
|
414
|
+
dict[$location] = location || this.startLocation( this._input.LT(-1) );
|
|
415
|
+
return dict;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function setDictEndLocation( dict ) {
|
|
419
|
+
const stop = this._input.LT(-1);
|
|
420
|
+
Object.assign( dict[$location], {
|
|
421
|
+
endLine: stop.line,
|
|
422
|
+
endCol: stop.stop - stop.start + stop.column + 2,
|
|
423
|
+
} );
|
|
424
|
+
}
|
|
425
|
+
|
|
376
426
|
function surroundByParens( expr, open, close, asQuery = false ) {
|
|
377
427
|
if (!expr)
|
|
378
428
|
return expr;
|
|
@@ -546,11 +596,11 @@ function numberLiteral( token, sign, text = token.text ) {
|
|
|
546
596
|
location.endCol = endCol;
|
|
547
597
|
text = sign.text + text;
|
|
548
598
|
}
|
|
599
|
+
|
|
549
600
|
const num = Number.parseFloat( text || '0' ); // not Number.parseInt() !
|
|
550
601
|
if (!Number.isSafeInteger(num)) {
|
|
551
602
|
if (sign == null) {
|
|
552
|
-
this.error( 'syntax-
|
|
553
|
-
'An integer number is expected here' );
|
|
603
|
+
this.error( 'syntax-expected-integer', token, { '#': !text.match(/^[0-9]*$/) ? 'normal' : 'unsafe'} );
|
|
554
604
|
}
|
|
555
605
|
else if (text !== `${num}`) {
|
|
556
606
|
return { literal: 'number', val: text, location };
|
|
@@ -664,13 +714,13 @@ function addDef( parent, env, kind, name, annos, props, location ) {
|
|
|
664
714
|
}
|
|
665
715
|
}
|
|
666
716
|
else if (name && name.id == null) {
|
|
667
|
-
name.id = pathName(name.path ); // A.B.C -> 'A.B.C'
|
|
717
|
+
name.id = pathName( name.path ); // A.B.C -> 'A.B.C'
|
|
668
718
|
}
|
|
669
719
|
const art = this.assignProps( { name }, annos, props, location );
|
|
670
720
|
if (kind)
|
|
671
721
|
art.kind = kind;
|
|
672
|
-
if (!parent[env])
|
|
673
|
-
parent[env] = Object.create(null);
|
|
722
|
+
if (!parent[env]) // TODO: dump with --test-mode, env !== 'artifacts'
|
|
723
|
+
parent[env] = env === 'args' ? Object.create(null) : this.createDict( { ...location } );
|
|
674
724
|
if (!art.name || art.name.id == null) {
|
|
675
725
|
// no id was parsed, but with error recovery: no further error
|
|
676
726
|
// TODO: add to parent[env]['']
|
|
@@ -727,6 +777,31 @@ function addItem( parent, env, kind, annos, props, location ) {
|
|
|
727
777
|
return art;
|
|
728
778
|
}
|
|
729
779
|
|
|
780
|
+
/**
|
|
781
|
+
* For `annotate/extend E:elem.sub`, create the `elements` structure
|
|
782
|
+
* that can be used by the core compiler to annotate/extend elements.
|
|
783
|
+
*
|
|
784
|
+
* @param {string} kind Either `annotate` or `extend`
|
|
785
|
+
* @param {object} artifact Main artifact that shall have `elements`.
|
|
786
|
+
* @param {XSN.Path} elementPath Path as returned by `simplePath` token.
|
|
787
|
+
* @param {object[]} annos Existing annotations that shall be added to the _last_ path step.
|
|
788
|
+
* @param {XSN.Location} artifactLocation Start location of the `annotate` statement.
|
|
789
|
+
* @returns {object} Deepest element
|
|
790
|
+
*/
|
|
791
|
+
function artifactForElementAnnotateOrExtend(kind, artifact, elementPath, annos, artifactLocation ) {
|
|
792
|
+
if (!Array.isArray(elementPath) || elementPath.broken || elementPath.length < 1)
|
|
793
|
+
return artifact;
|
|
794
|
+
|
|
795
|
+
for (const seg of elementPath.slice(0, -1)) {
|
|
796
|
+
artifact = this.addDef( artifact, 'elements', kind,
|
|
797
|
+
{ path: [seg], location: seg.location }, null, {}, artifactLocation );
|
|
798
|
+
}
|
|
799
|
+
const last = elementPath[elementPath.length - 1];
|
|
800
|
+
artifact = this.addDef( artifact, 'elements', kind,
|
|
801
|
+
{ path: [ last ], location: last.location }, annos, {}, artifactLocation );
|
|
802
|
+
return artifact;
|
|
803
|
+
}
|
|
804
|
+
|
|
730
805
|
/** Assign all non-empty (undefined, null, {}, []) properties in argument
|
|
731
806
|
* `props` and argument `annos` as property `$annotations` to `target`
|
|
732
807
|
* and return it. Hack: if argument `annos` is exactly `true`, return
|
|
@@ -829,6 +904,31 @@ function handleComposition( cardinality, isComposition ) {
|
|
|
829
904
|
this.excludeExpected( [ [ "'}'", 'COMPOSITIONofBRACE' ], brace1, ...manyOne ] );
|
|
830
905
|
}
|
|
831
906
|
|
|
907
|
+
function associationInSelectItem( art ) {
|
|
908
|
+
const isPath = art.value.path && art.value.path.length
|
|
909
|
+
const isIdentifier = isPath && art.value.path.length === 1;
|
|
910
|
+
if (isIdentifier) {
|
|
911
|
+
if (!art.name) {
|
|
912
|
+
art.name = art.value.path[0];
|
|
913
|
+
} else {
|
|
914
|
+
// Use alias if provided, i.e. ignore art.value.path.
|
|
915
|
+
this.error( 'query-unexpected-alias', art.name.location, {},
|
|
916
|
+
'Unexpected alias for association' );
|
|
917
|
+
}
|
|
918
|
+
delete art.value;
|
|
919
|
+
} else {
|
|
920
|
+
const loc = isPath ? art.value.path[1].location : art.value.location;
|
|
921
|
+
// If neither path nor alias are present, `query-req-name` is emitted in `populate.js`.
|
|
922
|
+
if (isPath || art.name) {
|
|
923
|
+
this.error( 'query-expected-identifier', loc, { '#': 'assoc' } );
|
|
924
|
+
if (isPath) {
|
|
925
|
+
art.name = art.value.path[art.value.path.length - 1];
|
|
926
|
+
}
|
|
927
|
+
delete art.value;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
832
932
|
function reportExpandInline( clauseName ) {
|
|
833
933
|
let token = this.getCurrentToken();
|
|
834
934
|
// improve error location when using "inline" `.{…}` after ref (arguments and
|
|
@@ -840,6 +940,24 @@ function reportExpandInline( clauseName ) {
|
|
|
840
940
|
'Unexpected nested $(PROP), can only be used after a reference' );
|
|
841
941
|
}
|
|
842
942
|
|
|
943
|
+
function checkTypeFacet( art, argIdent ) {
|
|
944
|
+
const id = argIdent.id;
|
|
945
|
+
if (id === 'length' || id === 'scale' || id === 'precision' || id === 'srid') {
|
|
946
|
+
if (art[id] !== undefined) {
|
|
947
|
+
this.error( 'syntax-duplicate-argument', argIdent.location,
|
|
948
|
+
{ '#': 'duplicate', code: id } );
|
|
949
|
+
this.error( 'syntax-duplicate-argument', art[id].location,
|
|
950
|
+
{ '#': 'duplicate', code: id } );
|
|
951
|
+
}
|
|
952
|
+
return true;
|
|
953
|
+
|
|
954
|
+
} else {
|
|
955
|
+
this.error( 'syntax-duplicate-argument', argIdent.location,
|
|
956
|
+
{ '#': 'unknown', code: id } );
|
|
957
|
+
return false;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
|
|
843
961
|
module.exports = {
|
|
844
962
|
genericAntlrParser: GenericAntlrParser,
|
|
845
963
|
};
|