@sap/cds-compiler 4.8.0 → 4.9.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.
Files changed (95) hide show
  1. package/CHANGELOG.md +38 -4
  2. package/bin/cds_remove_invalid_whitespace.js +135 -0
  3. package/bin/cds_update_annotations.js +180 -0
  4. package/bin/cds_update_identifiers.js +3 -4
  5. package/bin/cdsc.js +30 -17
  6. package/doc/CHANGELOG_BETA.md +19 -0
  7. package/lib/api/main.js +59 -24
  8. package/lib/api/options.js +12 -1
  9. package/lib/api/validate.js +1 -5
  10. package/lib/base/builtins.js +27 -0
  11. package/lib/base/message-registry.js +38 -21
  12. package/lib/base/messages.js +51 -20
  13. package/lib/base/model.js +4 -5
  14. package/lib/checks/actionsFunctions.js +2 -2
  15. package/lib/checks/annotationsOData.js +3 -0
  16. package/lib/checks/defaultValues.js +5 -2
  17. package/lib/checks/queryNoDbArtifacts.js +3 -2
  18. package/lib/checks/validator.js +2 -34
  19. package/lib/compiler/assert-consistency.js +10 -3
  20. package/lib/compiler/checks.js +44 -18
  21. package/lib/compiler/define.js +38 -30
  22. package/lib/compiler/extend.js +33 -10
  23. package/lib/compiler/index.js +0 -1
  24. package/lib/compiler/lsp-api.js +5 -0
  25. package/lib/compiler/populate.js +0 -2
  26. package/lib/compiler/propagator.js +23 -19
  27. package/lib/compiler/resolve.js +48 -29
  28. package/lib/compiler/shared.js +60 -20
  29. package/lib/compiler/tweak-assocs.js +72 -116
  30. package/lib/compiler/xpr-rewrite.js +762 -0
  31. package/lib/edm/annotations/edmJson.js +24 -7
  32. package/lib/edm/annotations/genericTranslation.js +81 -61
  33. package/lib/edm/edm.js +4 -4
  34. package/lib/edm/edmInboundChecks.js +33 -0
  35. package/lib/edm/edmPreprocessor.js +9 -6
  36. package/lib/gen/Dictionary.json +129 -14
  37. package/lib/gen/language.checksum +1 -1
  38. package/lib/gen/language.interp +1 -1
  39. package/lib/gen/languageParser.js +1523 -1518
  40. package/lib/json/from-csn.js +13 -4
  41. package/lib/json/to-csn.js +12 -12
  42. package/lib/language/genericAntlrParser.js +14 -6
  43. package/lib/main.d.ts +67 -14
  44. package/lib/main.js +1 -0
  45. package/lib/model/cloneCsn.js +6 -3
  46. package/lib/model/csnRefs.js +23 -11
  47. package/lib/model/csnUtils.js +13 -7
  48. package/lib/model/enrichCsn.js +3 -1
  49. package/lib/model/revealInternalProperties.js +2 -1
  50. package/lib/model/sortViews.js +14 -6
  51. package/lib/modelCompare/compare.js +33 -34
  52. package/lib/optionProcessor.js +27 -2
  53. package/lib/render/DuplicateChecker.js +6 -6
  54. package/lib/render/manageConstraints.js +1 -0
  55. package/lib/render/toCdl.js +3 -1
  56. package/lib/transform/db/applyTransformations.js +33 -0
  57. package/lib/transform/db/constraints.js +75 -28
  58. package/lib/transform/db/expansion.js +8 -3
  59. package/lib/transform/db/flattening.js +2 -2
  60. package/lib/transform/db/groupByOrderBy.js +2 -2
  61. package/lib/transform/db/temporal.js +6 -3
  62. package/lib/transform/db/transformExists.js +2 -2
  63. package/lib/transform/effective/annotations.js +194 -0
  64. package/lib/transform/effective/main.js +6 -8
  65. package/lib/transform/effective/misc.js +31 -10
  66. package/lib/transform/forOdata.js +23 -7
  67. package/lib/transform/forRelationalDB.js +3 -3
  68. package/lib/transform/localized.js +7 -6
  69. package/lib/transform/odata/flattening.js +221 -124
  70. package/lib/transform/odata/toFinalBaseType.js +1 -1
  71. package/lib/transform/odata/typesExposure.js +15 -12
  72. package/lib/transform/parseExpr.js +4 -4
  73. package/lib/transform/transformUtils.js +47 -42
  74. package/lib/transform/translateAssocsToJoins.js +47 -47
  75. package/lib/transform/universalCsn/universalCsnEnricher.js +16 -19
  76. package/package.json +1 -1
  77. package/share/messages/anno-missing-rewrite.md +45 -0
  78. package/share/messages/message-explanations.json +1 -0
  79. package/bin/.eslintrc.json +0 -17
  80. package/lib/api/.eslintrc.json +0 -37
  81. package/lib/checks/.eslintrc.json +0 -31
  82. package/lib/compiler/.eslintrc.json +0 -8
  83. package/lib/edm/.eslintrc.json +0 -46
  84. package/lib/inspect/.eslintrc.json +0 -4
  85. package/lib/json/.eslintrc.json +0 -4
  86. package/lib/language/.eslintrc.json +0 -4
  87. package/lib/model/.eslintrc.json +0 -13
  88. package/lib/modelCompare/utils/.eslintrc.json +0 -22
  89. package/lib/render/.eslintrc.json +0 -22
  90. package/lib/transform/.eslintrc.json +0 -13
  91. package/lib/transform/db/.eslintrc.json +0 -41
  92. package/lib/transform/draft/.eslintrc.json +0 -4
  93. package/lib/transform/effective/.eslintrc.json +0 -4
  94. package/lib/transform/universalCsn/.eslintrc.json +0 -37
  95. package/lib/utils/.eslintrc.json +0 -7
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const {
4
- forEachDefinition, forEachMemberRecursively, getArtifactDatabaseNameOf, getElementDatabaseNameOf, applyTransformations,
4
+ getArtifactDatabaseNameOf, getElementDatabaseNameOf,
5
5
  } = require('../../model/csnUtils');
