@sap/cds-compiler 3.6.2 → 3.8.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 (89) hide show
  1. package/CHANGELOG.md +109 -1
  2. package/README.md +3 -0
  3. package/bin/cdsc.js +12 -5
  4. package/doc/CHANGELOG_ARCHIVE.md +6 -6
  5. package/doc/CHANGELOG_BETA.md +35 -2
  6. package/doc/CHANGELOG_DEPRECATED.md +2 -2
  7. package/doc/DeprecatedOptions_v2.md +1 -1
  8. package/doc/NameResolution.md +1 -1
  9. package/lib/api/main.js +63 -23
  10. package/lib/api/options.js +1 -0
  11. package/lib/api/validate.js +5 -0
  12. package/lib/base/dictionaries.js +15 -3
  13. package/lib/base/keywords.js +2 -0
  14. package/lib/base/message-registry.js +120 -34
  15. package/lib/base/messages.js +51 -27
  16. package/lib/base/model.js +4 -2
  17. package/lib/base/shuffle.js +2 -1
  18. package/lib/checks/arrayOfs.js +1 -1
  19. package/lib/checks/defaultValues.js +1 -1
  20. package/lib/checks/elements.js +29 -1
  21. package/lib/checks/{emptyOrOnlyVirtual.js → hasPersistedElements.js} +10 -6
  22. package/lib/checks/invalidTarget.js +1 -1
  23. package/lib/checks/nonexpandableStructured.js +1 -1
  24. package/lib/checks/onConditions.js +15 -9
  25. package/lib/checks/sql-snippets.js +2 -2
  26. package/lib/checks/types.js +5 -1
  27. package/lib/checks/validator.js +7 -3
  28. package/lib/compiler/assert-consistency.js +42 -26
  29. package/lib/compiler/base.js +50 -4
  30. package/lib/compiler/builtins.js +17 -8
  31. package/lib/compiler/checks.js +241 -246
  32. package/lib/compiler/define.js +113 -146
  33. package/lib/compiler/extend.js +889 -383
  34. package/lib/compiler/finalize-parse-cdl.js +5 -58
  35. package/lib/compiler/index.js +1 -1
  36. package/lib/compiler/kick-start.js +7 -8
  37. package/lib/compiler/populate.js +297 -293
  38. package/lib/compiler/propagator.js +27 -18
  39. package/lib/compiler/resolve.js +146 -463
  40. package/lib/compiler/shared.js +36 -79
  41. package/lib/compiler/tweak-assocs.js +30 -28
  42. package/lib/compiler/utils.js +31 -5
  43. package/lib/edm/annotations/genericTranslation.js +131 -59
  44. package/lib/edm/annotations/preprocessAnnotations.js +3 -0
  45. package/lib/edm/csn2edm.js +22 -5
  46. package/lib/edm/edm.js +6 -4
  47. package/lib/edm/edmAnnoPreprocessor.js +1 -0
  48. package/lib/edm/edmPreprocessor.js +42 -26
  49. package/lib/gen/Dictionary.json +38 -2
  50. package/lib/gen/language.checksum +1 -1
  51. package/lib/gen/language.interp +3 -1
  52. package/lib/gen/languageLexer.js +1 -1
  53. package/lib/gen/languageParser.js +4828 -4472
  54. package/lib/inspect/inspectPropagation.js +20 -34
  55. package/lib/json/from-csn.js +140 -44
  56. package/lib/json/to-csn.js +114 -122
  57. package/lib/language/errorStrategy.js +2 -0
  58. package/lib/language/genericAntlrParser.js +156 -36
  59. package/lib/language/language.g4 +100 -58
  60. package/lib/language/textUtils.js +13 -0
  61. package/lib/main.d.ts +43 -3
  62. package/lib/main.js +4 -2
  63. package/lib/model/csnRefs.js +15 -3
  64. package/lib/model/csnUtils.js +12 -74
  65. package/lib/model/revealInternalProperties.js +4 -2
  66. package/lib/modelCompare/compare.js +2 -1
  67. package/lib/optionProcessor.js +3 -0
  68. package/lib/render/manageConstraints.js +5 -2
  69. package/lib/render/toCdl.js +216 -104
  70. package/lib/render/toHdbcds.js +2 -9
  71. package/lib/render/toRename.js +14 -51
  72. package/lib/render/toSql.js +4 -3
  73. package/lib/render/utils/common.js +9 -5
  74. package/lib/transform/braceExpression.js +6 -0
  75. package/lib/transform/db/assertUnique.js +2 -1
  76. package/lib/transform/db/expansion.js +2 -0
  77. package/lib/transform/db/flattening.js +37 -36
  78. package/lib/transform/db/rewriteCalculatedElements.js +600 -0
  79. package/lib/transform/db/transformExists.js +4 -0
  80. package/lib/transform/db/views.js +40 -37
  81. package/lib/transform/forOdataNew.js +20 -15
  82. package/lib/transform/forRelationalDB.js +58 -41
  83. package/lib/transform/odata/typesExposure.js +50 -15
  84. package/lib/transform/parseExpr.js +16 -8
  85. package/lib/transform/transformUtilsNew.js +42 -14
  86. package/lib/transform/translateAssocsToJoins.js +60 -37
  87. package/lib/transform/universalCsn/coreComputed.js +15 -7
  88. package/lib/transform/universalCsn/universalCsnEnricher.js +4 -4
  89. package/package.json +2 -1
