@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.
Files changed (51) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/bin/cdsc.js +2 -2
  3. package/bin/cdshi.js +24 -17
  4. package/bin/cdsse.js +17 -18
  5. package/lib/api/main.js +19 -2
  6. package/lib/api/options.js +4 -1
  7. package/lib/base/builtins.js +1 -0
  8. package/lib/base/message-registry.js +16 -3
  9. package/lib/base/model.js +0 -10
  10. package/lib/checks/actionsFunctions.js +0 -12
  11. package/lib/checks/structuredAnnoExpressions.js +10 -14
  12. package/lib/compiler/assert-consistency.js +19 -11
  13. package/lib/compiler/builtins.js +1 -1
  14. package/lib/compiler/define.js +3 -3
  15. package/lib/compiler/extend.js +5 -5
  16. package/lib/compiler/populate.js +9 -9
  17. package/lib/compiler/propagator.js +1 -0
  18. package/lib/compiler/resolve.js +29 -34
  19. package/lib/compiler/shared.js +7 -8
  20. package/lib/compiler/tweak-assocs.js +155 -64
  21. package/lib/compiler/utils.js +1 -1
  22. package/lib/compiler/xpr-rewrite.js +4 -3
  23. package/lib/edm/annotations/genericTranslation.js +13 -9
  24. package/lib/edm/csn2edm.js +26 -2
  25. package/lib/edm/edm.js +23 -8
  26. package/lib/edm/edmInboundChecks.js +5 -7
  27. package/lib/edm/edmPreprocessor.js +43 -30
  28. package/lib/gen/BaseParser.js +720 -0
  29. package/lib/gen/CdlParser.js +4421 -0
  30. package/lib/gen/language.checksum +1 -1
  31. package/lib/gen/language.interp +1 -1
  32. package/lib/gen/languageParser.js +4006 -4001
  33. package/lib/language/antlrParser.js +62 -0
  34. package/lib/language/genericAntlrParser.js +28 -0
  35. package/lib/model/csnUtils.js +2 -0
  36. package/lib/model/revealInternalProperties.js +2 -0
  37. package/lib/modelCompare/utils/filter.js +70 -42
  38. package/lib/optionProcessor.js +9 -3
  39. package/lib/parsers/AstBuildingParser.js +1172 -0
  40. package/lib/parsers/CdlGrammar.g4 +1940 -0
  41. package/lib/parsers/Lexer.js +239 -0
  42. package/lib/render/toCdl.js +23 -27
  43. package/lib/render/toSql.js +5 -5
  44. package/lib/transform/db/applyTransformations.js +54 -16
  45. package/lib/transform/draft/odata.js +10 -11
  46. package/lib/transform/effective/flattening.js +10 -14
  47. package/lib/transform/odata/flattening.js +42 -31
  48. package/lib/transform/odata/toFinalBaseType.js +7 -6
  49. package/lib/transform/universalCsn/universalCsnEnricher.js +1 -0
  50. package/package.json +2 -2
  51. 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, findAnnotationExpression } = require('../../model/csnUtils');
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 => findAnnotationExpression(elt, 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(an => findAnnotationExpression(def, an));
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(an => findAnnotationExpression(action, an));
103
+ const annoNames = copyAnnotations(action, flatAnnos).filter(pn => pn[0] === '@');
104
104
  annoNames.forEach((an) => {
105
105
  refCheck.anno = an;
106
- transformExpression(flatAnnos, an,
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 => findAnnotationExpression(member, pn));
115
+ const exprAnnos = Object.keys(member).filter(pn => pn[0] === '@');
116
116
  exprAnnos.forEach((pn) => {
117
117
  refCheck.anno = pn;
118
- transformExpression(member, pn, [ markBindingParam, refCheck, refFlattener ], path);
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 => findAnnotationExpression(flatElt, 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
- if (findAnnotationExpression(flatElt, pn) || pn === 'value')
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
- refChanged = isPrefixed;
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
- transformExpression(carrier, pn, [ refCheck, refFlattener ], csnPath);
376
- adaptRefs.forEach(fn =>
377
- { if( fn(refParentIsItems)) refChanged = true });
378
- adaptRefs.length = 0;
379
- transformExpression(carrier, pn, absolutifier, csnPath)
380
- if(refChanged && carrier[pn]['='])
381
- carrier[pn]['='] = true;
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
- transformExpression(member, pn, [ refCheck, refFlattener ], csnPath);
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, prop, ref, path) => {
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
- [ parent.ref, refChanged ] = flattenStructStepsInRef(ref,
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
- adaptRefs.push(fn);
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
- transformExpression,
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] === '@' && findAnnotationExpression(elt, pn)).forEach(xprAName => {
228
- transformExpression(elt, xprAName, {
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: xprAName, elemref: xpr.join('.'), name: usingPositionStr, code: typeRefStr });
245
+ { anno, elemref: xpr.join('.'), name: usingPositionStr, code: typeRefStr });
245
246
  }
246
247
  }
247
248
  },
@@ -54,6 +54,7 @@ module.exports = (csn, options) => {
54
54
  const ruleToFunction = {
55
55
  __proto__: null,
56
56
  never: skip,
57
+ onlyViaParent: skip, // TODO: not correct
57
58
  onlyViaArtifact,
58
59
  notWithPersistenceTable,
59
60
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds-compiler",
3
- "version": "5.1.2",
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`. In the previous example, this
35
- happens through the *direct* sources in the select clause.
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` then selecting from `Target` just once would be enough
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