6
6
  /**
7
7
  * Attach @cds.persistence.name to all artifacts and "things".
@@ -9,17 +9,34 @@ const {
9
9
  * @param {CSN.Model} csn
10
10
  * @param {CSN.Options} options
11
11
  * @param {object} csnUtils
12
+ * @returns {object}
12
13
  */
13
14
  function attachPersistenceName( csn, options, csnUtils ) {
14
15
  const { addStringAnnotationTo } = csnUtils;
15
16
 
16
- forEachDefinition(csn, (artifact, artifactName) => {
17
- if (artifact.kind === 'entity') {
18
- addStringAnnotationTo('@cds.persistence.name', getArtifactDatabaseNameOf(artifactName, options.sqlMapping, csn, options.sqlDialect), artifact);
19
-
20
- forEachMemberRecursively(artifact, (member, memberName) => addStringAnnotationTo('@cds.persistence.name', getElementDatabaseNameOf(memberName, options.sqlMapping, options.sqlDialect), member), [ 'definitions', artifactName ]);
17
+ /**
18
+ *
19
+ * @param {object} parent
20
+ * @param {string} prop
21
+ * @param {object} dict
22
+ * @param {CSN.Path} path
23
+ */
24
+ function addToEachMember( parent, prop, dict, path ) {
25
+ const artifact = csn.definitions[path[1]];
26
+ if (artifact?.kind === 'entity') {
27
+ for (const memberName in dict)
28
+ addStringAnnotationTo('@cds.persistence.name', getElementDatabaseNameOf(memberName, options.sqlMapping, options.sqlDialect), dict[memberName]);
21
29
  }
22
- });
30
+ }
31
+
32
+ return {
33
+ kind: (parent, prop, kind, path) => {
34
+ if (kind === 'entity')
35
+ addStringAnnotationTo('@cds.persistence.name', getArtifactDatabaseNameOf(path[1], options.sqlMapping, csn, options.sqlDialect), parent);
36
+ },
37
+ elements: addToEachMember,
38
+ params: addToEachMember,
39
+ };
23
40
  }
24
41
 
25
42
  /**
@@ -42,10 +59,11 @@ function killProp( parent, prop ) {
42
59
  * - localized
43
60
  * @param {CSN.Model} csn
44
61
  * @param {CSN.Options} options
62
+ * @returns {object}
45
63
  * @todo Callback-like architecture and merge with persistence name?
46
64
  */
47
65
  function _removeDefinitionsAndProperties( csn, options ) {
48
- const killers = {
66
+ const transformers = {
49
67
  $ignore: (a, b, c, path, parentParent) => {
50
68
  const tail = path[path.length - 1];
51
69
  delete parentParent[tail];
@@ -74,13 +92,16 @@ function _removeDefinitionsAndProperties( csn, options ) {
74
92
  // Set when we remove .key from temporal things, used in localized.js
75
93
  $key: killProp,
76
94
  includes: killProp,
77
- localized: killProp,
78
95
  enum: killProp,
79
96
  keys: killProp,
80
97
  excluding: killProp, // * is resolved, so has no effect anymore
98
+ targetAspect: killProp,
81
99
  };
82
100
 
83
- applyTransformations(csn, killers, [], { skipIgnore: false });
101
+ if (!options.keepLocalized)
102
+ transformers.localized = killProp;
103
+
104
+ return transformers;
84
105
  }
85
106
 
86
107
 
@@ -73,7 +73,7 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
73
73
  timetrace.start('OData transformation');
74
74
 
75
75
  // copy the model as we don't want to change the input model
76
- let csn = cloneFullCsn(inputModel, options);
76
+ const csn = cloneFullCsn(inputModel, options);
77
77
  messageFunctions.setModel(csn);
78
78
 
79
79
  const { message, error, warning, info, throwWithAnyError } = messageFunctions;
@@ -184,14 +184,19 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
184
184
  expandStructsInExpression(csn, { skipArtifact: isExternalServiceMember, drillRef: true });
185
185
 
186
186
  if (!structuredOData) {
187
- expansion.expandStructureReferences(csn, options, '_', { error, info, throwWithAnyError }, csnUtils, { skipArtifact: isExternalServiceMember });
187
+ expansion.expandStructureReferences(csn, options, '_',
188
+ { error, info, throwWithAnyError }, csnUtils,
189
+ { skipArtifact: isExternalServiceMember });
188
190
  const resolved = new WeakMap();
189
191
 
190
192
  const { inspectRef, effectiveType } = csnRefs(csn);
191
- const { adaptRefs, transformer: refFlattener } = flattening.getStructRefFlatteningTransformer(csn, inspectRef, effectiveType, options, resolved, '_');
193
+ const { adaptRefs, transformer: refFlattener } =
194
+ flattening.getStructRefFlatteningTransformer(csn, inspectRef, effectiveType, options, resolved, '_');
192
195
 
193
- flattening.allInOneFlattening(csn, refFlattener, adaptRefs, inspectRef, isExternalServiceMember, error, csnUtils, options);
194
- flattening.flattenAllStructStepsInRefs(csn, refFlattener, adaptRefs, inspectRef, effectiveType, csnUtils, error, options,
196
+ flattening.allInOneFlattening(csn, refFlattener, adaptRefs,
197
+ inspectRef, isExternalServiceMember, error, csnUtils, options);
198
+ flattening.flattenAllStructStepsInRefs(csn, refFlattener, adaptRefs,
199
+ inspectRef, effectiveType, csnUtils, error, options,
195
200
  { //skip: ['action', 'aspect', 'event', 'function', 'type'],
196
201
  skipArtifact: isExternalServiceMember,
197
202
  });
@@ -208,12 +213,22 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
208
213
  def[an] = av;
209
214
  })
210
215
  }
216
+ if(def.actions) {
217
+ Object.values(def.actions).forEach((action) => {
218
+ if(action.$flatAnnotations) {
219
+ Object.entries(action.$flatAnnotations).forEach(([an, av]) => {
220
+ action[an] = av;
221
+ });
222
+ }
223
+ });
224
+ }
211
225
  });
212
226
  }