@@ -13,8 +13,7 @@
13
13
 
14
14
  'use strict';
15
15
 
16
- const { dictAddArray } = require('../base/dictionaries');
17
- const { forEachGeneric, forEachMember } = require('../base/model');
16
+ const { forEachGeneric } = require('../base/model');
18
17
  const { setLink, setArtifactLink } = require('./utils');
19
18
 
20
19
 
@@ -30,19 +29,19 @@ function finalizeParseCdl( model ) {
30
29
  resolveUncheckedPath,
31
30
  resolveTypeArgumentsUnchecked,
32
31
  initMembers,
33
- extensionsDict,
34
32
  } = model.$functions;
35
33
 
36
34
  resolveTypesAndExtensionsForParseCdl();
37
35
  return;
38
36
 
39
37
  function resolveTypesAndExtensionsForParseCdl() {
38
+ const late = model.$lateExtensions;
40
39
  const extensions = [];
41
40
 
42
- for (const name in extensionsDict) {
43
- for (const ext of extensionsDict[name]) {
41
+ // TODO: why not just use the extensions as they are from the first source?
42
+ for (const name in late) {
43
+ for (const ext of late[name]._extensions) {
44
44
  ext.name.absolute = resolveUncheckedPath( ext.name, 'extend', ext );
45
- mergeAnnotatesForSameArtifact( ext ); // TODO: should not be necessary anymore
46
45
  // Initialize members and define annotations in sub-elements.
47
46
  initMembers( ext, ext, ext._block, true );
48
47
  extensions.push( ext );
@@ -96,8 +95,6 @@ function finalizeParseCdl( model ) {
96
95
 
97
96
  if (artifact.from) {
98
97
  const { from } = artifact;
99
- // Note: `_from` only contains sources necessary for calculating elements,
100
- // not e.g. those from the `where exists` clause.
101
98
  resolveUncheckedPath(from, 'from', main);
102
99
  resolveTypesForParseCdl(from, main);
103
100
  }
@@ -108,11 +105,6 @@ function finalizeParseCdl( model ) {
108
105
  if (parseCdlSpeciallyHandledXsnProps.includes(prop) || parseCdlIgnoredXsnProps.includes(prop))
109
106
  continue;
110
107
 
111
- // define.js (and initMembers()) initializes annotations. If there is a duplicate, the
112
- // annotation is an array in XSN.
113
- if (prop[0] === '@' && Array.isArray(artifact[prop]))
114
- chooseAndReportDuplicateAnnotation(artifact, prop);
115
-
116
108
  if (artifact[prop] && Object.getPrototypeOf(artifact[prop]) === null)
117
109
  // Dictionary in XSN
118
110
  forEachGeneric(artifact, prop, art => resolveTypesForParseCdl(art, art));
@@ -172,12 +164,10 @@ function finalizeParseCdl( model ) {
172
164
  const name = resolveUncheckedPath( artWithType.type, 'type', user );
173
165
  const type = name && model.definitions[name] || { name: { absolute: name } };
174
166
  resolveTypeArgumentsUnchecked( artWithType, type, user );
175
- return;
176
167
  }
177
168
  else if (!user._main) {
178
169
  error( 'ref-undefined-typeof', [ artWithType.type.location, user ], {},
179
170
  'Current artifact has no element to refer to as type' );
180
- return;
181
171
  }
182
172
  else if (root.id === '$self' || root.id === '$projection') {
183
173
  setArtifactLink( root, user._main );
@@ -206,49 +196,6 @@ function finalizeParseCdl( model ) {
206
196
  setArtifactLink( root, fake );
207
197
  }
208
198
  }
209
-
210
- function chooseAndReportDuplicateAnnotation( artifact, annoName ) {
211
- for (const anno of artifact[annoName])
212
- message( 'anno-duplicate', [ anno.name.location, artifact ], { anno: annoName } );
213
-
214
- // Choose any annotation, doesn't matter because of the error above.
215
- artifact[annoName] = artifact[annoName][0];
216
- }
217
-
218
- /**
219
- * For duplicate entries in `annotate {}` blocks, we de-duplicate the entries and merge them.
220
- * Since it is allowed in "normal" compilations to have e.g.
221
- * `annotate E with { @anno1 id, @anno2 id }`.
222
- *
223
- * @param {object} ext
224
- */
225
- function mergeAnnotatesForSameArtifact( ext ) {
226
- if (!ext || typeof ext !== 'object')
227
- return;
228
-
229
- forEachMember(ext, sub => mergeAnnotatesForSameArtifact(sub));
230
-
231
- // do not do a complex merge:
232
- if (isComplexExtension( ext ) ||
233
- !Array.isArray( ext.$duplicates ) || ext.$duplicates.some( isComplexExtension ))
234
- return;
235
- for (const dup of ext.$duplicates) {
236
- for (const prop in dup) {
237
- if (prop.charAt(0) === '@')
238
- dictAddArray( ext, prop, dup[prop] );
239
- }
240
- }
241
- delete ext.$duplicates;
242
- }
243
- }
244
-
245
- /**
246
- * We only de-duplicate an extend/annotate `ext` in function
247
- * mergeAnnotatesForSameArtifact() if the extend/annotate is simple, i.e. has
248
- * no members like elements.
249
- */
250
- function isComplexExtension( ext ) {
251
- return ext.kind !== 'annotate' || ext.elements || ext.parameters || ext.actions;
252
199
  }
253
200
 
254
201
  module.exports = finalizeParseCdl;
@@ -15,7 +15,7 @@
15
15
  'use strict';
16
16
 
17
17
  const { resolveModule, resolveModuleSync } = require('../utils/moduleResolve');
18
- const parseLanguage = require('../language/antlrParser');
18
+ const parseLanguage = require('../language/antlrParser'); // TODO: should we do some lazyload here?
19
19
  const parseCsn = require('../json/from-csn');
20
20
 
21
21
  const assertConsistency = require('./assert-consistency');
@@ -31,9 +31,9 @@ function kickStart( model ) {
31
31
  */
32
32
  function setAncestorsAndService( name ) {
33
33
  const art = model.definitions[name];
34
- if (!('_parent' in art))
34
+ if (art._parent === undefined)
35
35
  return; // nothing to do for builtins and redefinitions
36
- if (art._from && !('_ancestors' in art))
36
+ if (art.query && art._ancestors === undefined)
37
37
  setProjectionAncestors( art );
38
38
 
39
39
  let parent = art._parent;
@@ -72,13 +72,12 @@ function kickStart( model ) {
72
72
  // no need to set preferredRedirectionTarget in the while loop as we would
73
73
  // use the projection having @cds.redirection.target anyhow instead of
74
74
  // `art` anyway (if we do the no-x-service-implicit-redirection TODO above)
75
- while (art && !('_ancestors' in art) &&
76
- art._from && art._from.length === 1 &&
77
- (preferredRedirectionTarget || !annotationIsFalse( art['@cds.redirection.target'] ) ) &&
78
- art.query.op && art.query.op.val === 'SELECT') {
75
+ while (art?.query?.from?.path && // direct select with one source
76
+ art._ancestors !== 0 && // prevent inf-loop
77
+ (preferredRedirectionTarget || !annotationIsFalse( art['@cds.redirection.target'] ) )) {
79
78
  chain.push( art );
80
- setLink( art, '_ancestors', null ); // avoid infloop with cyclic from
81
- const name = resolveUncheckedPath( art._from[0], 'include', art ); // TODO: 'include'?
79
+ setLink( art, '_ancestors', 0 ); // avoid infloop with cyclic from
80
+ const name = resolveUncheckedPath( art.query.from, 'include', art ); // TODO: 'include'?
82
81
  art = name && model.definitions[name];
83
82
  if (autoexposed)
84
83
  break; // only direct projection for auto-exposed