@sap/cds-compiler 3.4.4 → 3.5.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 (129) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +1 -0
  3. package/bin/cds_update_identifiers.js +5 -5
  4. package/bin/cdsc.js +12 -12
  5. package/doc/CHANGELOG_ARCHIVE.md +1 -1
  6. package/doc/CHANGELOG_BETA.md +9 -1
  7. package/doc/CHANGELOG_DEPRECATED.md +2 -0
  8. package/lib/api/main.js +58 -59
  9. package/lib/api/options.js +4 -2
  10. package/lib/api/validate.js +2 -2
  11. package/lib/base/cleanSymbols.js +2 -3
  12. package/lib/base/dictionaries.js +6 -6
  13. package/lib/base/error.js +2 -2
  14. package/lib/base/keywords.js +6 -6
  15. package/lib/base/location.js +11 -12
  16. package/lib/base/message-registry.js +124 -28
  17. package/lib/base/messages.js +247 -179
  18. package/lib/base/model.js +14 -11
  19. package/lib/base/node-helpers.js +9 -10
  20. package/lib/base/optionProcessorHelper.js +138 -129
  21. package/lib/checks/actionsFunctions.js +5 -5
  22. package/lib/checks/annotationsOData.js +4 -4
  23. package/lib/checks/arrayOfs.js +1 -1
  24. package/lib/checks/cdsPersistence.js +1 -1
  25. package/lib/checks/checkForTypes.js +3 -3
  26. package/lib/checks/defaultValues.js +3 -3
  27. package/lib/checks/elements.js +7 -7
  28. package/lib/checks/emptyOrOnlyVirtual.js +2 -2
  29. package/lib/checks/foreignKeys.js +1 -1
  30. package/lib/checks/invalidTarget.js +4 -4
  31. package/lib/checks/managedInType.js +1 -1
  32. package/lib/checks/managedWithoutKeys.js +1 -1
  33. package/lib/checks/nonexpandableStructured.js +5 -3
  34. package/lib/checks/nullableKeys.js +1 -1
  35. package/lib/checks/onConditions.js +5 -6
  36. package/lib/checks/parameters.js +1 -1
  37. package/lib/checks/queryNoDbArtifacts.js +2 -2
  38. package/lib/checks/selectItems.js +4 -4
  39. package/lib/checks/sql-snippets.js +4 -4
  40. package/lib/checks/types.js +7 -7
  41. package/lib/checks/utils.js +4 -4
  42. package/lib/checks/validator.js +16 -13
  43. package/lib/compiler/.eslintrc.json +1 -1
  44. package/lib/compiler/assert-consistency.js +0 -1
  45. package/lib/compiler/builtins.js +1 -1
  46. package/lib/compiler/checks.js +73 -15
  47. package/lib/compiler/define.js +3 -7
  48. package/lib/compiler/extend.js +212 -32
  49. package/lib/compiler/finalize-parse-cdl.js +7 -2
  50. package/lib/compiler/index.js +17 -14
  51. package/lib/compiler/populate.js +2 -5
  52. package/lib/compiler/propagator.js +2 -0
  53. package/lib/compiler/shared.js +23 -12
  54. package/lib/compiler/tweak-assocs.js +5 -6
  55. package/lib/compiler/utils.js +6 -0
  56. package/lib/edm/annotations/genericTranslation.js +553 -319
  57. package/lib/edm/annotations/preprocessAnnotations.js +39 -35
  58. package/lib/edm/csn2edm.js +88 -75
  59. package/lib/edm/edm.js +17 -3
  60. package/lib/edm/edmAnnoPreprocessor.js +5 -5
  61. package/lib/edm/edmPreprocessor.js +106 -76
  62. package/lib/edm/edmUtils.js +41 -2
  63. package/lib/gen/Dictionary.json +34 -0
  64. package/lib/gen/language.checksum +1 -1
  65. package/lib/gen/language.interp +66 -63
  66. package/lib/gen/language.tokens +81 -81
  67. package/lib/gen/languageLexer.interp +4 -10
  68. package/lib/gen/languageLexer.js +854 -869
  69. package/lib/gen/languageLexer.tokens +79 -81
  70. package/lib/gen/languageParser.js +14360 -14146
  71. package/lib/inspect/inspectModelStatistics.js +2 -2
  72. package/lib/inspect/inspectPropagation.js +6 -6
  73. package/lib/inspect/inspectUtils.js +2 -2
  74. package/lib/json/from-csn.js +82 -40
  75. package/lib/json/to-csn.js +82 -157
  76. package/lib/language/.eslintrc.json +1 -4
  77. package/lib/language/genericAntlrParser.js +59 -38
  78. package/lib/language/language.g4 +1508 -1490
  79. package/lib/language/multiLineStringParser.js +1 -1
  80. package/lib/main.js +3 -3
  81. package/lib/model/csnUtils.js +130 -122
  82. package/lib/model/revealInternalProperties.js +1 -1
  83. package/lib/model/sortViews.js +4 -6
  84. package/lib/modelCompare/utils/filter.js +4 -3
  85. package/lib/optionProcessor.js +5 -0
  86. package/lib/render/DuplicateChecker.js +1 -1
  87. package/lib/render/manageConstraints.js +12 -12
  88. package/lib/render/toCdl.js +225 -159
  89. package/lib/render/toHdbcds.js +63 -63
  90. package/lib/render/toRename.js +5 -5
  91. package/lib/render/toSql.js +55 -65
  92. package/lib/render/utils/common.js +20 -37
  93. package/lib/render/utils/delta.js +3 -3
  94. package/lib/render/utils/sql.js +22 -6
  95. package/lib/render/utils/stringEscapes.js +3 -3
  96. package/lib/transform/db/applyTransformations.js +3 -3
  97. package/lib/transform/db/assertUnique.js +13 -12
  98. package/lib/transform/db/associations.js +5 -5
  99. package/lib/transform/db/cdsPersistence.js +10 -8
  100. package/lib/transform/db/constraints.js +14 -14
  101. package/lib/transform/db/expansion.js +20 -22
  102. package/lib/transform/db/flattening.js +24 -42
  103. package/lib/transform/db/groupByOrderBy.js +3 -3
  104. package/lib/transform/db/temporal.js +6 -6
  105. package/lib/transform/db/transformExists.js +23 -23
  106. package/lib/transform/db/views.js +16 -16
  107. package/lib/transform/draft/db.js +10 -10
  108. package/lib/transform/draft/odata.js +2 -2
  109. package/lib/transform/forOdataNew.js +12 -40
  110. package/lib/transform/forRelationalDB.js +17 -7
  111. package/lib/transform/localized.js +2 -2
  112. package/lib/transform/odata/toFinalBaseType.js +41 -27
  113. package/lib/transform/odata/typesExposure.js +106 -62
  114. package/lib/transform/parseExpr.js +209 -106
  115. package/lib/transform/transformUtilsNew.js +2 -2
  116. package/lib/transform/translateAssocsToJoins.js +24 -19
  117. package/lib/transform/universalCsn/coreComputed.js +10 -10
  118. package/lib/transform/universalCsn/universalCsnEnricher.js +26 -26
  119. package/lib/transform/universalCsn/utils.js +3 -3
  120. package/lib/utils/file.js +5 -5
  121. package/lib/utils/moduleResolve.js +13 -13
  122. package/lib/utils/objectUtils.js +6 -6
  123. package/lib/utils/term.js +5 -2
  124. package/lib/utils/timetrace.js +51 -24
  125. package/package.json +5 -7
  126. package/share/messages/check-proper-type-of.md +1 -1
  127. package/share/messages/message-explanations.json +1 -1
  128. package/share/messages/redirected-to-complex.md +4 -4
  129. package/share/messages/{syntax-expecting-integer.md → syntax-expecting-unsigned-int.md} +7 -4
