@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
package/CHANGELOG.md CHANGED
@@ -7,6 +7,64 @@
7
7
  Note: `beta` fixes, changes and features are usually not listed in this ChangeLog but [here](doc/CHANGELOG_BETA.md).
8
8
  The compiler behavior concerning `beta` features can change at any time without notice.
9
9
 
10
+ ## Version 3.5.2 - 2022-12-20
11
+
12
+ ### Fixed
13
+
14
+ - to.sql/hdi/hdbcds: Don't process references in actions, as they have no impact on the database - avoids internal errors
15
+
16
+ ## Version 3.5.0 - 2022-12-07
17
+
18
+ ### Added
19
+
20
+ - grammar: `localized` is now allowed in select items as well, to force the creation of convenience views.
21
+ - to.edm(x):
22
+ + Validate annotation values of OASIS/SAP vocabulary term definitions against `@Validation.AllowedValues`.
23
+ + Reveal dangling type references in produced EDM.
24
+ + `@Capabilities` 'pull up' introduced with [3.3.0](#version-330---2022-09-29) must now be switched
25
+ on with option `odataCapabilitiesPullup`.
26
+ - If option `addTextsLanguageAssoc` is set but ignored by the compiler, an info message is emitted.
27
+ This can happen if, e.g., the `sap.common.Languages` entity is missing.
28
+ - Add OData vocabularies 'Offline' and 'PDF'.
29
+
30
+ ### Changed
31
+
32
+ - to.edm(x):
33
+ + Vocabulary references to `Common` and `Core` are added to the generated EDM by default to allow
34
+ usage of these vocabularies in http messages even if the terms are not being used in the EDM itself.
35
+ + API representation of enum types as `@Validation.AllowedValues` has been shifted from `for.odata` to
36
+ `to.edm(x)`. This allows to reuse imported enum types in new APIs.
37
+ + Messages raised from the EDM annotation renderer have been reworked with message id and enhanced message
38
+ position including the annotation under investigation.
39
+ + `@Validation.AllowedValues` annotation as introduced for enum elements with
40
+ [1.44.2](./doc/CHANGELOG_ARCHIVE.md#version-1442---2020-10-09)
41
+ are now always rendered into the API regardless of `@assert.range`.
42
+ - to.cdl: The input CSN is no longer cloned for client-CSN and parseCdl-CSN,
43
+ as the renderer does not modify it.
44
+ - A new warning is emitted if compositions of anonymous aspects are used with the `Association`
45
+ keyword instead of `Composition`. Replace the former with the latter to fix the warning.
46
+
47
+ ### Removed
48
+
49
+ - to.edm(x): 'Empty Schema' warning has been removed.
50
+
51
+ ### Fixed
52
+
53
+ - Enums with a structured base type were accidentally not warned about if used in annotation definitions.
54
+ - for.odata/for.hana: Instead of parenthesising tuple expansion with `()`, put
55
+ newly created expression in a `xpr` expression, if the term has more than one expansion.
56
+ - Annotation on indirect or inferred enum values were sometimes lost
57
+ - to.cdl:
58
+ + Certain keywords of special functions no longer add superfluous parentheses.
59
+ + Extension rendering now supports type extensions as well as `key` for elements.
60
+ + Builtins that clashed names with implicit contexts were not rendered with `cds.` prefix.
61
+ + Unknown artifacts (as can happen in parseCdl-style CSN) are now rendered as `USING` statements.
62
+ + Type extensions in `csn.extensions` (e.g. for `length`) are now rendered.
63
+ - to.edm(x):
64
+ + Fix a bug in type exposure when using `@cds.external` complex types.
65
+ + Don't remove empty `Edm.EntityContainer`.
66
+ + Aspects with actions outside of services are no longer warned about.
67
+ - for.hana: Fix a foreign key replacement bug during association to join translation.
10
68
 
11
69
  ## Version 3.4.4 - 2022-11-25
12
70
 
package/README.md CHANGED
@@ -24,6 +24,7 @@ Or maintain your package.json dependencies as follows:
24
24
  }
25
25
  ```
26
26
 
27
+
27
28
  ## Documentation
28
29
 
29
30
  Please refer to the [official CDS documentation](https://cap.cloud.sap/docs/cds/).
@@ -50,7 +50,7 @@ process.exit(0); // success
50
50
 
51
51
  // --------------------------------------------------------
52
52
 
53
- function modernizeIdentifierStyle(source, filename) {
53
+ function modernizeIdentifierStyle( source, filename ) {
54
54
  const options = { messages: [], attachTokens: true };
55
55
  const messageFunctions = createMessageFunctions( options, 'parse', null );
56
56
 
@@ -82,7 +82,7 @@ function modernizeIdentifierStyle(source, filename) {
82
82
 
83
83
  // -----------------------------------------------
84
84
 
85
- function updateIdent(identToken) {
85
+ function updateIdent( identToken ) {
86
86
  const newIdentText = toNewIdentStyle(identToken.text);
87
87
 
88
88
  if (!identToken.stop)
@@ -96,7 +96,7 @@ function modernizeIdentifierStyle(source, filename) {
96
96
  currentOffset += (newIdentText.length - identToken.text.length);
97
97
  }
98
98
 
99
- function toNewIdentStyle(oldIdentText) {
99
+ function toNewIdentStyle( oldIdentText ) {
100
100
  let ident = oldIdentText.slice(1, oldIdentText.length - 1);
101
101
 
102
102
  // There are only two replacement rules we need to check for:
@@ -116,7 +116,7 @@ function modernizeIdentifierStyle(source, filename) {
116
116
  * @param {string} replaceWith
117
117
  * @return {string}
118
118
  */
119
- function replaceSliceInSource(source, startIndex, endIndex, replaceWith) {
119
+ function replaceSliceInSource( source, startIndex, endIndex, replaceWith ) {
120
120
  return source.substring(0, startIndex) +
121
121
  replaceWith +
122
122
  source.substring(endIndex);
@@ -125,7 +125,7 @@ function replaceSliceInSource(source, startIndex, endIndex, replaceWith) {
125
125
  /**
126
126
  * @param {string} msg
127
127
  */
128
- function exitError(msg) {
128
+ function exitError( msg ) {
129
129
  console.error(msg);
130
130
  usage();
131
131
  process.exit(1);
package/bin/cdsc.js CHANGED
@@ -57,7 +57,7 @@ catch (err) {
57
57
  throw err;
58
58
  }
59
59
 
60
- function remapCmdOptions(options, command) {
60
+ function remapCmdOptions( options, command ) {
61
61
  if (!command || !options[command])
62
62
  return;
63
63
 
@@ -208,7 +208,7 @@ function cdsc_main() {
208
208
  * @param {CSN.Options} options
209
209
  * @param {object} args
210
210
  */
211
- function validateDirectBackendOption(command, options, args) {
211
+ function validateDirectBackendOption( command, options, args ) {
212
212
  if (![ 'toCdl', 'toOdata', 'toHana', 'toCsn', 'toSql' ].includes(command)) {
213
213
  displayUsage(`Option '--direct-backend' can't be used with command '${command}'`,
214
214
  optionProcessor.helpText, 2);