213
227
 
214
228
  // TODO: add the generated foreign keys to the columns when we are in a view
215
229
  // see db/views.js::addForeignKeysToColumns
216
- flattening.handleManagedAssociationsAndCreateForeignKeys(csn, options, messageFunctions, '_', !structuredOData, csnUtils,{ skipArtifact: isExternalServiceMember });
230
+ flattening.handleManagedAssociationsAndCreateForeignKeys(csn, options, messageFunctions, '_',
231
+ !structuredOData, csnUtils,{ skipArtifact: isExternalServiceMember });
217
232
 
218
233
  // Allow using managed associations as steps in on-conditions to access their fks
219
234
  // To be done after handleManagedAssociationsAndCreateForeignKeys,
@@ -252,7 +267,8 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
252
267
  // Annotate artifacts with their DB names if requested.
253
268
  // Skip artifacts that have no DB equivalent anyway
254
269
  if (options.sqlMapping && !(def.kind in skipPersNameKinds))
255
- def['@cds.persistence.name'] = getArtifactDatabaseNameOf(defName, options.sqlMapping, csn, 'hana'); // hana to allow naming mode "hdbcds"
270
+ // hana to allow naming mode "hdbcds"
271
+ def['@cds.persistence.name'] = getArtifactDatabaseNameOf(defName, options.sqlMapping, csn, 'hana');
256
272
 