@@ -18,7 +18,7 @@ const { ModelError } = require('../../base/error');
18
18
  *
19
19
  * @returns {string} SQL statement which can be used to create the referential constraint on the db.
20
20
  */
21
- function renderReferentialConstraint(constraint, indent, toUpperCase, csn, options, alterConstraint = false) {
21
+ function renderReferentialConstraint( constraint, indent, toUpperCase, csn, options, alterConstraint = false ) {
22
22
  let quoteId;
23
23
  // for to.hana we can't utilize the sql identifier utils
24
24
  if (options.transformation === 'hdbcds') {
@@ -29,7 +29,7 @@ function renderReferentialConstraint(constraint, indent, toUpperCase, csn, optio
29
29
  };
30
30
  }
31
31
  else {
32
- quoteId = getIdentifierUtils(options).quoteSqlId;
32
+ quoteId = getIdentifierUtils(csn, options).quoteSqlId;
33
33
  }
34
34
  if (toUpperCase) {
35
35
  constraint.identifier = constraint.identifier.toUpperCase();
@@ -81,8 +81,8 @@ function renderReferentialConstraint(constraint, indent, toUpperCase, csn, optio
81
81
  * @param {CSN.Options} options
82
82
  * @returns quoteSqlId and prepareIdentifier function
83
83
  */
84
- function getIdentifierUtils(options) {
85
- return { quoteSqlId, prepareIdentifier };
84
+ function getIdentifierUtils( csn, options ) {
85
+ return { quoteSqlId, prepareIdentifier, renderArtifactName };
86
86
  /**
87
87
  * Return 'name' with appropriate "-quotes.
88
88
  * Additionally perform the following conversions on 'name'
@@ -95,7 +95,7 @@ function getIdentifierUtils(options) {
95
95
  * @param {string} name Identifier to quote
96
96
  * @returns {string} Quoted identifier
97
97
  */
98
- function quoteSqlId(name) {
98
+ function quoteSqlId( name ) {
99
99
  name = prepareIdentifier(name);
100
100
 
101
101
  switch (options.sqlMapping) {
@@ -120,7 +120,7 @@ function getIdentifierUtils(options) {
120
120
  * @param {string} name Identifier to prepare
121
121
  * @returns {string} Identifier prepared for quoting
122
122
  */
123
- function prepareIdentifier(name) {
123
+ function prepareIdentifier( name ) {
124
124
  // Sanity check
125
125
  if (options.sqlDialect === 'sqlite' && options.sqlMapping !== 'plain')
126
126
  throw new ModelError(`Not expecting ${options.sqlMapping} names for 'sqlite' dialect`);
@@ -137,6 +137,22 @@ function getIdentifierUtils(options) {
137
137
  throw new ModelError(`No matching rendering found for naming mode ${options.sqlMapping}`);
138
138
  }
139
139
  }
140
+
141
+ /**
142
+ * Given the following artifact name: namespace.prefix.entity.with.dot, render the following,
143
+ * depending on the naming mode:
144
+ * - plain: NAMESPACE_PREFIX_ENTITY_WITH_DOT
145
+ * - quoted: namespace.prefix.entity_with_dot
146
+ * - hdbcds: namespace::prefix.entity_with_dot
147
+ *
148
+ *
149
+ * @param {string} artifactName Artifact name to render
150
+ *
151
+ * @returns {string} Artifact name
152
+ */
153
+ function renderArtifactName( artifactName ) {
154
+ return quoteSqlId(getResultingName(csn, options.sqlMapping, artifactName));
155
+ }
140
156
  }
141
157
 
142
158
 
@@ -16,7 +16,7 @@ const unpairedSurrogate = /[^\u{D800}-\u{DBFF}][\u{DC00}-\u{DFFF}]|[\u{D800}-\u{
16
16
  * @param {string} str
17
17
  * @return {boolean}
18
18
  */
19
- function hasUnpairedUnicodeSurrogate(str) {
19
+ function hasUnpairedUnicodeSurrogate( str ) {
20
20
  return unpairedSurrogate.test(str);
21
21
  }
22
22
 
@@ -26,7 +26,7 @@ function hasUnpairedUnicodeSurrogate(str) {
26
26
  * @param {string} str
27
27
  * @return {boolean}
28
28
  */
29
- function hasControlCharacters(str) {
29
+ function hasControlCharacters( str ) {
30
30
  return controlCharacters.test(str);
31
31
  }
32
32
 
@@ -60,7 +60,7 @@ function hasControlCharacters(str) {
60
60
  * @param {object} escapes
61
61
  * @returns {string}
62
62
  */
63
- function escapeString(str, escapes) {
63
+ function escapeString( str, escapes ) {
64
64
  const output = [];
65
65
 
66
66
  for (let i = 0; i < str.length; ++i) {
@@ -22,7 +22,7 @@ const { setProp } = require('../../base/model');
22
22
  * @param {CSN.Path} path Path to parent
23
23
  * @returns {object} parent with transformations applied
24
24
  */
25
- function applyTransformationsInternal(parent, prop, customTransformers, artifactTransformers, options, path = []) {
25
+ function applyTransformationsInternal( parent, prop, customTransformers, artifactTransformers, options, path = [] ) {
26
26
  const transformers = {
27
27
  elements: dictionary,
28
28
  definitions: dictionary,
@@ -196,7 +196,7 @@ function applyTransformations( csn, customTransformers = {}, artifactTransformer
196
196
  * @param {CSN.Path} path Path pointing to parent
197
197
  * @returns {object} parent[prop] with transformations applied
198
198
  */
199
- function applyTransformationsOnNonDictionary(parent, prop, customTransformers = {}, options = {}, path = []) {
199
+ function applyTransformationsOnNonDictionary( parent, prop, customTransformers = {}, options = {}, path = [] ) {
200
200
  return applyTransformationsInternal(parent, prop, customTransformers, [], options, path)[prop];
201
201
  }
202
202
 
@@ -217,7 +217,7 @@ function applyTransformationsOnNonDictionary(parent, prop, customTransformers =
217
217
  * @param {CSN.Path} path Path pointing to parent
218
218
  * @returns {object} dictionary with transformations applied
219
219
  */
220
- function applyTransformationsOnDictionary(dictionary, customTransformers = {}, options = {}, path = []) {
220
+ function applyTransformationsOnDictionary( dictionary, customTransformers = {}, options = {}, path = [] ) {
221
221
  return applyTransformationsInternal(dictionary, null, customTransformers, [], { directDict: true, ...options }, path);
222
222
  }
223
223
 
@@ -20,7 +20,7 @@ const { pathName } = require('../../compiler/utils');
20
20
  * @param {Function} error Message function for errors
21
21
  * @param {Function} info Message function for info
22
22
  */
23
- function processAssertUnique(csn, options, error, info) {
23
+ function processAssertUnique( csn, options, error, info ) {
24
24
  const { resolvePath, flattenPath } = getTransformers(csn, options);
25
25
 
26
26
  forEachDefinition(csn, handleAssertUnique);
@@ -30,7 +30,7 @@ function processAssertUnique(csn, options, error, info) {
30
30
  * @param {CSN.Artifact} artifact
31
31
  * @param {string} artifactName
32
32
  */
33
- function handleAssertUnique(artifact, artifactName) {
33
+ function handleAssertUnique( artifact, artifactName ) {
34
34
  // operate only on real entities that are not abstract
35
35
  if (artifact.abstract || (artifact.kind !== 'entity' || (artifact.query || artifact.projection) && !hasAnnotationValue(artifact, '@cds.persistence.table')))
36
36
  return;
@@ -38,12 +38,13 @@ function processAssertUnique(csn, options, error, info) {
38
38
  const constraintDict = Object.create(null);
39
39
  // filter unique constraints from annotations
40
40
  for (const propName in artifact) {
41
- if (propName.startsWith('@assert.unique') && artifact[propName] !== null) {
42
- const anno = propName;
41
+ const anno = propName;
42
+ if (propName === '@assert.unique')
43
+ error(null, [ 'definitions', artifactName ], { anno }, '$(ANNO): Table constraint can\'t be anonymous');
44
+
45
+ if (propName.startsWith('@assert.unique.') && artifact[propName] !== null) {
43
46
  // Constraint Name check
44
47
  const constraintName = propName.split('.').splice(2);
45
- if (constraintName.length === 0)
46
- error(null, [ 'definitions', artifactName ], { anno }, '$(ANNO): Table constraint can\'t be anonymous');
47
48
  if (constraintName.length > 1)
48
49
  // Neither HANA CDS nor HANA SQL allow dots in index names
49
50
  error(null, [ 'definitions', artifactName ], { anno }, '$(ANNO): Illegal character \'.\' in constraint name');
@@ -121,7 +122,7 @@ function processAssertUnique(csn, options, error, info) {
121
122
  * @param {string} propName
122
123
  * @returns {Array} Array of paths
123
124
  */
124
- function checkVal(val, propName) {
125
+ function checkVal( val, propName ) {
125
126
  const paths = [];
126
127
  const loc = [ 'definitions', artifactName ];
127
128
  if (!Array.isArray(val)) {
@@ -147,7 +148,7 @@ function processAssertUnique(csn, options, error, info) {
147
148
  * @param {any} v
148
149
  * @returns {string|string[]|any}
149
150
  */
150
- function unref(v) {
151
+ function unref( v ) {
151
152
  if (Array.isArray(v))
152
153
  return v.map(unref);
153
154
  return (v['='] || v);
@@ -160,7 +161,7 @@ function processAssertUnique(csn, options, error, info) {
160
161
  * @param {string} val
161
162
  * @returns {object}
162
163
  */
163
- function toRef(val) {
164
+ function toRef( val ) {
164
165
  let ref = val.split('.');
165
166
  const [ head, ...tail ] = ref;
166
167
  if (head === '$self' || head === '$projection')
@@ -185,7 +186,7 @@ function processAssertUnique(csn, options, error, info) {
185
186
  * @param {object} path
186
187
  * @param {string} constraintName
187
188
  */
188
- function check(path, constraintName) {
189
+ function check( path, constraintName ) {
189
190
  if (path.isChecked)
190
191
  return;
191
192
  path.isChecked = true;
@@ -262,12 +263,12 @@ function processAssertUnique(csn, options, error, info) {
262
263
  * @param {CSN.Options} options
263
264
  * @param {string} pathDelimiter
264
265
  */
265
- function rewriteUniqueConstraints(csn, options, pathDelimiter) {
266
+ function rewriteUniqueConstraints( csn, options, pathDelimiter ) {
266
267
  forEachDefinition(csn, rewrite);
267
268
  /**
268
269
  * @param {CSN.Artifact} artifact
269
270
  */
270
- function rewrite(artifact) {
271
+ function rewrite( artifact ) {
271
272
  if (artifact.$tableConstraints && artifact.$tableConstraints.unique) {
272
273
  const uniqueConstraints = artifact.$tableConstraints.unique;
273
274
  // it's safe to add the tc here
@@ -15,7 +15,7 @@ const {
15
15
  * @param {string} pathDelimiter
16
16
  * @returns {CSN.Model} Return the input csn, with the transformations applied
17
17
  */
18
- function attachOnConditions(csn, pathDelimiter) {
18
+ function attachOnConditions( csn, pathDelimiter ) {
19
19
  const {
20
20
  isManagedAssociation,
21
21
  } = getUtils(csn);
@@ -41,7 +41,7 @@ function attachOnConditions(csn, pathDelimiter) {
41
41
  * @param {string} elemName
42
42
  * @returns {void}
43
43
  */
44
- function transformManagedAssociation(elem, elemName) {
44
+ function transformManagedAssociation( elem, elemName ) {
45
45
  // No need to run over this - we already did, possibly because it was referenced in the ON-Condition
46
46
  // of another association - see a few lines lower
47
47
  if (alreadyHandled.has(elem))
@@ -107,7 +107,7 @@ function attachOnConditions(csn, pathDelimiter) {
107
107
  * @param {string} pathDelimiter
108
108
  * @returns {(artifact: CSN.Artifact, artifactName: string) => void} Callback for forEachDefinition
109
109
  */
110
- function getFKAccessFinalizer(csn, pathDelimiter) {
110
+ function getFKAccessFinalizer( csn, pathDelimiter ) {
111
111
  const {
112
112
  inspectRef,
113
113
  } = getUtils(csn);
@@ -123,7 +123,7 @@ function getFKAccessFinalizer(csn, pathDelimiter) {
123
123
  * @param {CSN.Artifact} artifact Artifact to check
124
124
  * @param {string} artifactName Name of the artifact
125
125
  */
126
- function handleManagedAssocSteps(artifact, artifactName) {
126
+ function handleManagedAssocSteps( artifact, artifactName ) {
127
127
  const transformer = {
128
128
  ref: (refOwner, prop, ref, path) => {
129
129
  // [<assoc base>.]<managed assoc>.<field>
@@ -177,7 +177,7 @@ function getFKAccessFinalizer(csn, pathDelimiter) {
177
177
  * @param {number} startIndex
178
178
  * @returns {object | undefined} CSN definition of the source of the managed association
179
179
  */
180
- function findSource(links, startIndex) {
180
+ function findSource( links, startIndex ) {
181
181
  for (let i = startIndex; i >= 0; i--) {
182
182
  const link = links[i];
183
183
  // We found the latest assoc step - now check where that points to
@@ -19,7 +19,7 @@ function getAnnoProcessor() {
19
19
  /**
20
20
  * @param {CSN.Artifact} artifact
21
21
  */
22
- function handleCdsPersistence(artifact) {
22
+ function handleCdsPersistence( artifact ) {
23
23
  const ignoreArtifact = (artifact.kind === 'entity') &&
24
24
  (artifact.abstract ||
25
25
  hasAnnotationValue(artifact, '@cds.persistence.skip') ||
@@ -39,7 +39,7 @@ function getAnnoProcessor() {
39
39
  * @param {Function} messageFunctions.info
40
40
  * @returns {(artifact: CSN.Artifact, artifactName: string, prop: string, path: CSN.Path) => void} Callback function for forEachDefinition
41
41
  */
42
- function getAssocToSkippedIgnorer(csn, options, messageFunctions) {
42
+ function getAssocToSkippedIgnorer( csn, options, messageFunctions ) {
43
43
  const { info } = messageFunctions;
44
44
  const doA2J = !(options.transformation === 'hdbcds' && options.sqlMapping === 'hdbcds');
45
45
 
@@ -55,7 +55,7 @@ function getAssocToSkippedIgnorer(csn, options, messageFunctions) {
55
55
  * @param {string} prop
56
56
  * @param {CSN.Path} path
57
57
  */
58
- function ignoreAssociationToSkippedTarget(artifact, artifactName, prop, path) {
58
+ function ignoreAssociationToSkippedTarget( artifact, artifactName, prop, path ) {
59
59
  if (isPersistedOnDatabase(artifact)) {
60
60
  // TODO: structure in CSN is artifact.query.[SELECT/SET].mixin
61
61
  if (artifact.query) {
@@ -79,7 +79,7 @@ function getAssocToSkippedIgnorer(csn, options, messageFunctions) {
79
79
  * @param {string} prop
80
80
  * @param {CSN.Path} path
81
81
  */
82
- function ignore(member, memberName, prop, path) {
82
+ function ignore( member, memberName, prop, path ) {
83
83
  if (options.sqlDialect === 'hana' &&
84
84
  !member._ignore && member.target &&
85
85
  isAssocOrComposition(member.type) &&
@@ -102,7 +102,7 @@ function getAssocToSkippedIgnorer(csn, options, messageFunctions) {
102
102
  * @param {Function} messageFunctions.error
103
103
  * @returns {(artifact: CSN.Artifact, artifactName) => void} Callback function for forEachDefinition
104
104
  */
105
- function getPersistenceTableProcessor(csn, options, messageFunctions ) {
105
+ function getPersistenceTableProcessor( csn, options, messageFunctions ) {
106
106
  const { error } = messageFunctions;
107
107
  const {
108
108
  recurseElements,
@@ -115,7 +115,7 @@ function getPersistenceTableProcessor(csn, options, messageFunctions ) {
115
115
  * @param {CSN.Artifact} artifact
116
116
  * @param {string} artifactName
117
117
  */
118
- function handleQueryish(artifact, artifactName) {
118
+ function handleQueryish( artifact, artifactName ) {
119
119
  const stripQueryish = artifact.query && hasAnnotationValue(artifact, '@cds.persistence.table');
120
120
 
121
121
  if (stripQueryish) {
@@ -124,8 +124,10 @@ function getPersistenceTableProcessor(csn, options, messageFunctions ) {
124
124
 
125
125
  recurseElements(artifact, [ 'definitions', artifactName ], (member, path) => {
126
126
  // All elements must have a type for this to work
127
- if (!member._ignore && !member.kind && !member.type)
128
- error(null, path, 'Expecting element to have a type if view is annotated with “@cds.persistence.table');
127
+ if (!member._ignore && !member.kind && !member.type) {
128
+ error(null, path, { anno: '@cds.persistence.table' },
129
+ 'Expecting element to have a type if view is annotated with $(ANNO)');
130
+ }
129
131
  });
130
132
  }
131
133
  }
@@ -14,7 +14,7 @@ const ASSOCIATION = 'cds.Association';
14
14
  * @param {CSN.Model} csn
15
15
  * @param {CSN.Options} options are used to modify the validate / enforced flag on the constraints
16
16
  */
17
- function createReferentialConstraints(csn, options) {
17
+ function createReferentialConstraints( csn, options ) {
18
18
  let validated = true;
19
19
  let enforced = true;
20
20
  if (options.integrityNotValidated)
@@ -77,7 +77,7 @@ function createReferentialConstraints(csn, options) {
77
77
  * @param {CSN.Artifact} parent artifact containing the composition
78
78
  * @param {CSN.Path} path
79
79
  */
80
- function foreignKeyConstraintForUpLinkOfComposition(composition, parent, path) {
80
+ function foreignKeyConstraintForUpLinkOfComposition( composition, parent, path ) {
81
81
  const dependent = csn.definitions[path[1]];
82
82
  if (skipConstraintGeneration(parent, dependent, composition))
83
83
  return;
@@ -103,7 +103,7 @@ function createReferentialConstraints(csn, options) {
103
103
  * @param {CSN.Path} path
104
104
  * @param {CSN.PathSegment} upLinkFor the name of the composition which used this association in a `$self = <comp>.<up_>` comparison
105
105
  */
106
- function foreignKeyConstraintForAssociation(association, path, upLinkFor = null) {
106
+ function foreignKeyConstraintForAssociation( association, path, upLinkFor = null ) {
107
107
  const parent = csn.definitions[association.target];
108
108
  const dependent = csn.definitions[path[1]];
109
109
  if (skipConstraintGeneration(parent, dependent, association))
@@ -136,7 +136,7 @@ function createReferentialConstraints(csn, options) {
136
136
  * @param {CSN.PathSegment} upLinkFor the name of the composition which used this association in a `$self = <comp>.<up_>` comparison
137
137
  * it is used for a comment in the constraint, which is only printed out in test-mode
138
138
  */
139
- function attachConstraintsToDependentKeys(dependentKeys, parentKeys, parentTable, sourceAssociation, upLinkFor = null) {
139
+ function attachConstraintsToDependentKeys( dependentKeys, parentKeys, parentTable, sourceAssociation, upLinkFor = null ) {
140
140
  while (dependentKeys.length > 0) {
141
141
  const dependentKeyValuePair = dependentKeys.pop();
142
142
  const dependentKey = dependentKeyValuePair[1];
@@ -178,7 +178,7 @@ function createReferentialConstraints(csn, options) {
178
178
  * @param {CSN.Path} path the path to the element
179
179
  * @returns {boolean} indicating whether the association / composition is a constraint candidate
180
180
  */
181
- function hasConstraintCompliantOnCondition(element, siblingElements, path) {
181
+ function hasConstraintCompliantOnCondition( element, siblingElements, path ) {
182
182
  const onCondition = element.on;
183
183
  const allowedTokens = [ '=', 'and', '(', ')' ];
184
184
  // on condition must only contain logical operator 'AND'
@@ -266,7 +266,7 @@ function createReferentialConstraints(csn, options) {
266
266
  * @param {CSN.Association} element the composition or association
267
267
  * @returns {boolean}
268
268
  */
269
- function skipConstraintGeneration(parent, dependent, element) {
269
+ function skipConstraintGeneration( parent, dependent, element ) {
270
270
  // if set to 'off' don't even bother, just skip all constraints
271
271
  if (options.assertIntegrity === false || options.assertIntegrity === 'false')
272
272
  return true;
@@ -390,7 +390,7 @@ function createReferentialConstraints(csn, options) {
390
390
  * @param {string|boolean} value
391
391
  * @returns {boolean}
392
392
  */
393
- function isAssertIntegrityAnnotationSetTo(value) {
393
+ function isAssertIntegrityAnnotationSetTo( value ) {
394
394
  return hasAnnotationValue(element, '@assert.integrity', value, true);
395
395
  }
396
396
 
@@ -401,7 +401,7 @@ function createReferentialConstraints(csn, options) {
401
401
  * @param {string} prop
402
402
  * @param {object} val
403
403
  */
404
- function assignPropOnBacklinkIfPossible(prop, val) {
404
+ function assignPropOnBacklinkIfPossible( prop, val ) {
405
405
  if (!element.$selfOnCondition)
406
406
  return;
407
407
  const target = csn.definitions[element.target];
@@ -418,7 +418,7 @@ function createReferentialConstraints(csn, options) {
418
418
  * @param {CSN.Composition} composition the composition which might be treated like an association
419
419
  * @returns {boolean} true if the composition should be treated as an association in regards to foreign key constraints
420
420
  */
421
- function treatCompositionLikeAssociation(composition) {
421
+ function treatCompositionLikeAssociation( composition ) {
422
422
  return Boolean(isToOne(composition) && composition.keys);
423
423
  }
424
424
 
@@ -428,7 +428,7 @@ function createReferentialConstraints(csn, options) {
428
428
  * @param {CSN.Association|CSN.Composition} assocOrComposition
429
429
  * @returns {boolean}
430
430
  */
431
- function isToOne(assocOrComposition) {
431
+ function isToOne( assocOrComposition ) {
432
432
  const { min, max } = assocOrComposition.cardinality || {};
433
433
  return !min && !max || max === 1;
434
434
  }
@@ -440,7 +440,7 @@ function createReferentialConstraints(csn, options) {
440
440
  * @param {CSN.Elements} targetElements elements of association/composition target entity
441
441
  * @returns {Map} of target elements with their name as key
442
442
  */
443
- function elementsOfTargetSide(on, targetElements) {
443
+ function elementsOfTargetSide( on, targetElements ) {
444
444
  const elements = new Map();
445
445
  on.filter(element => typeof element === 'object' &&
446
446
  element.ref.length > 1 &&
@@ -459,7 +459,7 @@ function createReferentialConstraints(csn, options) {
459
459
  * @param {CSN.Elements} sourceElements elements of source entity where the association/composition is defined.
460
460
  * @returns {Map} of source elements with their name as key
461
461
  */
462
- function elementsOfSourceSide(on, sourceElements) {
462
+ function elementsOfSourceSide( on, sourceElements ) {
463
463
  const elements = new Map();
464
464
  on.filter(element => typeof element === 'object' &&
465
465
  element.ref.length === 1 &&
@@ -481,7 +481,7 @@ function createReferentialConstraints(csn, options) {
481
481
  * @param {CSN.Artifact} artifact
482
482
  * @param {string} artifactName
483
483
  */
484
- function collectAndAttachReferentialConstraints(artifact, artifactName) {
484
+ function collectAndAttachReferentialConstraints( artifact, artifactName ) {
485
485
  const referentialConstraints = Object.create(null);
486
486
  for (const elementName in artifact.elements) {
487
487
  const element = artifact.elements[elementName];
@@ -546,7 +546,7 @@ function createReferentialConstraints(csn, options) {
546
546
  * @param {CSN.Path} path
547
547
  * @param {Function} error
548
548
  */
549
- function assertConstraintIdentifierUniqueness(artifact, artifactName, path, error) {
549
+ function assertConstraintIdentifierUniqueness( artifact, artifactName, path, error ) {
550
550
  // can only happen if referential & unique constraints are present
551
551
  if (!(artifact.$tableConstraints && artifact.$tableConstraints.referential && artifact.$tableConstraints.unique))
552
552
  return;
@@ -23,7 +23,7 @@ const { forEach } = require('../../utils/objectUtils');
23
23
  * @param {Function} messageFunctions.throwWithAnyError
24
24
  * @param {object} iterateOptions
25
25
  */
26
- function expandStructureReferences(csn, options, pathDelimiter, { error, info, throwWithAnyError }, iterateOptions = {}) {
26
+ function expandStructureReferences( csn, options, pathDelimiter, { error, info, throwWithAnyError }, iterateOptions = {} ) {
27
27
  const csnUtils = getUtils(csn);
28
28
  const {
29
29
  isStructured, get$combined, getFinalBaseTypeWithProps,
@@ -62,7 +62,7 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
62
62
  * For such skipped things, error for usage of assoc pointing to them and and ignore publishing of assoc pointing to them.
63
63
  */
64
64
  function rewriteExpandInline() {
65
- let cleanup;
65
+ let cleanup = [];
66
66
  let _dependents;
67
67
 
68
68
  const entity = findAnEntity();
@@ -81,7 +81,7 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
81
81
  * Do not remove unexpandable many columns in OData
82
82
  */
83
83
  if (rewritten.toMany.length > 0 && !options.toOdata) {
84
- markAsToDummyfy(artifact, path[1]);
84
+ markAsToDummify(artifact, path[1]);
85
85
  error( null, [ 'definitions', path[1] ], { name: path[1] }, 'Unexpected .expand with to-many association in entity $(NAME)');
86
86
  }
87
87
  else {
@@ -96,12 +96,10 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
96
96
  if (!options.toOdata)
97
97
  dummyfy();
98
98
 
99
- if (cleanup)
100
- cleanup.forEach(fn => fn());
99
+ cleanup.forEach(fn => fn());
101
100
 
102
101
  ({ effectiveType, inspectRef } = csnRefs(csn));
103
102
 
104
-
105
103
  const publishing = [];
106
104
  // OData must allow navigations to @cds.persistence.skip targets
107
105
  // as valid navigations in the API
@@ -134,7 +132,7 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
134
132
  * @param {Array} parts
135
133
  * @param {CSN.Path} path
136
134
  */
137
- function check(parent, name, parts, path) {
135
+ function check( parent, name, parts, path ) {
138
136
  const inColumns = name === 'columns';
139
137
  const kill = [];
140
138
  for (let i = 0; i < parts.length; i++) {
@@ -207,8 +205,8 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
207
205
  * @param {CSN.Artifact} artifact
208
206
  * @param {string} name
209
207
  */
210
- function markAsToDummyfy(artifact, name) {
211
- if (!_dependents && !cleanup)
208
+ function markAsToDummify( artifact, name ) {
209
+ if (!_dependents && cleanup.length === 0)
212
210
  ({ cleanup, _dependents } = setDependencies(csn, csnUtils));
213
211
 
214
212
  const stack = [ [ artifact, name ] ];
@@ -240,7 +238,7 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
240
238
  * @param {CSN.Artifact} base The current base
241
239
  * @returns {CSN.Artifact}
242
240
  */
243
- function nextBase(parent, base) {
241
+ function nextBase( parent, base ) {
244
242
  if (parent.ref) {
245
243
  const finalBaseType = getFinalBaseTypeWithProps(parent._art.type);
246
244
  const art = parent._art;
@@ -262,7 +260,7 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
262
260
  * @param {string[]} excluding
263
261
  * @returns {{columns: Array, toMany: Array}} Object with rewritten columns (.expand/.inline) and with any .expand + to-many
264
262
  */
265
- function rewrite(root, columns, excluding) {
263
+ function rewrite( root, columns, excluding ) {
266
264
  const allToMany = [];
267
265
  const newThing = [];
268
266
  const containsExpandInline = columns.some(col => col.expand || col.inline);
@@ -299,7 +297,7 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
299
297
  * @param {CSN.Element} obj
300
298
  * @returns {boolean}
301
299
  */
302
- function isToMany(obj) {
300
+ function isToMany( obj ) {
303
301
  if (!obj._art)
304
302
  return false;
305
303
  const eType = effectiveType(obj._art);
@@ -318,7 +316,7 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
318
316
  * @param {Array} alias Any start-alias
319
317
  * @returns {{expanded: Array, toManys: Array}} Object with expanded .expand/.inline and with any .expand + to-many
320
318
  */
321
- function expandInline(root, col, ref, alias) {
319
+ function expandInline( root, col, ref, alias ) {
322
320
  const toManys = [];
323
321
  const expanded = [];
324
322
  const stack = [ [ root, col, ref, alias ] ];
@@ -376,7 +374,7 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
376
374
  * @param {object} parent Thing that has an .xpr/.args
377
375
  * @param {string[]} ref Ref so far
378
376
  */
379
- function rewriteExpressionArrays(parent, ref) {
377
+ function rewriteExpressionArrays( parent, ref ) {
380
378
  const stack = [ [ parent, ref ] ];
381
379
  while (stack.length > 0) {
382
380
  const [ current, currentRef ] = stack.pop();
@@ -397,7 +395,7 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
397
395
  * @param {object} parent
398
396
  * @param {Array} ref The so-far effective name (basically the will-be alias), as an array to treat like a ref
399
397
  */
400
- function rewriteOn(parent, ref) {
398
+ function rewriteOn( parent, ref ) {
401
399
  const stack = [ [ parent, ref ] ];
402
400
  while (stack.length > 0) {
403
401
  const [ current, currentRef ] = stack.pop();
@@ -418,7 +416,7 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
418
416
  * @param {Array} currentRef
419
417
  * @param {Array} stack
420
418
  */
421
- function rewriteOnCondition(on, currentRef, stack) {
419
+ function rewriteOnCondition( on, currentRef, stack ) {
422
420
  for (let i = 0; i < on.length; i++) {
423
421
  const part = on[i];
424
422
  if (part.ref && part.ref[0] !== '$self' && part.ref[0] !== '$projection') {
@@ -439,7 +437,7 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
439
437
  * @param {Array} currentRef
440
438
  * @param {Array} stack
441
439
  */
442
- function rewriteSingleExpressionArray(expressionArray, currentRef, stack) {
440
+ function rewriteSingleExpressionArray( expressionArray, currentRef, stack ) {
443
441
  for (let i = 0; i < expressionArray.length; i++) {
444
442
  const part = expressionArray[i];
445
443
  if (part.ref) {
@@ -472,7 +470,7 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
472
470
  * @param {string} source
473
471
  * @returns {CSN.Artifact}
474
472
  */
475
- function createDummyView(source) {
473
+ function createDummyView( source ) {
476
474
  const elements = Object.create(null);
477
475
  elements.one = {
478
476
  '@Core.Computed': true,
@@ -517,7 +515,7 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
517
515
  * @param {boolean} [withAlias=false] Whether to "expand" the (implicit) alias aswell.
518
516
  * @returns {Array} New array - with all structured things expanded
519
517
  */
520
- function expand(thing, path, withAlias = false) {
518
+ function expand( thing, path, withAlias = false ) {
521
519
  const newThing = [];
522
520
  for (let i = 0; i < thing.length; i++) {
523
521
  const col = thing[i];
@@ -553,7 +551,7 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
553
551
  * @param {boolean} withAlias
554
552
  * @returns {Array}
555
553
  */
556
- function expandRef(art, ref, alias, isKey, withAlias) {
554
+ function expandRef( art, ref, alias, isKey, withAlias ) {
557
555
  const expanded = [];
558
556
  /** @type {Array<[CSN.Element, any[], any[]]>} */
559
557
  const stack = [ [ art, ref, [ alias || ref[ref.length - 1] ] ] ];
@@ -588,7 +586,7 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
588
586
  * @param {object} part A thing with a ref/as/func
589
587
  * @returns {string}
590
588
  */
591
- function dbName(part) {
589
+ function dbName( part ) {
592
590
  if (part.as)
593
591
  return part.as;
594
592
  else if (part.ref)
@@ -606,7 +604,7 @@ function expandStructureReferences(csn, options, pathDelimiter, { error, info, t
606
604
  * @param {string[]} [excluding=[]]
607
605
  * @returns {Array} If there was a star, expand it and handle shadowing/excluding, else just return subs
608
606
  */
609
- function replaceStar(base, subs, excluding = []) {
607
+ function replaceStar( base, subs, excluding = [] ) {
610
608
  const stars = [];
611
609
  const names = Object.create(null);
612
610
  for (let i = 0; i < subs.length; i++) {