@@ -225,7 +225,7 @@ function validateDirectBackendOption(command, options, args) {
225
225
  }
226
226
 
227
227
  // Display help text 'helpText' and 'error' (if any), then exit with exit code <code>
228
- function displayUsage(error, helpText, code) {
228
+ function displayUsage( error, helpText, code ) {
229
229
  // Display non-error output (like help) to stdout
230
230
  const out = (code === 0 && !error) ? process.stdout : process.stderr;
231
231
  // Display help text first, error at the end (more readable, no scrolling)
@@ -240,7 +240,7 @@ function displayUsage(error, helpText, code) {
240
240
  }
241
241
 
242
242
  // Executes a command line that has been translated to 'command' (what to do), 'options' (how) and 'args' (which files)
243
- function executeCommandLine(command, options, args) {
243
+ function executeCommandLine( command, options, args ) {
244
244
  const normalizeFilename = options.testMode && process.platform === 'win32';
245
245
  const messageLevels = {
246
246
  Error: 0, Warning: 1, Info: 2, Debug: 3,
@@ -428,7 +428,7 @@ function executeCommandLine(command, options, args) {
428
428
  console.log(explainMessage(args.messageId));
429
429
  }
430
430
 
431
- function inspect(model) {
431
+ function inspect( model ) {
432
432
  const inspectModel = require('../lib/inspect');
433
433
 
434
434
  if (options.statistics) {
@@ -449,7 +449,7 @@ function executeCommandLine(command, options, args) {
449
449
  // Display error messages in `err` resulting from a compilation. Also set
450
450
  // process.exitCode - process.exit() will force the process to exit as quickly
451
451
  // as possible = is problematic, since console.error() might be asynchronous
452
- function displayErrors(err) {
452
+ function displayErrors( err ) {
453
453
  if (err instanceof main.CompilationError) {
454
454
  if (options.rawOutput)
455
455
  console.error( util.inspect( reveal( err.model, options.rawOutput ), false, null ));
@@ -531,7 +531,7 @@ function executeCommandLine(command, options, args) {
531
531
  // or display it to stdout if 'options.out' is '-'.
532
532
  // Depending on 'options.rawOutput', the model is either compacted to 'name.json' or
533
533
  // written in raw form to '<name>_raw.txt'.
534
- function displayNamedXsn(xsn, name) {
534
+ function displayNamedXsn( xsn, name ) {
535
535
  if (options.rawOutput) {
536
536
  writeToFileOrDisplay(options.out, `${name}_raw.txt`, util.inspect(reveal(xsn, options.rawOutput), false, null), true);
537
537
  }
@@ -552,7 +552,7 @@ function executeCommandLine(command, options, args) {
552
552
  * @param {CSN.Model} csn
553
553
  * @param {string} name
554
554
  */
555
- function displayNamedCsn(csn, name) {
555
+ function displayNamedCsn( csn, name ) {
556
556
  if (!csn) // only print CSN if it is set.
557
557
  return;
558
558
  if (options.internalMsg) {
@@ -570,7 +570,7 @@ function executeCommandLine(command, options, args) {
570
570
  // If 'content' is not a string, JSON-stringify it
571
571
  // If displaying to stdout, prepend a headline containing 'filename', unless 'omitHeadline' is set.
572
572
  // For filenames, illegal characters (slash, backslash, colon) are replaced by '_'.
573
- function writeToFileOrDisplay(dir, fileName, content, omitHeadline = false) {
573
+ function writeToFileOrDisplay( dir, fileName, content, omitHeadline = false ) {
574
574
  if (options.internalMsg)
575
575
  return;
576
576
  fileName = fileName.replace(/[:/\\]/g, '_');
@@ -604,7 +604,7 @@ function executeCommandLine(command, options, args) {
604
604
  }
605
605
  }
606
606
 
607
- function loadOptionsFromJson(cmdLine) {
607
+ function loadOptionsFromJson( cmdLine ) {
608
608
  try {
609
609
  let opt = JSON.parse(fs.readFileSync(cmdLine.options.options, 'utf-8'));
610
610
  if (opt.cds)
@@ -620,7 +620,7 @@ function loadOptionsFromJson(cmdLine) {
620
620
  }
621
621
  }
622
622
 
623
- function catchErrors(err) {
623
+ function catchErrors( err ) {
624
624
  // @ts-ignore
625
625
  if (err instanceof Error && err.hasBeenReported)
626
626
  return;
@@ -663,7 +663,7 @@ function parseSeverityOptions({ options }) {
663
663
  }
664
664
  }
665
665
 
666
- function parseSeverityOption(list, severity) {
666
+ function parseSeverityOption( list, severity ) {
667
667
  const ids = list.split(',');
668
668
  for (let id of ids) {
669
669
  id = id.trim();
@@ -2870,7 +2870,7 @@ Features
2870
2870
 
2871
2871
  Fixes
2872
2872
  * Issue an error, if an association element that is defined in a mixin of the
2873
- same view is explicitly redirected. Up to now this modelling error was not
2873
+ same view is explicitly redirected. Up to now this modeling error was not
2874
2874
  recognized and led to the generation of incorrect HANA CDS models.
2875
2875
  * We now also allow query entities and their elements to use as type, relaxing
2876
2876
  a check introduces with v1.0.26.
@@ -8,7 +8,15 @@ Note: `beta` fixes, changes and features are listed in this ChangeLog just for i
8
8
  The compiler behavior concerning `beta` features can change at any time without notice.
9
9
  **Don't use `beta` fixes, changes and features in productive mode.**
10
10
 
11
- ## Version 3.4.0 - 2022-MM-DD
11
+ ## Version 3.5.0 - 2022-12-07
12
+
13
+ ### Added `odataTerms`
14
+
15
+ Allows to introduce and use new `Edm.Term`s in an OData API
16
+ based on CDS annotations. Annotations must be service members,
17
+ they can't be autoexposed.
18
+
19
+ ## Version 3.4.0 - 2022-10-26
12
20
 
13
21
  ### Added `aspectWithoutElements`
14
22
 
@@ -53,6 +53,8 @@ is `@cds.persistence.exists` copied to localized convenience views.
53
53
 
54
54
  ### Removed `parensAsStrings`
55
55
 
56
+ <!-- fully removed with 3.5.0 -->
57
+
56
58
  ### Removed `projectionAsQuery`
57
59
 
58
60
  ### Removed `redirectInSubQueries`
package/lib/api/main.js CHANGED
@@ -27,15 +27,14 @@ const sqlUtils = lazyload('../render/utils/sql');
27
27
  * @param {CSN.Model} csn SQL transformed model
28
28
  * @returns {string} Name with . replaced as _ in some places
29
29
  */
30
- function getFileName(artifactName, csn) {
30
+ function getFileName( artifactName, csn ) {
31
31
  return csnUtils.getResultingName(csn, 'quoted', artifactName);
32
32
  }
33
33
 
34
- const { cloneCsnNonDict } = require('../model/csnUtils');
35
34
  const { toHdbcdsSource } = require('../render/toHdbcds');
36
35
  const { ModelError } = require('../base/error');
37
36
  const { forEach, forEachKey } = require('../utils/objectUtils');
38
- const { checkRemovedDeprecatedFlags, isBetaEnabled } = require('../base/model');
37
+ const { checkRemovedDeprecatedFlags } = require('../base/model');
39
38
  const { csn2edm, csn2edmAll } = require('../edm/csn2edm');
40
39
 
41
40
  const relevantGeneralOptions = [ /* for future generic options */ ];
@@ -51,8 +50,8 @@ const warnAboutMismatchOdata = [ 'odataVersion' ];
51
50
  * @param {string[]} relevantOptionNames Option names that are defining characteristics
52
51
  * @param {string[]} [optionalOptionNames=[]] Option names that should be attached as a fyi
53
52
  */
54
- function attachTransformerCharacteristics(csn, transformation, options,
55
- relevantOptionNames, optionalOptionNames = []) {
53
+ function attachTransformerCharacteristics( csn, transformation, options,
54
+ relevantOptionNames, optionalOptionNames = [] ) {
56
55
  const relevant = {};
57
56
  for (const name of relevantOptionNames ) {
58
57
  if (options[name] !== undefined)
@@ -86,7 +85,7 @@ function attachTransformerCharacteristics(csn, transformation, options,
86
85
  * @param {string[]} warnAboutMismatch Option names to warn about, but not error on
87
86
  * @param {string} module Name of the module that calls this function, e.g. `for.odata`
88
87
  */
89
- function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMismatch, module) {
88
+ function checkPreTransformedCsn( csn, options, relevantOptionNames, warnAboutMismatch, module ) {
90
89
  if (!csn.meta) {
91
90
  // Not able to check
92
91
  return;
@@ -94,7 +93,7 @@ function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMism
94
93
  const { error, warning, throwWithAnyError } = messages.makeMessageFunction(csn, options, module);
95
94
 
96
95
  for (const name of relevantOptionNames ) {
97
- if (options[name] !== csn.meta.options[name]) {
96
+ if (options[name] !== csn.meta.options?.[name]) {
98
97
  error('wrong-pretransformed-csn', null, { prop: name, value: options[name], othervalue: csn.meta.options[name] },
99
98
  'Expected pre-processed CSN to have option $(PROP) set to $(VALUE). Found: $(OTHERVALUE)');
100
99
  }
@@ -119,7 +118,7 @@ function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMism
119
118
  * @param {string} transformation Name of the transformation
120
119
  * @returns {boolean} Return true if it is pre-transformed
121
120
  */
122
- function isPreTransformed(csn, transformation) {
121
+ function isPreTransformed( csn, transformation ) {
123
122
  return csn && csn.meta && csn.meta.transformation === transformation;
124
123
  }
125
124
 
@@ -130,7 +129,7 @@ function isPreTransformed(csn, transformation) {
130
129
  * @param {object} internalOptions processed options
131
130
  * @returns {object} Return an oData-pre-processed CSN
132
131
  */
133
- function odataInternal(csn, internalOptions) {
132
+ function odataInternal( csn, internalOptions ) {
134
133
  const oDataCsn = forOdataNew.transform4odataWithCsn(csn, internalOptions);
135
134
  attachTransformerCharacteristics(oDataCsn, 'odata', internalOptions, relevantOdataOptions, warnAboutMismatchOdata);
136
135
  return oDataCsn;
@@ -143,7 +142,7 @@ function odataInternal(csn, internalOptions) {
143
142
  * @param {ODataOptions} [options={}] Options
144
143
  * @returns {oDataCSN} Return an oData-pre-processed CSN
145
144
  */
146
- function odata(csn, options = {}) {
145
+ function odata( csn, options = {} ) {
147
146
  const internalOptions = prepareOptions.for.odata(options);
148
147
  return odataInternal(csn, internalOptions);
149
148
  }
@@ -155,9 +154,9 @@ function odata(csn, options = {}) {
155
154
  * @param {object} [externalOptions={}] Options
156
155
  * @returns {object} { model: string, namespace: string }
157
156
  */
158
- function cdl(csn, externalOptions = {}) {
157
+ function cdl( csn, externalOptions = {} ) {
159
158
  const internalOptions = prepareOptions.to.cdl(externalOptions);
160
- return toCdl.csnToCdl(cloneCsnNonDict(csn, internalOptions), internalOptions);
159
+ return toCdl.csnToCdl(csn, internalOptions);
161
160
  }
162
161
 
163
162
  /**
@@ -168,7 +167,7 @@ function cdl(csn, externalOptions = {}) {
168
167
  * @returns {CSN.Model} CSN transformed like to.sql
169
168
  * @private
170
169
  */
171
- function forSql(csn, options = {}) {
170
+ function forSql( csn, options = {} ) {
172
171
  const internalOptions = prepareOptions.to.sql(options);
173
172
  internalOptions.transformation = 'sql';
174
173
  const transformedCsn = forRelationalDB.transformForRelationalDBWithCsn(csn, internalOptions, 'to.sql');
@@ -183,7 +182,7 @@ function forSql(csn, options = {}) {
183
182
  * @returns {CSN.Model} CSN transformed like to.hdi
184
183
  * @private
185
184
  */
186
- function forHdi(csn, options = {}) {
185
+ function forHdi( csn, options = {} ) {
187
186
  const internalOptions = prepareOptions.to.hdi(options);
188
187
  internalOptions.transformation = 'sql';
189
188
  const transformedCsn = forRelationalDB.transformForRelationalDBWithCsn(csn, internalOptions, 'to.hdi');
@@ -198,7 +197,7 @@ function forHdi(csn, options = {}) {
198
197
  * @returns {CSN.Model} CSN transformed like to.hdbcds
199
198
  * @private
200
199
  */
201
- function forHdbcds(csn, options = {}) {
200
+ function forHdbcds( csn, options = {} ) {
202
201
  const internalOptions = prepareOptions.to.hdbcds(options);
203
202
  internalOptions.transformation = 'hdbcds';
204
203
 
@@ -214,7 +213,7 @@ function forHdbcds(csn, options = {}) {
214
213
  * @param {SqlOptions} [options={}] Options
215
214
  * @returns {SQL[]} Array of SQL statements, tables first, views second
216
215
  */
217
- function sql(csn, options = {}) {
216
+ function sql( csn, options = {} ) {
218
217
  const internalOptions = prepareOptions.to.sql(options);
219
218
  internalOptions.transformation = 'sql';
220
219
 
@@ -244,7 +243,7 @@ function sql(csn, options = {}) {
244
243
  * multiple statements concatenated as a multi-line string in case the change e.g.
245
244
  * consists of a column drop and add).
246
245
  */
247
- function mtx(csn, deltaCsn, options = {}) {
246
+ function mtx( csn, deltaCsn, options = {} ) {
248
247
  if (!baseModel.isBetaEnabled(options, 'to.mtx'))
249
248
  throw new Error('to.mtx is only available with beta flag `to.mtx`');
250
249
 
@@ -278,7 +277,7 @@ function mtx(csn, deltaCsn, options = {}) {
278
277
  * @param {HdiOptions} [options={}] Options
279
278
  * @returns {HDIArtifacts} { <filename>:<content>, ...}
280
279
  */
281
- function hdi(csn, options = {}) {
280
+ function hdi( csn, options = {} ) {
282
281
  const internalOptions = prepareOptions.to.hdi(options);
283
282
 
284
283
  // we need the CSN for view sorting
@@ -334,7 +333,7 @@ function hdi(csn, options = {}) {
334
333
  * @param {Function} filter Filter for keys not to remap
335
334
  * @returns {object} New result structure
336
335
  */
337
- function remapNames(dict, csn, filter) {
336
+ function remapNames( dict, csn, filter ) {
338
337
  const result = Object.create(null);
339
338
 
340
339
  forEach(dict, (key, value) => {
@@ -354,7 +353,7 @@ function remapNames(dict, csn, filter) {
354
353
  * @param {Function} filter Filter for keys not to remap
355
354
  * @returns {string} Remapped filename
356
355
  */
357
- function remapName(key, csn, filter = () => true) {
356
+ function remapName( key, csn, filter = () => true ) {
358
357
  if (filter(key)) {
359
358
  const lastDot = key.lastIndexOf('.');
360
359
  const prefix = key.slice(0, lastDot);
@@ -380,13 +379,10 @@ function remapName(key, csn, filter = () => true) {
380
379
  * - drops: An array of SQL statements to drop views/tables
381
380
  * - createsAndAlters: An array of SQL statements to ALTER/CREATE tables/views
382
381
  */
383
- function sqlMigration(csn, options, beforeImage) {
382
+ function sqlMigration( csn, options, beforeImage ) {
384
383
  const internalOptions = prepareOptions.to.sql(options);
385
384
  const { error, throwWithError } = messages.makeMessageFunction(csn, options, 'to.sql.migration');
386
385
 
387
- if (!isBetaEnabled(internalOptions, 'sqlMigration'))
388
- throw new Error('Function `to.sql.migration` requires beta-flag `sqlMigration`');
389
-
390
386
  // Prepare after-image.
391
387
  const afterImage = forSql(csn, options);
392
388
  // Compare both images.
@@ -399,12 +395,12 @@ function sqlMigration(csn, options, beforeImage) {
399
395
  Object.entries(diff.deletions).forEach(entry => diffFilterObj.deletion(entry, error));
400
396
  }
401
397
 
402
- const identifierUtils = sqlUtils.getIdentifierUtils(internalOptions);
398
+ const identifierUtils = sqlUtils.getIdentifierUtils(csn, internalOptions);
403
399
 
404
400
  const drops = {
405
401
  creates: {},
406
402
  final: Object.entries(diff.deletions).reduce((previous, [ name, artifact ]) => {
407
- previous[name] = `DROP ${ (artifact.query || artifact.projection) ? 'VIEW' : 'TABLE' } ${ identifierUtils.quoteSqlId(artifact['@cds.persistence.name']) };`;
403
+ previous[name] = `DROP ${ (artifact.query || artifact.projection) ? 'VIEW' : 'TABLE' } ${ identifierUtils.renderArtifactName(name) };`;
408
404
  return previous;
409
405
  }, {}),
410
406
  };
@@ -420,7 +416,7 @@ function sqlMigration(csn, options, beforeImage) {
420
416
  (diffArtifact.query || diffArtifact.projection) &&
421
417
  (diffArtifact[modelCompare.isChanged] === true || // we know it changed because we compared two views
422
418
  diffArtifact[modelCompare.isChanged] === undefined)) { // if it was removed in the after, then we don't have the flag
423
- drops.creates[artifactName] = `DROP VIEW ${ identifierUtils.quoteSqlId(diffArtifact['@cds.persistence.name']) };`;
419
+ drops.creates[artifactName] = `DROP VIEW ${ identifierUtils.renderArtifactName(artifactName) };`;
424
420
  } // TODO: What happens with a changed kind -> entity becomes a view?
425
421
  else if (diffArtifact &&
426
422
  diffArtifact['@cds.persistence.skip'] !== true &&
@@ -492,7 +488,7 @@ function sqlMigration(csn, options, beforeImage) {
492
488
  * is known, i.e. for the very first migration step
493
489
  * @returns {migration} The migration result
494
490
  */
495
- function hdiMigration(csn, options, beforeImage) {
491
+ function hdiMigration( csn, options, beforeImage ) {
496
492
  const internalOptions = prepareOptions.to.hdi(options);
497
493
 
498
494
  // Prepare after-image.
@@ -523,7 +519,7 @@ function hdiMigration(csn, options, beforeImage) {
523
519
  * @param {CSN.Model} afterImage CSN, used to create correct file names in result structure.
524
520
  * @returns {object[]} Array of objects, each having: name, suffix and sql
525
521
  */
526
- function createSqlDefinitions(hdbkinds, afterImage) {
522
+ function createSqlDefinitions( hdbkinds, afterImage ) {
527
523
  const result = [];
528
524
  forEach(hdbkinds, (kind, artifacts) => {
529
525
  const suffix = `.${ kind }`;
@@ -543,7 +539,7 @@ function createSqlDefinitions(hdbkinds, afterImage) {
543
539
  * @param {CSN.Model} beforeImage CSN used to create correct file names in result structure.
544
540
  * @returns {object[]} Array of objects, each having: name and suffix - only .hdbtable as suffix for now
545
541
  */
546
- function createSqlDeletions(deletions, beforeImage) {
542
+ function createSqlDeletions( deletions, beforeImage ) {
547
543
  const result = [];
548
544
  forEach(deletions, name => result.push({ name: getFileName(name, beforeImage), suffix: '.hdbtable' }));
549
545
  return result;
@@ -555,7 +551,7 @@ function createSqlDeletions(deletions, beforeImage) {
555
551
  * @param {CSN.Model} afterImage CSN used to create correct file names in result structure.
556
552
  * @returns {object[]} Array of objects, each having: name, suffix and changeset.
557
553
  */
558
- function createSqlMigrations(migrations, afterImage) {
554
+ function createSqlMigrations( migrations, afterImage ) {
559
555
  const result = [];
560
556
  forEach(migrations, (name, changeset) => result.push({ name: getFileName(name, afterImage), suffix: '.hdbmigrationtable', changeset }));
561
557
  return result;
@@ -572,15 +568,13 @@ sql.migration = sqlMigration;
572
568
  * @param {HdbcdsOptions} [options={}] Options
573
569
  * @returns {HDBCDS} { <filename>:<content>, ...}
574
570
  */
575
- function hdbcds(csn, options = {}) {
576
- timetrace.timetrace.start('to.hdbcds');
571
+ function hdbcds( csn, options = {} ) {
577
572
  const internalOptions = prepareOptions.to.hdbcds(options);
578
573
  internalOptions.transformation = 'hdbcds';
579
574
 
580
575
  const hanaCsn = forHdbcds(csn, internalOptions);
581
576
 
582
577
  const result = flattenResultStructure(toHdbcdsSource(hanaCsn, internalOptions));
583
- timetrace.timetrace.stop();
584
578
  return result;
585
579
  }
586
580
  /**
@@ -590,7 +584,7 @@ function hdbcds(csn, options = {}) {
590
584
  * @param {ODataOptions} [options={}] Options
591
585
  * @returns {edm} The JSON representation of the service
592
586
  */
593
- function edm(csn, options = {}) {
587
+ function edm( csn, options = {} ) {
594
588
  // If not provided at all, set service to undefined to trigger validation
595
589
  const internalOptions = prepareOptions.to.edm(
596
590
  // eslint-disable-next-line comma-dangle
@@ -620,7 +614,7 @@ edm.all = edmall;
620
614
  * @param {ODataOptions} [options={}] Options
621
615
  * @returns {edms} { <service>:<JSON representation>, ...}
622
616
  */
623
- function edmall(csn, options = {}) {
617
+ function edmall( csn, options = {} ) {
624
618
  const internalOptions = prepareOptions.to.edm(options);
625
619
  const { error } = messages.makeMessageFunction(csn, internalOptions, 'for.odata');
626
620
 
@@ -650,7 +644,7 @@ function edmall(csn, options = {}) {
650
644
  * @param {ODataOptions} [options={}] Options
651
645
  * @returns {edmx} The XML representation of the service
652
646
  */
653
- function edmx(csn, options = {}) {
647
+ function edmx( csn, options = {} ) {
654
648
  // If not provided at all, set service to undefined to trigger validation
655
649
  const internalOptions = prepareOptions.to.edmx(
656
650
  // eslint-disable-next-line comma-dangle
@@ -681,7 +675,7 @@ edmx.all = edmxall;
681
675
  * @param {ODataOptions} [options={}] Options
682
676
  * @returns {edmxs} { <service>:<XML representation>, ...}
683
677
  */
684
- function edmxall(csn, options = {}) {
678
+ function edmxall( csn, options = {} ) {
685
679
  const internalOptions = prepareOptions.to.edmx(options);
686
680
 
687
681
  const result = {};
@@ -713,11 +707,11 @@ function edmxall(csn, options = {}) {
713
707
  * @param {ODataOptions} options OData / EDMX specific options.
714
708
  * @returns {object} Rendered EDMX string for the given service.
715
709
  */
716
- function preparedCsnToEdmx(csn, service, options) {
717
- const e = csn2edm(csn, service, options);
718
- return {
719
- edmx: (e ? e.toXML('all') : undefined),
720
- };
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 };
721
715
  }
722
716
 
723
717
  /**
@@ -728,14 +722,13 @@ function preparedCsnToEdmx(csn, service, options) {
728
722
  * @param {ODataOptions} options OData / EDMX specific options.
729
723
  * @returns {object} Dictionary of rendered EDMX strings for each service.
730
724
  */
731
- function preparedCsnToEdmxAll(csn, options) {
725
+ function preparedCsnToEdmxAll( csn, options ) {
726
+ timetrace.timetrace.start('EDMX all rendering');
732
727
  const edmxResult = csn2edmAll(csn, options);
733
728
  for (const service in edmxResult)
734
729
  edmxResult[service] = edmxResult[service].toXML('all');
735
-
736
- return {
737
- edmx: edmxResult,
738
- };
730
+ timetrace.timetrace.stop('EDMX all rendering');
731
+ return { edmx: edmxResult };
739
732
  }
740
733
 
741
734
  /**
@@ -747,13 +740,13 @@ function preparedCsnToEdmxAll(csn, options) {
747
740
  * @param {ODataOptions} options OData / EDMX specific options.
748
741
  * @returns {object} Rendered EDM JSON object for of the given service.
749
742
  */
750
- function preparedCsnToEdm(csn, service, options) {
743
+ function preparedCsnToEdm( csn, service, options ) {
744
+ timetrace.timetrace.start('EDM rendering');
751
745
  // Override OData version as edm json is always v4
752
746
  options.odataVersion = 'v4';
753
- const e = csn2edm(csn, service, options);
754
- return {
755
- edmj: (e ? e.toJSON() : undefined),
756
- };
747
+ const e = csn2edm(csn, service, options)?.toJSON();
748
+ timetrace.timetrace.stop('EDM rendering');
749
+ return { edmj: e };
757
750
  }
758
751
 
759
752
  /**
@@ -764,13 +757,14 @@ function preparedCsnToEdm(csn, service, options) {
764
757
  * @param {ODataOptions} options OData / EDMX specific options.
765
758
  * @returns {object} Dictionary of rendered EDM JSON objects for each service.
766
759
  */
767
- function preparedCsnToEdmAll(csn, options) {
760
+ function preparedCsnToEdmAll( csn, options ) {
761
+ timetrace.timetrace.start('EDM all rendering');
768
762
  // Override OData version as edm json is always v4
769
763
  options.odataVersion = 'v4';
770
764
  const edmj = csn2edmAll(csn, options);
771
765
  for (const service in edmj)
772
766
  edmj[service] = edmj[service].toJSON();
773
-
767
+ timetrace.timetrace.stop('EDM all rendering');
774
768
  return {
775
769
  edmj,
776
770
  };
@@ -785,7 +779,7 @@ function preparedCsnToEdmAll(csn, options) {
785
779
  * @param {object} toProcess { <type>: { <name>:<content>, ...}, <type>: ...}
786
780
  * @returns {object} { <name.type>:<content> }
787
781
  */
788
- function flattenResultStructure(toProcess) {
782
+ function flattenResultStructure( toProcess ) {
789
783
  const result = {};
790
784
  forEach(toProcess, (fileType, artifacts) => {
791
785
  if (fileType === 'messages')
@@ -852,9 +846,14 @@ function publishCsnProcessor( processor, _name ) {
852
846
  checkRemovedDeprecatedFlags( options, messageFunctions );
853
847
  }
854
848
  checkOutdatedOptions( options );
855
- 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;
856
854
  }
857
855
  catch (err) {
856
+ timetrace.timetrace.reset('Exception in backend triggered');
858
857
  if (err instanceof messages.CompilationError || options.noRecompile || isPreTransformed(csn, 'odata')) // we cannot recompile a pre-transformed CSN
859
858
  throw err;
860
859
 
@@ -885,7 +884,7 @@ const oldBackendOptionNames = [ 'toSql', 'toOdata', 'toHana', 'forHana' ];
885
884
  *
886
885
  * @param {CSN.Options} options Backend options
887
886
  */
888
- function checkOutdatedOptions(options) {
887
+ function checkOutdatedOptions( options ) {
889
888
  const { error, throwWithError } = messages.makeMessageFunction(null, options, 'api');
890
889
 
891
890
  // This error has been emitted once, we don't need to emit it again.
@@ -923,7 +922,7 @@ function checkOutdatedOptions(options) {
923
922
  * @param {string} moduleName Name of the module to load - like with require
924
923
  * @returns {object} A Proxy that handles the on-demand loading
925
924
  */
926
- function lazyload(moduleName) {
925
+ function lazyload( moduleName ) {
927
926
  let module;
928
927
  return new Proxy(((...args) => {
929
928
  if (!module) // eslint-disable-next-line global-require