@sap/cds-compiler 3.4.2 → 3.5.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 (143) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +1 -0
  3. package/bin/cds_update_identifiers.js +5 -5
  4. package/bin/cdsc.js +15 -16
  5. package/bin/cdshi.js +19 -6
  6. package/doc/CHANGELOG_ARCHIVE.md +2 -2
  7. package/doc/CHANGELOG_BETA.md +9 -1
  8. package/doc/CHANGELOG_DEPRECATED.md +2 -0
  9. package/lib/api/main.js +61 -59
  10. package/lib/api/options.js +4 -2
  11. package/lib/api/validate.js +2 -2
  12. package/lib/base/cleanSymbols.js +2 -3
  13. package/lib/base/dictionaries.js +6 -6
  14. package/lib/base/error.js +2 -2
  15. package/lib/base/keywords.js +6 -6
  16. package/lib/base/location.js +11 -12
  17. package/lib/base/message-registry.js +177 -58
  18. package/lib/base/messages.js +252 -180
  19. package/lib/base/model.js +14 -11
  20. package/lib/base/node-helpers.js +9 -10
  21. package/lib/base/optionProcessorHelper.js +138 -129
  22. package/lib/checks/.eslintrc.json +2 -0
  23. package/lib/checks/actionsFunctions.js +5 -5
  24. package/lib/checks/annotationsOData.js +4 -4
  25. package/lib/checks/arrayOfs.js +1 -1
  26. package/lib/checks/cdsPersistence.js +1 -1
  27. package/lib/checks/checkForTypes.js +3 -3
  28. package/lib/checks/defaultValues.js +3 -3
  29. package/lib/checks/elements.js +7 -7
  30. package/lib/checks/emptyOrOnlyVirtual.js +2 -2
  31. package/lib/checks/foreignKeys.js +1 -1
  32. package/lib/checks/invalidTarget.js +4 -4
  33. package/lib/checks/managedInType.js +1 -1
  34. package/lib/checks/managedWithoutKeys.js +1 -1
  35. package/lib/checks/nonexpandableStructured.js +5 -3
  36. package/lib/checks/nullableKeys.js +1 -1
  37. package/lib/checks/onConditions.js +5 -6
  38. package/lib/checks/parameters.js +1 -1
  39. package/lib/checks/queryNoDbArtifacts.js +2 -2
  40. package/lib/checks/selectItems.js +4 -4
  41. package/lib/checks/sql-snippets.js +4 -4
  42. package/lib/checks/types.js +7 -7
  43. package/lib/checks/utils.js +4 -4
  44. package/lib/checks/validator.js +16 -13
  45. package/lib/compiler/.eslintrc.json +4 -1
  46. package/lib/compiler/assert-consistency.js +8 -7
  47. package/lib/compiler/builtins.js +14 -14
  48. package/lib/compiler/checks.js +123 -48
  49. package/lib/compiler/define.js +12 -13
  50. package/lib/compiler/extend.js +266 -60
  51. package/lib/compiler/finalize-parse-cdl.js +10 -5
  52. package/lib/compiler/index.js +17 -14
  53. package/lib/compiler/populate.js +14 -6
  54. package/lib/compiler/propagator.js +2 -0
  55. package/lib/compiler/resolve.js +2 -15
  56. package/lib/compiler/shared.js +27 -16
  57. package/lib/compiler/tweak-assocs.js +5 -6
  58. package/lib/compiler/utils.js +20 -0
  59. package/lib/edm/annotations/genericTranslation.js +604 -358
  60. package/lib/edm/annotations/preprocessAnnotations.js +39 -35
  61. package/lib/edm/csn2edm.js +275 -222
  62. package/lib/edm/edm.js +17 -3
  63. package/lib/edm/edmAnnoPreprocessor.js +6 -6
  64. package/lib/edm/edmInboundChecks.js +2 -2
  65. package/lib/edm/edmPreprocessor.js +107 -77
  66. package/lib/edm/edmUtils.js +44 -5
  67. package/lib/gen/Dictionary.json +210 -8
  68. package/lib/gen/language.checksum +1 -1
  69. package/lib/gen/language.interp +67 -63
  70. package/lib/gen/language.tokens +81 -81
  71. package/lib/gen/languageLexer.interp +4 -10
  72. package/lib/gen/languageLexer.js +854 -869
  73. package/lib/gen/languageLexer.tokens +79 -81
  74. package/lib/gen/languageParser.js +14309 -13832
  75. package/lib/inspect/inspectModelStatistics.js +2 -2
  76. package/lib/inspect/inspectPropagation.js +6 -6
  77. package/lib/inspect/inspectUtils.js +2 -2
  78. package/lib/json/from-csn.js +102 -55
  79. package/lib/json/to-csn.js +119 -198
  80. package/lib/language/antlrParser.js +5 -2
  81. package/lib/language/docCommentParser.js +6 -6
  82. package/lib/language/errorStrategy.js +43 -23
  83. package/lib/language/genericAntlrParser.js +113 -133
  84. package/lib/language/language.g4 +1550 -1506
  85. package/lib/language/multiLineStringParser.js +3 -3
  86. package/lib/language/textUtils.js +2 -2
  87. package/lib/main.js +3 -3
  88. package/lib/model/csnRefs.js +5 -0
  89. package/lib/model/csnUtils.js +130 -122
  90. package/lib/model/revealInternalProperties.js +1 -1
  91. package/lib/model/sortViews.js +4 -6
  92. package/lib/modelCompare/compare.js +2 -2
  93. package/lib/modelCompare/utils/.eslintrc.json +22 -0
  94. package/lib/modelCompare/utils/filter.js +100 -0
  95. package/lib/optionProcessor.js +5 -0
  96. package/lib/render/.eslintrc.json +1 -0
  97. package/lib/render/DuplicateChecker.js +1 -1
  98. package/lib/render/manageConstraints.js +12 -12
  99. package/lib/render/toCdl.js +311 -276
  100. package/lib/render/toHdbcds.js +97 -94
  101. package/lib/render/toRename.js +5 -5
  102. package/lib/render/toSql.js +127 -223
  103. package/lib/render/utils/common.js +141 -108
  104. package/lib/render/utils/delta.js +227 -0
  105. package/lib/render/utils/sql.js +22 -6
  106. package/lib/render/utils/stringEscapes.js +3 -3
  107. package/lib/transform/db/.eslintrc.json +2 -0
  108. package/lib/transform/db/applyTransformations.js +3 -3
  109. package/lib/transform/db/assertUnique.js +13 -12
  110. package/lib/transform/db/associations.js +5 -5
  111. package/lib/transform/db/cdsPersistence.js +10 -8
  112. package/lib/transform/db/constraints.js +14 -14
  113. package/lib/transform/db/expansion.js +20 -22
  114. package/lib/transform/db/flattening.js +24 -42
  115. package/lib/transform/db/groupByOrderBy.js +3 -3
  116. package/lib/transform/db/temporal.js +6 -6
  117. package/lib/transform/db/transformExists.js +23 -23
  118. package/lib/transform/db/views.js +16 -16
  119. package/lib/transform/draft/.eslintrc.json +1 -35
  120. package/lib/transform/draft/db.js +10 -10
  121. package/lib/transform/draft/odata.js +2 -2
  122. package/lib/transform/forOdataNew.js +8 -29
  123. package/lib/transform/forRelationalDB.js +16 -6
  124. package/lib/transform/localized.js +11 -10
  125. package/lib/transform/odata/toFinalBaseType.js +41 -27
  126. package/lib/transform/odata/typesExposure.js +113 -47
  127. package/lib/transform/parseExpr.js +209 -106
  128. package/lib/transform/transformUtilsNew.js +17 -10
  129. package/lib/transform/translateAssocsToJoins.js +24 -19
  130. package/lib/transform/universalCsn/coreComputed.js +10 -10
  131. package/lib/transform/universalCsn/universalCsnEnricher.js +26 -26
  132. package/lib/transform/universalCsn/utils.js +3 -3
  133. package/lib/utils/file.js +5 -5
  134. package/lib/utils/moduleResolve.js +13 -13
  135. package/lib/utils/objectUtils.js +6 -6
  136. package/lib/utils/term.js +5 -2
  137. package/lib/utils/timetrace.js +51 -24
  138. package/package.json +5 -8
  139. package/share/messages/check-proper-type-of.md +1 -1
  140. package/share/messages/message-explanations.json +1 -1
  141. package/share/messages/redirected-to-complex.md +4 -4
  142. package/share/messages/{syntax-expecting-integer.md → syntax-expecting-unsigned-int.md} +7 -4
  143. package/lib/modelCompare/filter.js +0 -83