257
273
  forEachMemberRecursively(def, (member, memberName, propertyName) => {
258
274
  // Annotate elements, foreign keys, parameters, etc. with their DB names if requested
@@ -183,7 +183,7 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
183
183
  forEachDefinition(csn, [
184
184
  // (001) Add a temporal where condition to views where applicable before assoc2join
185
185
  // assoc2join eventually rewrites the table aliases
186
- temporal.getViewDecorator(csn, messageFunctions, csnUtils),
186
+ temporal.getViewDecorator(csn, messageFunctions, csnUtils, options),
187
187
  // check unique constraints - further processing is done in rewriteUniqueConstraints
188
188
  assertUnique.prepare(csn, options, messageFunctions)
189
189
  ]);
@@ -951,7 +951,7 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
951
951
  if (isFulltextIndex)
952
952
  error(null, path, { name: artName }, 'A fulltext index can\'t be defined on a structured element $(NAME)');
953
953
  // First, compute the name from the path, e.g ['s', 's1', 's2' ] will result in 'S_s1_s2' ...
954
- const refPath = flattenStructStepsInRef(val.ref, path);
954
+ const [ refPath ] = flattenStructStepsInRef(val.ref, path);
955
955
  // ... and take this as the prefix for all elements
956
956
  const flattenedElems = flattenStructuredElement(art, refPath, [], ['definitions', artName, 'elements']);
957
957
  Object.keys(flattenedElems).forEach((elem, i, elems) => {
@@ -967,7 +967,7 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
967
967
  }
968
968
  else {
969
969
  // The reference is not structured, so just replace it by a ref to the combined prefix path
970
- const refPath = flattenStructStepsInRef(val.ref, path);
970
+ const [ refPath ] = flattenStructStepsInRef(val.ref, path);
971
971
  flattenedIndex.push({ ref: refPath });
972
972
  }
973
973
  }
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { makeMessageFunction } = require('../base/messages');
4
- const { setProp, isDeprecatedEnabled} = require('../base/model');
4
+ const { setProp, isDeprecatedEnabled, isBetaEnabled} = require('../base/model');
5
5
  const { forEachKey } = require('../utils/objectUtils');
6
6
  const { cleanSymbols } = require('../base/cleanSymbols.js');
7
7
  const {
@@ -747,7 +747,7 @@ function copyLocation(target, source) {
747
747
  }
748
748
 
749
749
  /**
750
- * Copy @cds.persistence.exists/skip annotations from the source to
750
+ * Copy @cds.persistence.skip annotations from the source to
751
751
  * the target. Ignores existing annotations on the _target_.
752
752
  *
753
753
  * @param {CSN.Artifact} target
@@ -755,14 +755,15 @@ function copyLocation(target, source) {
755
755
  * @param {CSN.Options} options
756
756
  */
757
757
  function copyPersistenceAnnotations(target, source, options) {
758
- const doNotCopyExists = isDeprecatedEnabled( options, 'eagerPersistenceForGeneratedEntities' );
758
+ const copyExists = !isBetaEnabled(options, 'v5preview') &&
759
+ !isDeprecatedEnabled( options, 'eagerPersistenceForGeneratedEntities' );
759
760
  forEachKey(source, anno => {
760
761
  // Note:
761
- // Because `.exists` is copied to the convenience view, it could
762
+ // v3/v4: Because `.exists` is copied to the convenience view, it could
762
763
  // lead to some localization views referencing non-existing ones.
763
764
  // But that is the contract: User says that it already exists!
764
- // In v2, `.exists` was never copied.
765
- if (anno === annoPersistenceSkip || (!doNotCopyExists && anno === '@cds.persistence.exists'))
765
+ // v2/>=v5, `.exists` is never copied.
766
+ if (anno === annoPersistenceSkip || (copyExists && anno === '@cds.persistence.exists'))
766
767
  target[anno] = source[anno];
767
768
  });
768
769
  }