@sap/cds-compiler 5.1.2 → 5.2.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 +26 -0
- package/bin/cdsc.js +2 -2
- package/bin/cdshi.js +24 -17
- package/bin/cdsse.js +17 -18
- package/lib/api/main.js +19 -2
- package/lib/api/options.js +4 -1
- package/lib/base/builtins.js +1 -0
- package/lib/base/message-registry.js +16 -3
- package/lib/base/model.js +0 -10
- package/lib/checks/actionsFunctions.js +0 -12
- package/lib/checks/structuredAnnoExpressions.js +10 -14
- package/lib/compiler/assert-consistency.js +19 -11
- package/lib/compiler/builtins.js +1 -1
- package/lib/compiler/define.js +3 -3
- package/lib/compiler/extend.js +5 -5
- package/lib/compiler/populate.js +9 -9
- package/lib/compiler/propagator.js +1 -0
- package/lib/compiler/resolve.js +29 -34
- package/lib/compiler/shared.js +7 -8
- package/lib/compiler/tweak-assocs.js +155 -64
- package/lib/compiler/utils.js +1 -1
- package/lib/compiler/xpr-rewrite.js +4 -3
- package/lib/edm/annotations/genericTranslation.js +13 -9
- package/lib/edm/csn2edm.js +26 -2
- package/lib/edm/edm.js +23 -8
- package/lib/edm/edmInboundChecks.js +5 -7
- package/lib/edm/edmPreprocessor.js +43 -30
- package/lib/gen/BaseParser.js +720 -0
- package/lib/gen/CdlParser.js +4421 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +4006 -4001
- package/lib/language/antlrParser.js +62 -0
- package/lib/language/genericAntlrParser.js +28 -0
- package/lib/model/csnUtils.js +2 -0
- package/lib/model/revealInternalProperties.js +2 -0
- package/lib/modelCompare/utils/filter.js +70 -42
- package/lib/optionProcessor.js +9 -3
- package/lib/parsers/AstBuildingParser.js +1172 -0
- package/lib/parsers/CdlGrammar.g4 +1940 -0
- package/lib/parsers/Lexer.js +239 -0
- package/lib/render/toCdl.js +23 -27
- package/lib/render/toSql.js +5 -5
- package/lib/transform/db/applyTransformations.js +54 -16
- package/lib/transform/draft/odata.js +10 -11
- package/lib/transform/effective/flattening.js +10 -14
- package/lib/transform/odata/flattening.js +42 -31
- package/lib/transform/odata/toFinalBaseType.js +7 -6
- package/lib/transform/universalCsn/universalCsnEnricher.js +1 -0
- package/package.json +2 -2
- package/share/messages/redirected-to-ambiguous.md +5 -4
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { forEachDefinition,
|
|
4
4
|
copyAnnotations, forEachMemberRecursively,
|
|
5
|
-
transformExpression,
|
|
5
|
+
transformExpression, transformAnnotationExpression } = require('../../model/csnUtils');
|
|
6
6
|
const { isBuiltinType, isMagicVariable } = require('../../base/builtins');
|
|
7
7
|
const transformUtils = require('../transformUtils');
|
|
8
8
|
const { setProp } = require('../../base/model');
|
|
@@ -54,7 +54,7 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, isExternal
|
|
|
54
54
|
if (flatElt.items) {
|
|
55
55
|
// rewrite annotation paths inside items.elements
|
|
56
56
|
forEachMemberRecursively(flatElt.items, (elt, _eltName, _prop, path) => {
|
|
57
|
-
const exprAnnos = Object.keys(elt).filter(pn =>
|
|
57
|
+
const exprAnnos = Object.keys(elt).filter(pn => pn[0] === '@');
|
|
58
58
|
flattenAndPrefixExprPaths(elt, exprAnnos, elt.$path, path, 0, true);
|
|
59
59
|
}, [ flatEltName ], true, { pathWithoutProp: true } );
|
|
60
60
|
}
|
|
@@ -67,7 +67,7 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, isExternal
|
|
|
67
67
|
});
|
|
68
68
|
// entity annotations
|
|
69
69
|
const flatAnnos = Object.create(null);
|
|
70
|
-
const annoNames = copyAnnotations(def, flatAnnos).filter(
|
|
70
|
+
const annoNames = copyAnnotations(def, flatAnnos).filter(pn => pn[0] === '@');
|
|
71
71
|
flattenAndPrefixExprPaths(flatAnnos, annoNames, [ 'definitions', defName ], [ defName ], 0);
|
|
72
72
|
setProp(def, '$flatAnnotations', flatAnnos);
|
|
73
73
|
// explicit binding parameter of bound action
|
|
@@ -100,10 +100,10 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, isExternal
|
|
|
100
100
|
};
|
|
101
101
|
|
|
102
102
|
const flatAnnos = Object.create(null);
|
|
103
|
-
const annoNames = copyAnnotations(action, flatAnnos).filter(
|
|
103
|
+
const annoNames = copyAnnotations(action, flatAnnos).filter(pn => pn[0] === '@');
|
|
104
104
|
annoNames.forEach((an) => {
|
|
105
105
|
refCheck.anno = an;
|
|
106
|
-
|
|
106
|
+
transformAnnotationExpression(flatAnnos, an,
|
|
107
107
|
[ markBindingParam, refCheck, refFlattener ],
|
|
108
108
|
[ 'definitions', defName, 'actions', actionName ]);
|
|
109
109
|
adaptRefs.forEach(fn => fn(true, 1, (parent) => parent.$bparam));
|
|
@@ -112,10 +112,10 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, isExternal
|
|
|
112
112
|
setProp(action, '$flatAnnotations', flatAnnos);
|
|
113
113
|
|
|
114
114
|
forEachMemberRecursively(action, (member, memberName, prop, path, _parent) => {
|
|
115
|
-
const exprAnnos = Object.keys(member).filter(pn =>
|
|
115
|
+
const exprAnnos = Object.keys(member).filter(pn => pn[0] === '@');
|
|
116
116
|
exprAnnos.forEach((pn) => {
|
|
117
117
|
refCheck.anno = pn;
|
|
118
|
-
|
|
118
|
+
transformAnnotationExpression(member, pn, [ markBindingParam, refCheck, refFlattener ], path);
|
|
119
119
|
adaptRefs.forEach(fn => fn(true, 1, (parent) => parent.$bparam));
|
|
120
120
|
adaptRefs.length = 0;
|
|
121
121
|
});
|
|
@@ -193,7 +193,7 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, isExternal
|
|
|
193
193
|
};
|
|
194
194
|
// TODO: copy only those expression annotations that have no path into unreachable subtree, starting
|
|
195
195
|
// of typePathRoot (which could be some completely different path)
|
|
196
|
-
const exprAnnoNames = copyAnnotations(elt, flatElt, false, excludes).filter(pn =>
|
|
196
|
+
const exprAnnoNames = copyAnnotations(elt, flatElt, false, excludes).filter(pn => pn[0] === '@');
|
|
197
197
|
flattenAndPrefixExprPaths(flatElt, exprAnnoNames, elt.$path, rootPrefix, typeIdx);
|
|
198
198
|
// Copy selected type properties
|
|
199
199
|
['key', 'virtual', 'masked', 'viaAll', 'localized'].forEach(p => {
|
|
@@ -217,7 +217,7 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, isExternal
|
|
|
217
217
|
const [ nonAnnoProps, exprAnnoProps ] = Object.keys(flatElt).reduce((acc, pn) => {
|
|
218
218
|
if (pn[0] !== '@' && pn !== 'value')
|
|
219
219
|
acc[0].push(pn);
|
|
220
|
-
|
|
220
|
+
else
|
|
221
221
|
acc[1].push(pn);
|
|
222
222
|
return acc;
|
|
223
223
|
}, [[],[]]);
|
|
@@ -326,9 +326,8 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, isExternal
|
|
|
326
326
|
return `${head}`;
|
|
327
327
|
})();
|
|
328
328
|
|
|
329
|
-
let refChanged = false;
|
|
330
329
|
const absolutifier = {
|
|
331
|
-
ref : (parent, prop, xpr) => {
|
|
330
|
+
ref : (parent, prop, xpr, _path, _p, _ppn, ctx) => {
|
|
332
331
|
const head = xpr[0].id || xpr[0];
|
|
333
332
|
let isPrefixed = false;
|
|
334
333
|
if(!isMagicVariable(head)) {
|
|
@@ -365,20 +364,27 @@ function allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, isExternal
|
|
|
365
364
|
parent[prop].unshift('$self');
|
|
366
365
|
}
|
|
367
366
|
}
|
|
368
|
-
if(isPrefixed)
|
|
369
|
-
|
|
367
|
+
if(isPrefixed && ctx?.annoExpr?.['=']) {
|
|
368
|
+
ctx.annoExpr['='] = true;
|
|
369
|
+
}
|
|
370
370
|
}
|
|
371
371
|
}
|
|
372
|
+
|
|
373
|
+
refFlattener.$fnArgs = [ refParentIsItems ];
|
|
372
374
|
propNames.forEach(pn => {
|
|
373
|
-
refChanged = false;
|
|
374
375
|
refCheck.anno = pn;
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
376
|
+
if(pn[0] === '@') {
|
|
377
|
+
transformAnnotationExpression(carrier, pn, [ refCheck, refFlattener ], csnPath);
|
|
378
|
+
adaptRefs.forEach(fn => fn(refParentIsItems));
|
|
379
|
+
adaptRefs.length = 0;
|
|
380
|
+
transformAnnotationExpression(carrier, pn, absolutifier, csnPath);
|
|
381
|
+
}
|
|
382
|
+
if(pn === 'value') {
|
|
383
|
+
transformExpression(carrier, pn, [ refCheck, refFlattener ], csnPath);
|
|
384
|
+
adaptRefs.forEach(fn => fn(refParentIsItems));
|
|
385
|
+
adaptRefs.length = 0;
|
|
386
|
+
transformExpression(carrier, pn, absolutifier, csnPath);
|
|
387
|
+
}
|
|
382
388
|
});
|
|
383
389
|
}
|
|
384
390
|
|
|
@@ -454,14 +460,10 @@ function flattenAllStructStepsInRefs( csn, refFlattener, adaptRefs, inspectRef,
|
|
|
454
460
|
typeNames.forEach(tn => {
|
|
455
461
|
forEachMemberRecursively(csn.definitions[tn], (member, memberName, prop, csnPath) => {
|
|
456
462
|
Object.keys(member).filter(pn => pn[0] === '@').forEach(pn => {
|
|
457
|
-
let refChanged = false;
|
|
458
463
|
refCheck.anno = pn;
|
|
459
|
-
|
|
460
|
-
adaptRefs.forEach(fn =>
|
|
461
|
-
if (fn(true, 1)) refChanged = true });
|
|
464
|
+
transformAnnotationExpression(member, pn, [ refCheck, refFlattener ], csnPath);
|
|
465
|
+
adaptRefs.forEach(fn => fn(true, 1));
|
|
462
466
|
adaptRefs.length = 0;
|
|
463
|
-
if(refChanged && member[pn]['='])
|
|
464
|
-
member[pn]['='] = true;
|
|
465
467
|
});
|
|
466
468
|
}, [ 'definitions', tn ]);
|
|
467
469
|
})
|
|
@@ -488,8 +490,7 @@ function getStructRefFlatteningTransformer(csn, inspectRef, effectiveType, optio
|
|
|
488
490
|
}
|
|
489
491
|
const adaptRefs = [];
|
|
490
492
|
const transformer = {
|
|
491
|
-
ref: (parent,
|
|
492
|
-
let refChanged = false;
|
|
493
|
+
ref: (parent, _prop, ref, path, _p, _ppn, ctx) => {
|
|
493
494
|
const { links, art, scope } = inspectRef(path);
|
|
494
495
|
const resolvedLinkTypes = resolveLinkTypes(links);
|
|
495
496
|
setProp(parent, '$path', [ ...path ]);
|
|
@@ -502,9 +503,10 @@ function getStructRefFlatteningTransformer(csn, inspectRef, effectiveType, optio
|
|
|
502
503
|
// full path into target, uncomment this line and
|
|
503
504
|
// comment/remove setProp in expansion.js
|
|
504
505
|
// setProp(parent, '$structRef', parent.ref);
|
|
505
|
-
[
|
|
506
|
+
const [ newRef, refChanged ] = flattenStructStepsInRef(ref,
|
|
506
507
|
scopedPath, links, scope, resolvedLinkTypes,
|
|
507
508
|
suspend, suspendPos, parent.$bparam);
|
|
509
|
+
parent.ref = newRef;
|
|
508
510
|
resolved.set(parent, { links, art, scope });
|
|
509
511
|
// Explicitly set implicit alias for things that are now flattened - but only in columns
|
|
510
512
|
// TODO: Can this be done elegantly during expand phase already?
|
|
@@ -546,8 +548,17 @@ function getStructRefFlatteningTransformer(csn, inspectRef, effectiveType, optio
|
|
|
546
548
|
&& typeof path[path.length - 1] === 'number';
|
|
547
549
|
}
|
|
548
550
|
};
|
|
551
|
+
|
|
549
552
|
// adapt queries later
|
|
550
|
-
|
|
553
|
+
if(ctx?.annoExpr?.['=']) {
|
|
554
|
+
const annoExpr = ctx.annoExpr;
|
|
555
|
+
adaptRefs.push((...args) => {
|
|
556
|
+
if(fn(...args))
|
|
557
|
+
annoExpr['='] = true;
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
else
|
|
561
|
+
adaptRefs.push(fn);
|
|
551
562
|
},
|
|
552
563
|
}
|
|
553
564
|
|
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
const { setProp, isBetaEnabled } = require('../../base/model');
|
|
4
4
|
const {
|
|
5
|
-
|
|
5
|
+
transformAnnotationExpression,
|
|
6
6
|
forEachDefinition,
|
|
7
7
|
forEachGeneric,
|
|
8
8
|
forEachMemberRecursively,
|
|
9
|
-
findAnnotationExpression,
|
|
10
9
|
} = require('../../model/csnUtils');
|
|
11
10
|
const { isBuiltinType } = require('../../base/builtins');
|
|
12
11
|
const { isArtifactInSomeService, isArtifactInService } = require('./utils');
|
|
@@ -224,9 +223,9 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, e
|
|
|
224
223
|
const usingPositionStr = f($path2path(location));
|
|
225
224
|
const eltRootPath = $path2path(elt.$path);
|
|
226
225
|
|
|
227
|
-
Object.keys(elt).filter(pn => pn[0] === '@'
|
|
228
|
-
|
|
229
|
-
ref: (parent, prop, xpr, csnPath) => {
|
|
226
|
+
Object.keys(elt).filter(pn => pn[0] === '@').forEach(anno => {
|
|
227
|
+
transformAnnotationExpression(elt, anno, {
|
|
228
|
+
ref: (parent, prop, xpr, csnPath, _p, _ppn, ctx) => {
|
|
230
229
|
let prefixMatch = true;
|
|
231
230
|
const head = xpr[0].id || xpr[0];
|
|
232
231
|
if (head === '$self') {
|
|
@@ -238,10 +237,12 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, e
|
|
|
238
237
|
parent[prop] = [ ...xpr.slice(eltRootPath.length-1)];
|
|
239
238
|
else
|
|
240
239
|
parent[prop] = [ '$self', ...xpr.slice(typeRefRootPath.length)];
|
|
240
|
+
if(ctx?.annoExpr?.['='])
|
|
241
|
+
ctx.annoExpr['='] = true;
|
|
241
242
|
}
|
|
242
243
|
else {
|
|
243
244
|
error('odata-anno-xpr-ref', csnPath,
|
|
244
|
-
{ anno
|
|
245
|
+
{ anno, elemref: xpr.join('.'), name: usingPositionStr, code: typeRefStr });
|
|
245
246
|
}
|
|
246
247
|
}
|
|
247
248
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sap/cds-compiler",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"description": "CDS (Core Data Services) compiler and backends",
|
|
5
5
|
"homepage": "https://cap.cloud.sap/",
|
|
6
6
|
"author": "SAP SE (https://www.sap.com)",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"types": "lib/main.d.ts",
|
|
16
16
|
"scripts": {
|
|
17
17
|
"download": "node scripts/downloadANTLR.js",
|
|
18
|
-
"gen": "node ./scripts/build.js && node scripts/genGrammarChecksum.js",
|
|
18
|
+
"gen": "node ./scripts/build.js && node scripts/genGrammarChecksum.js && node ./redepage/bin/redepage --pretty --compile lib/gen/CdlParser.js --copy-base-parser lib/parsers/CdlGrammar.g4",
|
|
19
19
|
"xmakeAfterInstall": "npm run gen",
|
|
20
20
|
"xmakePrepareRelease": "echo \"$(node scripts/stripReadme.js README.md)\" > README.md && node scripts/assertSnapshotVersioning.js && node scripts/assertChangelog.js && node scripts/cleanup.js --remove-dev",
|
|
21
21
|
"test": "npm run test:piper",
|
|
@@ -31,14 +31,15 @@ view View as select from
|
|
|
31
31
|
};
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
Entity `Target` exists more than once in `View
|
|
35
|
-
happens through the *direct* sources in the
|
|
34
|
+
Entity `Target` exists more than once in `View` under different table aliases.
|
|
35
|
+
In the previous example, this happens through the *direct* sources in the
|
|
36
|
+
select clause.
|
|
36
37
|
Because the original target exists twice in the redirected target, the compiler
|
|
37
38
|
isn’t able to correctly resolve the redirection due to ambiguities.
|
|
38
39
|
|
|
39
40
|
This can also happen through *indirect* sources. For example if entity `Main`
|
|
40
|
-
were to include `Target
|
|
41
|
-
to trigger this error.
|
|
41
|
+
were to include `Target`, then selecting from `Target` just once would be
|
|
42
|
+
enough to trigger this error.
|
|
42
43
|
|
|
43
44
|
## How to Fix
|
|
44
45
|
|