package/lib/api/main.js CHANGED
@@ -12,11 +12,12 @@ const forOdataNew = lazyload('../transform/forOdataNew.js');
12
12
  const toSql = lazyload('../render/toSql');
13
13
  const toCdl = require('../render/toCdl');
14
14
  const modelCompare = lazyload('../modelCompare/compare');
15
- const diffFilter = lazyload('../modelCompare/filter');
15
+ const diffFilter = lazyload('../modelCompare/utils/filter');
16
16
  const sortViews = lazyload('../model/sortViews');
17
17
  const csnUtils = lazyload('../model/csnUtils');
18
18
  const timetrace = lazyload('../utils/timetrace');
19
19
  const forRelationalDB = lazyload('../transform/forRelationalDB');
20
+ const sqlUtils = lazyload('../render/utils/sql');
20
21
 
21
22
  /**
22
23
  * Return the artifact name for use for the hdbresult object
@@ -26,15 +27,14 @@ const forRelationalDB = lazyload('../transform/forRelationalDB');
26
27
  * @param {CSN.Model} csn SQL transformed model
27
28
  * @returns {string} Name with . replaced as _ in some places
28
29
  */
29
- function getFileName(artifactName, csn) {
30
+ function getFileName( artifactName, csn ) {
30
31
  return csnUtils.getResultingName(csn, 'quoted', artifactName);
31
32
  }
32
33
 
33
- const { cloneCsnNonDict } = require('../model/csnUtils');
34
34
  const { toHdbcdsSource } = require('../render/toHdbcds');
35
35
  const { ModelError } = require('../base/error');
36
36
  const { forEach, forEachKey } = require('../utils/objectUtils');
37
- const { checkRemovedDeprecatedFlags, isBetaEnabled } = require('../base/model');
37
+ const { checkRemovedDeprecatedFlags } = require('../base/model');
38
38
  const { csn2edm, csn2edmAll } = require('../edm/csn2edm');
39
39
 
40
40
  const relevantGeneralOptions = [ /* for future generic options */ ];
@@ -50,8 +50,8 @@ const warnAboutMismatchOdata = [ 'odataVersion' ];
50
50
  * @param {string[]} relevantOptionNames Option names that are defining characteristics
51
51
  * @param {string[]} [optionalOptionNames=[]] Option names that should be attached as a fyi
52
52
  */
53
- function attachTransformerCharacteristics(csn, transformation, options,
54
- relevantOptionNames, optionalOptionNames = []) {
53
+ function attachTransformerCharacteristics( csn, transformation, options,
54
+ relevantOptionNames, optionalOptionNames = [] ) {
55
55
  const relevant = {};
56
56
  for (const name of relevantOptionNames ) {
57
57
  if (options[name] !== undefined)
@@ -85,7 +85,7 @@ function attachTransformerCharacteristics(csn, transformation, options,
85
85
  * @param {string[]} warnAboutMismatch Option names to warn about, but not error on
86
86
  * @param {string} module Name of the module that calls this function, e.g. `for.odata`
87
87
  */
88
- function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMismatch, module) {
88
+ function checkPreTransformedCsn( csn, options, relevantOptionNames, warnAboutMismatch, module ) {
89
89
  if (!csn.meta) {
90
90
  // Not able to check
91
91
  return;
@@ -93,7 +93,7 @@ function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMism
93
93
  const { error, warning, throwWithAnyError } = messages.makeMessageFunction(csn, options, module);
94
94
 
95
95
  for (const name of relevantOptionNames ) {
96
- if (options[name] !== csn.meta.options[name]) {
96
+ if (options[name] !== csn.meta.options?.[name]) {
97
97
  error('wrong-pretransformed-csn', null, { prop: name, value: options[name], othervalue: csn.meta.options[name] },
98
98
  'Expected pre-processed CSN to have option $(PROP) set to $(VALUE). Found: $(OTHERVALUE)');
99
99
  }
@@ -118,7 +118,7 @@ function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMism
118
118
  * @param {string} transformation Name of the transformation
119
119
  * @returns {boolean} Return true if it is pre-transformed
120
120
  */
121
- function isPreTransformed(csn, transformation) {
121
+ function isPreTransformed( csn, transformation ) {
122
122
  return csn && csn.meta && csn.meta.transformation === transformation;
123
123
  }
124
124
 
@@ -129,7 +129,7 @@ function isPreTransformed(csn, transformation) {
129
129
  * @param {object} internalOptions processed options
130
130
  * @returns {object} Return an oData-pre-processed CSN
131
131
  */
132
- function odataInternal(csn, internalOptions) {
132
+ function odataInternal( csn, internalOptions ) {
133
133
  const oDataCsn = forOdataNew.transform4odataWithCsn(csn, internalOptions);
134
134
  attachTransformerCharacteristics(oDataCsn, 'odata', internalOptions, relevantOdataOptions, warnAboutMismatchOdata);
135
135
  return oDataCsn;
@@ -142,7 +142,7 @@ function odataInternal(csn, internalOptions) {
142
142
  * @param {ODataOptions} [options={}] Options
143
143
  * @returns {oDataCSN} Return an oData-pre-processed CSN
144
144
  */
145
- function odata(csn, options = {}) {
145
+ function odata( csn, options = {} ) {
146
146
  const internalOptions = prepareOptions.for.odata(options);
147
147
  return odataInternal(csn, internalOptions);
148
148
  }
@@ -154,9 +154,9 @@ function odata(csn, options = {}) {
154
154
  * @param {object} [externalOptions={}] Options
155
155
  * @returns {object} { model: string, namespace: string }
156
156
  */
157
- function cdl(csn, externalOptions = {}) {
157
+ function cdl( csn, externalOptions = {} ) {
158
158
  const internalOptions = prepareOptions.to.cdl(externalOptions);
159
- return toCdl.csnToCdl(cloneCsnNonDict(csn, internalOptions), internalOptions);
159
+ return toCdl.csnToCdl(csn, internalOptions);
160
160
  }
161
161
 
162
162
  /**
@@ -167,7 +167,7 @@ function cdl(csn, externalOptions = {}) {
167
167
  * @returns {CSN.Model} CSN transformed like to.sql
168
168
  * @private
169
169
  */
170
- function forSql(csn, options = {}) {
170
+ function forSql( csn, options = {} ) {
171
171
  const internalOptions = prepareOptions.to.sql(options);
172
172
  internalOptions.transformation = 'sql';
173
173
  const transformedCsn = forRelationalDB.transformForRelationalDBWithCsn(csn, internalOptions, 'to.sql');
@@ -182,7 +182,7 @@ function forSql(csn, options = {}) {
182
182
  * @returns {CSN.Model} CSN transformed like to.hdi
183
183
  * @private
184
184
  */
185
- function forHdi(csn, options = {}) {
185
+ function forHdi( csn, options = {} ) {
186
186
  const internalOptions = prepareOptions.to.hdi(options);
187
187
  internalOptions.transformation = 'sql';
188
188
  const transformedCsn = forRelationalDB.transformForRelationalDBWithCsn(csn, internalOptions, 'to.hdi');
@@ -197,7 +197,7 @@ function forHdi(csn, options = {}) {
197
197
  * @returns {CSN.Model} CSN transformed like to.hdbcds
198
198
  * @private
199
199
  */
200
- function forHdbcds(csn, options = {}) {
200
+ function forHdbcds( csn, options = {} ) {
201
201
  const internalOptions = prepareOptions.to.hdbcds(options);
202
202
  internalOptions.transformation = 'hdbcds';
203
203
 
@@ -213,7 +213,7 @@ function forHdbcds(csn, options = {}) {
213
213
  * @param {SqlOptions} [options={}] Options
214
214
  * @returns {SQL[]} Array of SQL statements, tables first, views second
215
215
  */
216
- function sql(csn, options = {}) {
216
+ function sql( csn, options = {} ) {
217
217
  const internalOptions = prepareOptions.to.sql(options);
218
218
  internalOptions.transformation = 'sql';
219
219
 
@@ -243,7 +243,7 @@ function sql(csn, options = {}) {
243
243
  * multiple statements concatenated as a multi-line string in case the change e.g.
244
244
  * consists of a column drop and add).
245
245
  */
246
- function mtx(csn, deltaCsn, options = {}) {
246
+ function mtx( csn, deltaCsn, options = {} ) {
247
247
  if (!baseModel.isBetaEnabled(options, 'to.mtx'))
248
248
  throw new Error('to.mtx is only available with beta flag `to.mtx`');
249
249
 
@@ -277,7 +277,7 @@ function mtx(csn, deltaCsn, options = {}) {
277
277
  * @param {HdiOptions} [options={}] Options
278
278
  * @returns {HDIArtifacts} { <filename>:<content>, ...}
279
279
  */
280
- function hdi(csn, options = {}) {
280
+ function hdi( csn, options = {} ) {
281
281
  const internalOptions = prepareOptions.to.hdi(options);
282
282
 
283
283
  // we need the CSN for view sorting
@@ -333,7 +333,7 @@ function hdi(csn, options = {}) {
333
333
  * @param {Function} filter Filter for keys not to remap
334
334
  * @returns {object} New result structure
335
335
  */
336
- function remapNames(dict, csn, filter) {
336
+ function remapNames( dict, csn, filter ) {
337
337
  const result = Object.create(null);
338
338
 
339
339
  forEach(dict, (key, value) => {
@@ -353,7 +353,7 @@ function remapNames(dict, csn, filter) {
353
353
  * @param {Function} filter Filter for keys not to remap
354
354
  * @returns {string} Remapped filename
355
355
  */
356
- function remapName(key, csn, filter = () => true) {
356
+ function remapName( key, csn, filter = () => true ) {
357
357
  if (filter(key)) {
358
358
  const lastDot = key.lastIndexOf('.');
359
359
  const prefix = key.slice(0, lastDot);
@@ -379,13 +379,10 @@ function remapName(key, csn, filter = () => true) {
379
379
  * - drops: An array of SQL statements to drop views/tables
380
380
  * - createsAndAlters: An array of SQL statements to ALTER/CREATE tables/views
381
381
  */
382
- function sqlMigration(csn, options, beforeImage) {
382
+ function sqlMigration( csn, options, beforeImage ) {
383
383
  const internalOptions = prepareOptions.to.sql(options);
384
384
  const { error, throwWithError } = messages.makeMessageFunction(csn, options, 'to.sql.migration');
385
385
 
386
- if (!isBetaEnabled(internalOptions, 'sqlMigration'))
387
- throw new Error('Function `to.sql.migration` requires beta-flag `sqlMigration`');
388
-
389
386
  // Prepare after-image.
390
387
  const afterImage = forSql(csn, options);
391
388
  // Compare both images.
@@ -398,10 +395,12 @@ function sqlMigration(csn, options, beforeImage) {
398
395
  Object.entries(diff.deletions).forEach(entry => diffFilterObj.deletion(entry, error));
399
396
  }
400
397
 
398
+ const identifierUtils = sqlUtils.getIdentifierUtils(csn, internalOptions);
399
+
401
400
  const drops = {
402
401
  creates: {},
403
402
  final: Object.entries(diff.deletions).reduce((previous, [ name, artifact ]) => {
404
- previous[name] = `DROP ${ (artifact.query || artifact.projection) ? 'VIEW' : 'TABLE' } ${ artifact['@cds.persistence.name'] };`;
403
+ previous[name] = `DROP ${ (artifact.query || artifact.projection) ? 'VIEW' : 'TABLE' } ${ identifierUtils.renderArtifactName(name) };`;
405
404
  return previous;
406
405
  }, {}),
407
406
  };
@@ -417,7 +416,7 @@ function sqlMigration(csn, options, beforeImage) {
417
416
  (diffArtifact.query || diffArtifact.projection) &&
418
417
  (diffArtifact[modelCompare.isChanged] === true || // we know it changed because we compared two views
419
418
  diffArtifact[modelCompare.isChanged] === undefined)) { // if it was removed in the after, then we don't have the flag
420
- drops.creates[artifactName] = `DROP VIEW ${ diffArtifact['@cds.persistence.name'] };`;
419
+ drops.creates[artifactName] = `DROP VIEW ${ identifierUtils.renderArtifactName(artifactName) };`;
421
420
  } // TODO: What happens with a changed kind -> entity becomes a view?
422
421
  else if (diffArtifact &&
423
422
  diffArtifact['@cds.persistence.skip'] !== true &&
@@ -489,7 +488,7 @@ function sqlMigration(csn, options, beforeImage) {
489
488
  * is known, i.e. for the very first migration step
490
489
  * @returns {migration} The migration result
491
490
  */
492
- function hdiMigration(csn, options, beforeImage) {
491
+ function hdiMigration( csn, options, beforeImage ) {
493
492
  const internalOptions = prepareOptions.to.hdi(options);
494
493
 
495
494
  // Prepare after-image.
@@ -520,7 +519,7 @@ function hdiMigration(csn, options, beforeImage) {
520
519
  * @param {CSN.Model} afterImage CSN, used to create correct file names in result structure.
521
520
  * @returns {object[]} Array of objects, each having: name, suffix and sql
522
521
  */
523
- function createSqlDefinitions(hdbkinds, afterImage) {
522
+ function createSqlDefinitions( hdbkinds, afterImage ) {
524
523
  const result = [];
525
524
  forEach(hdbkinds, (kind, artifacts) => {
526
525
  const suffix = `.${ kind }`;
@@ -540,7 +539,7 @@ function createSqlDefinitions(hdbkinds, afterImage) {
540
539
  * @param {CSN.Model} beforeImage CSN used to create correct file names in result structure.
541
540
  * @returns {object[]} Array of objects, each having: name and suffix - only .hdbtable as suffix for now
542
541
  */
543
- function createSqlDeletions(deletions, beforeImage) {
542
+ function createSqlDeletions( deletions, beforeImage ) {
544
543
  const result = [];
545
544
  forEach(deletions, name => result.push({ name: getFileName(name, beforeImage), suffix: '.hdbtable' }));
546
545
  return result;
@@ -552,7 +551,7 @@ function createSqlDeletions(deletions, beforeImage) {
552
551
  * @param {CSN.Model} afterImage CSN used to create correct file names in result structure.
553
552
  * @returns {object[]} Array of objects, each having: name, suffix and changeset.
554
553
  */
555
- function createSqlMigrations(migrations, afterImage) {
554
+ function createSqlMigrations( migrations, afterImage ) {
556
555
  const result = [];
557
556
  forEach(migrations, (name, changeset) => result.push({ name: getFileName(name, afterImage), suffix: '.hdbmigrationtable', changeset }));
558
557
  return result;
@@ -569,15 +568,13 @@ sql.migration = sqlMigration;
569
568
  * @param {HdbcdsOptions} [options={}] Options
570
569
  * @returns {HDBCDS} { <filename>:<content>, ...}
571
570
  */
572
- function hdbcds(csn, options = {}) {
573
- timetrace.timetrace.start('to.hdbcds');
571
+ function hdbcds( csn, options = {} ) {
574
572
  const internalOptions = prepareOptions.to.hdbcds(options);
575
573
  internalOptions.transformation = 'hdbcds';
576
574
 
577
575
  const hanaCsn = forHdbcds(csn, internalOptions);
578
576
 
579
577
  const result = flattenResultStructure(toHdbcdsSource(hanaCsn, internalOptions));
580
- timetrace.timetrace.stop();
581
578
  return result;
582
579
  }
583
580
  /**
@@ -587,7 +584,7 @@ function hdbcds(csn, options = {}) {
587
584
  * @param {ODataOptions} [options={}] Options
588
585
  * @returns {edm} The JSON representation of the service
589
586
  */
590
- function edm(csn, options = {}) {
587
+ function edm( csn, options = {} ) {
591
588
  // If not provided at all, set service to undefined to trigger validation
592
589
  const internalOptions = prepareOptions.to.edm(
593
590
  // eslint-disable-next-line comma-dangle
@@ -617,7 +614,7 @@ edm.all = edmall;
617
614
  * @param {ODataOptions} [options={}] Options
618
615
  * @returns {edms} { <service>:<JSON representation>, ...}
619
616
  */
620
- function edmall(csn, options = {}) {
617
+ function edmall( csn, options = {} ) {
621
618
  const internalOptions = prepareOptions.to.edm(options);
622
619
  const { error } = messages.makeMessageFunction(csn, internalOptions, 'for.odata');
623
620
 
@@ -647,7 +644,7 @@ function edmall(csn, options = {}) {
647
644
  * @param {ODataOptions} [options={}] Options
648
645
  * @returns {edmx} The XML representation of the service
649
646
  */
650
- function edmx(csn, options = {}) {
647
+ function edmx( csn, options = {} ) {
651
648
  // If not provided at all, set service to undefined to trigger validation
652
649
  const internalOptions = prepareOptions.to.edmx(
653
650
  // eslint-disable-next-line comma-dangle
@@ -678,7 +675,7 @@ edmx.all = edmxall;
678
675
  * @param {ODataOptions} [options={}] Options
679
676
  * @returns {edmxs} { <service>:<XML representation>, ...}
680
677
  */
681
- function edmxall(csn, options = {}) {
678
+ function edmxall( csn, options = {} ) {
682
679
  const internalOptions = prepareOptions.to.edmx(options);
683
680
 
684
681
  const result = {};
@@ -710,11 +707,11 @@ function edmxall(csn, options = {}) {
710
707
  * @param {ODataOptions} options OData / EDMX specific options.
711
708
  * @returns {object} Rendered EDMX string for the given service.
712
709
  */
713
- function preparedCsnToEdmx(csn, service, options) {
714
- const e = csn2edm(csn, service, options);
715
- return {
716
- edmx: (e ? e.toXML('all') : undefined),
717
- };
710
+ function preparedCsnToEdmx( csn, service, options ) {
711
+ timetrace.timetrace.start('EDMX rendering');
712
+ const e = csn2edm(csn, service, options)?.toXML('all');
713
+ timetrace.timetrace.stop('EDMX rendering');
714
+ return { edmx: e };
718
715
  }
719
716
 
720
717
  /**
@@ -725,14 +722,13 @@ function preparedCsnToEdmx(csn, service, options) {
725
722
  * @param {ODataOptions} options OData / EDMX specific options.
726
723
  * @returns {object} Dictionary of rendered EDMX strings for each service.
727
724
  */
728
- function preparedCsnToEdmxAll(csn, options) {
725
+ function preparedCsnToEdmxAll( csn, options ) {
726
+ timetrace.timetrace.start('EDMX all rendering');
729
727
  const edmxResult = csn2edmAll(csn, options);
730
728
  for (const service in edmxResult)
731
729
  edmxResult[service] = edmxResult[service].toXML('all');
732
-
733
- return {
734
- edmx: edmxResult,
735
- };
730
+ timetrace.timetrace.stop('EDMX all rendering');
731
+ return { edmx: edmxResult };
736
732
  }
737
733
 
738
734
  /**
@@ -744,13 +740,13 @@ function preparedCsnToEdmxAll(csn, options) {
744
740
  * @param {ODataOptions} options OData / EDMX specific options.
745
741
  * @returns {object} Rendered EDM JSON object for of the given service.
746
742
  */
747
- function preparedCsnToEdm(csn, service, options) {
743
+ function preparedCsnToEdm( csn, service, options ) {
744
+ timetrace.timetrace.start('EDM rendering');
748
745
  // Override OData version as edm json is always v4
749
746
  options.odataVersion = 'v4';
750
- const e = csn2edm(csn, service, options);
751
- return {
752
- edmj: (e ? e.toJSON() : undefined),
753
- };
747
+ const e = csn2edm(csn, service, options)?.toJSON();
748
+ timetrace.timetrace.stop('EDM rendering');
749
+ return { edmj: e };
754
750
  }
755
751
 
756
752
  /**
@@ -761,13 +757,14 @@ function preparedCsnToEdm(csn, service, options) {
761
757
  * @param {ODataOptions} options OData / EDMX specific options.
762
758
  * @returns {object} Dictionary of rendered EDM JSON objects for each service.
763
759
  */
764
- function preparedCsnToEdmAll(csn, options) {
760
+ function preparedCsnToEdmAll( csn, options ) {
761
+ timetrace.timetrace.start('EDM all rendering');
765
762
  // Override OData version as edm json is always v4
766
763
  options.odataVersion = 'v4';
767
764
  const edmj = csn2edmAll(csn, options);
768
765
  for (const service in edmj)
769
766
  edmj[service] = edmj[service].toJSON();
770
-
767
+ timetrace.timetrace.stop('EDM all rendering');
771
768
  return {
772
769
  edmj,
773
770
  };
@@ -782,7 +779,7 @@ function preparedCsnToEdmAll(csn, options) {
782
779
  * @param {object} toProcess { <type>: { <name>:<content>, ...}, <type>: ...}
783
780
  * @returns {object} { <name.type>:<content> }
784
781
  */
785
- function flattenResultStructure(toProcess) {
782
+ function flattenResultStructure( toProcess ) {
786
783
  const result = {};
787
784
  forEach(toProcess, (fileType, artifacts) => {
788
785
  if (fileType === 'messages')
@@ -849,9 +846,14 @@ function publishCsnProcessor( processor, _name ) {
849
846
  checkRemovedDeprecatedFlags( options, messageFunctions );
850
847
  }
851
848
  checkOutdatedOptions( options );
852
- return processor( csn, options, ...args );
849
+
850
+ timetrace.timetrace.start(_name);
851
+ const result = processor( csn, options, ...args );
852
+ timetrace.timetrace.stop(_name);
853
+ return result;
853
854
  }
854
855
  catch (err) {
856
+ timetrace.timetrace.reset('Exception in backend triggered');
855
857
  if (err instanceof messages.CompilationError || options.noRecompile || isPreTransformed(csn, 'odata')) // we cannot recompile a pre-transformed CSN
856
858
  throw err;
857
859
 
@@ -882,7 +884,7 @@ const oldBackendOptionNames = [ 'toSql', 'toOdata', 'toHana', 'forHana' ];
882
884
  *
883
885
  * @param {CSN.Options} options Backend options
884
886
  */
885
- function checkOutdatedOptions(options) {
887
+ function checkOutdatedOptions( options ) {
886
888
  const { error, throwWithError } = messages.makeMessageFunction(null, options, 'api');
887
889
 
888
890
  // This error has been emitted once, we don't need to emit it again.
@@ -920,7 +922,7 @@ function checkOutdatedOptions(options) {
920
922
  * @param {string} moduleName Name of the module to load - like with require
921
923
  * @returns {object} A Proxy that handles the on-demand loading
922
924
  */
923
- function lazyload(moduleName) {
925
+ function lazyload( moduleName ) {
924
926
  let module;
925
927
  return new Proxy(((...args) => {
926
928
  if (!module) // eslint-disable-next-line global-require
@@ -15,6 +15,7 @@ const publicOptionsNewAPI = [
15
15
  'severities',
16
16
  'messages',
17
17
  'withLocations',
18
+ 'structXpr',
18
19
  'defaultBinaryLength',
19
20
  'defaultStringLength',
20
21
  'csnFlavor',
@@ -30,6 +31,7 @@ const publicOptionsNewAPI = [
30
31
  'odataVersion',
31
32
  'odataFormat',
32
33
  'odataContainment',
34
+ 'odataCapabilitiesPullup',
33
35
  'odataForeignKeys',
34
36
  'odataProxies',
35
37
  'odataXServiceRefs',
@@ -75,8 +77,8 @@ const overallOptions = publicOptionsNewAPI.concat(privateOptions);
75
77
  * @param {string} moduleName The called module, e.g. 'for.odata', 'to.hdi'. Needed to initialize the message functions
76
78
  * @returns {TranslatedOptions} General cds options
77
79
  */
78
- function translateOptions(input = {}, defaults = {}, hardRequire = {},
79
- customValidators = {}, combinationValidators = [], moduleName = '') {
80
+ function translateOptions( input = {}, defaults = {}, hardRequire = {},
81
+ customValidators = {}, combinationValidators = [], moduleName = '' ) {
80
82
  const options = Object.assign({}, defaults);
81
83
  for (const name of overallOptions) {
82
84
  // Ensure that arrays are not passed as a reference!
@@ -31,7 +31,7 @@ const booleanValidator = {
31
31
  * @param {any} availableValues Available values
32
32
  * @returns {Validator} Return a validator for a string in an expected range
33
33
  */
34
- function generateStringValidator(availableValues) {
34
+ function generateStringValidator( availableValues ) {
35
35
  return {
36
36
  validate: val => typeof val === 'string' && availableValues.some( av => av.toLowerCase() === val.toLowerCase() ),
37
37
  expected: (val) => {
@@ -152,7 +152,7 @@ const allCombinationValidators = {
152
152
  * @returns {void}
153
153
  * @throws {CompilationError} Throws in case of invalid option usage
154
154
  */
155
- function validate(options, moduleName, customValidators = {}, combinationValidators = []) {
155
+ function validate( options, moduleName, customValidators = {}, combinationValidators = [] ) {
156
156
  // TODO: issuing messages in this function looks very strange...
157
157
  {
158
158
  const messageCollector = { messages: [] };
@@ -7,10 +7,9 @@
7
7
  * @param {object} obj
8
8
  * @param {...any} symbols
9
9
  */
10
- function cleanSymbols(obj, ...symbols) {
11
- for (const symbol of symbols) {
10
+ function cleanSymbols( obj, ...symbols ) {
11
+ for (const symbol of symbols)
12
12
  delete obj[symbol];
13
- }
14
13
  }
15
14
 
16
15
  module.exports = {
@@ -20,7 +20,7 @@ function dictAdd( dict, name, entry, duplicateCallback ) {
20
20
  }
21
21
  found.$duplicates.push( entry );
22
22
  if (Array.isArray( entry.$duplicates ))
23
- found.$duplicates.push( ...entry.$duplicates )
23
+ found.$duplicates.push( ...entry.$duplicates );
24
24
  else if (duplicateCallback && name) // do not complain with empty name ''
25
25
  duplicateCallback( name, entry.name.location, entry );
26
26
  entry.$duplicates = true;
@@ -48,7 +48,7 @@ function dictForEach( dict, callback ) {
48
48
  // `entry.name.location`. If this is the first duplicate entry and if the
49
49
  // `filename`s are different, call the callback again on `found.name.location`.
50
50
  function dictAddArray( dict, name, entry, messageCallback ) {
51
- var found = dict[name];
51
+ const found = dict[name];
52
52
  if (!found || found.builtin) { // do not replace a builtin definition
53
53
  dict[name] = entry; // also ok if array (redefined)
54
54
  return entry;
@@ -86,12 +86,12 @@ function pushToDict( dict, name, entry ) {
86
86
  if (dict[name])
87
87
  dict[name].push( entry );
88
88
  else
89
- dict[name] = [entry];
89
+ dict[name] = [ entry ];
90
90
  }
91
91
 
92
92
  module.exports = {
93
- dictAdd, dictForEach,
93
+ dictAdd,
94
+ dictForEach,
94
95
  dictAddArray,
95
96
  pushToDict,
96
- }
97
-
97
+ };
package/lib/base/error.js CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
  class CompilerAssertion extends Error {
8
8
  constructor(message) {
9
- super(`cds-compiler assertion failed: ${message}`);
9
+ super(`cds-compiler assertion failed: ${ message }`);
10
10
  }
11
11
  }
12
12
 
@@ -16,7 +16,7 @@ class CompilerAssertion extends Error {
16
16
  */
17
17
  class ModelError extends Error {
18
18
  constructor(message) {
19
- super(`cds-compiler model error: ${message}`);
19
+ super(`cds-compiler model error: ${ message }`);
20
20
  }
21
21
  }
22
22
 
@@ -185,7 +185,7 @@ module.exports = {
185
185
  'WHERE',
186
186
  'WINDOW',
187
187
  'WITH',
188
- 'WITHOUT'
188
+ 'WITHOUT',
189
189
  ],
190
190
  // SAP HANA keywords, used for smart quoting in to-hdi.plain
191
191
  // See './scripts/keywords/hana/generateSqlKeywords.js'
@@ -706,7 +706,7 @@ module.exports = {
706
706
  'WITH',
707
707
  'WITHIN',
708
708
  'XMLTABLE',
709
- 'YEAR'
709
+ 'YEAR',
710
710
  ],
711
711
  // SAP HANA CDS keywords, used for smart quoting in to-hdbcds.plain
712
712
  hdbcds: [
@@ -841,7 +841,7 @@ module.exports = {
841
841
  'WHEN',
842
842
  'WHERE',
843
843
  'WINDOW',
844
- 'WITH'
844
+ 'WITH',
845
845
  ],
846
846
  // H2 keywords, used for smart quoting in to-sql.plain.postgres
847
847
  // Taken from http://www.h2database.com/html/advanced.html#keywords
@@ -945,6 +945,6 @@ module.exports = {
945
945
  'WINDOW',
946
946
  'WITH',
947
947
  'YEAR',
948
- '_ROWID_'
949
- ]
950
- }
948
+ '_ROWID_',
949
+ ],
950
+ };
@@ -39,7 +39,7 @@ function combinedLocation( start, end ) {
39
39
  *
40
40
  * TODO: make this function redundant (XSN sparse locations project)
41
41
  */
42
- function emptyLocation(filename) {
42
+ function emptyLocation( filename ) {
43
43
  return {
44
44
  file: filename,
45
45
  line: 1,
@@ -58,7 +58,7 @@ function emptyLocation(filename) {
58
58
  *
59
59
  * TODO: make this function redundant (XSN sparse locations project)
60
60
  */
61
- function emptyWeakLocation(filename) {
61
+ function emptyWeakLocation( filename ) {
62
62
  return {
63
63
  file: filename,
64
64
  line: 1,
@@ -90,9 +90,9 @@ function locationString( location, normalizeFilename ) {
90
90
  if (!location)
91
91
  return '<???>';
92
92
  const loc = location;
93
- let filename = (loc.file && normalizeFilename)
94
- ? loc.file.replace( /\\/g, '/' )
95
- : loc.file;
93
+ const filename = (loc.file && normalizeFilename)
94
+ ? loc.file.replace( /\\/g, '/' )
95
+ : loc.file;
96
96
  if (!(loc instanceof Object))
97
97
  return loc;
98
98
  if (!loc.line) {
@@ -100,14 +100,13 @@ function locationString( location, normalizeFilename ) {
100
100
  }
101
101
  else if (!loc.endLine) {
102
102
  return (loc.col)
103
- ? `${filename}:${loc.line}:${loc.col}`
104
- : `${filename}:${loc.line}`;
105
- }
106
- else {
107
- return (loc.line === loc.endLine)
108
- ? `${filename}:${loc.line}:${loc.col}-${loc.endCol}`
109
- : `${filename}:${loc.line}.${loc.col}-${loc.endLine}.${loc.endCol}`;
103
+ ? `${ filename }:${ loc.line }:${ loc.col }`
104
+ : `${ filename }:${ loc.line }`;
110
105
  }
106
+
107
+ return (loc.line === loc.endLine)
108
+ ? `${ filename }:${ loc.line }:${ loc.col }-${ loc.endCol }`
109
+ : `${ filename }:${ loc.line }.${ loc.col }-${ loc.endLine }.${ loc.endCol }`;
111
110
  }
112
111
 
113
112
  /**