@sap/cds-compiler 2.13.6 → 2.15.4

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 (78) hide show
  1. package/CHANGELOG.md +128 -4
  2. package/bin/cdsc.js +112 -37
  3. package/lib/api/main.js +20 -22
  4. package/lib/api/options.js +2 -3
  5. package/lib/api/validate.js +6 -6
  6. package/lib/base/message-registry.js +92 -17
  7. package/lib/base/messages.js +85 -64
  8. package/lib/base/optionProcessorHelper.js +19 -0
  9. package/lib/checks/annotationsOData.js +11 -32
  10. package/lib/checks/arrayOfs.js +1 -34
  11. package/lib/checks/validator.js +2 -4
  12. package/lib/compiler/assert-consistency.js +1 -0
  13. package/lib/compiler/base.js +1 -0
  14. package/lib/compiler/builtins.js +11 -0
  15. package/lib/compiler/checks.js +22 -70
  16. package/lib/compiler/define.js +59 -11
  17. package/lib/compiler/extend.js +20 -3
  18. package/lib/compiler/finalize-parse-cdl.js +26 -20
  19. package/lib/compiler/index.js +75 -26
  20. package/lib/compiler/populate.js +6 -5
  21. package/lib/compiler/propagator.js +4 -1
  22. package/lib/compiler/resolve.js +104 -16
  23. package/lib/compiler/shared.js +61 -27
  24. package/lib/compiler/tweak-assocs.js +7 -1
  25. package/lib/edm/annotations/genericTranslation.js +93 -21
  26. package/lib/edm/csn2edm.js +216 -98
  27. package/lib/edm/edm.js +305 -226
  28. package/lib/edm/edmPreprocessor.js +499 -423
  29. package/lib/edm/edmUtils.js +22 -22
  30. package/lib/gen/Dictionary.json +98 -22
  31. package/lib/gen/language.checksum +1 -1
  32. package/lib/gen/language.interp +3 -1
  33. package/lib/gen/languageParser.js +4636 -4368
  34. package/lib/json/csnVersion.js +10 -11
  35. package/lib/json/from-csn.js +3 -2
  36. package/lib/json/to-csn.js +0 -2
  37. package/lib/language/docCommentParser.js +2 -2
  38. package/lib/language/genericAntlrParser.js +47 -2
  39. package/lib/language/language.g4 +59 -27
  40. package/lib/main.d.ts +19 -1
  41. package/lib/main.js +6 -0
  42. package/lib/model/csnRefs.js +33 -6
  43. package/lib/model/csnUtils.js +193 -75
  44. package/lib/model/enrichCsn.js +1 -0
  45. package/lib/model/revealInternalProperties.js +2 -2
  46. package/lib/modelCompare/compare.js +6 -6
  47. package/lib/optionProcessor.js +62 -26
  48. package/lib/render/toCdl.js +844 -679
  49. package/lib/render/toHdbcds.js +189 -243
  50. package/lib/render/toSql.js +180 -198
  51. package/lib/render/utils/common.js +131 -15
  52. package/lib/transform/db/.eslintrc.json +1 -1
  53. package/lib/transform/db/associations.js +2 -2
  54. package/lib/transform/db/constraints.js +3 -1
  55. package/lib/transform/db/expansion.js +15 -10
  56. package/lib/transform/db/flattening.js +95 -68
  57. package/lib/transform/db/transformExists.js +7 -7
  58. package/lib/transform/db/views.js +6 -3
  59. package/lib/transform/forHanaNew.js +43 -26
  60. package/lib/transform/forOdataNew.js +43 -42
  61. package/lib/transform/localized.js +12 -7
  62. package/lib/transform/odata/toFinalBaseType.js +8 -6
  63. package/lib/transform/odata/typesExposure.js +145 -197
  64. package/lib/transform/transformUtilsNew.js +9 -12
  65. package/lib/transform/translateAssocsToJoins.js +5 -1
  66. package/lib/transform/universalCsn/coreComputed.js +5 -3
  67. package/lib/transform/universalCsn/universalCsnEnricher.js +27 -5
  68. package/lib/utils/moduleResolve.js +13 -6
  69. package/package.json +1 -1
  70. package/share/messages/message-explanations.json +2 -1
  71. package/share/messages/syntax-expected-integer.md +37 -0
  72. package/lib/transform/odata/attachPath.js +0 -96
  73. package/lib/transform/odata/expandStructKeysInAssociations.js +0 -59
  74. package/lib/transform/odata/generateForeignKeyElements.js +0 -261
  75. package/lib/transform/odata/referenceFlattener.js +0 -296
  76. package/lib/transform/odata/sortByAssociationDependency.js +0 -105
  77. package/lib/transform/odata/structuralPath.js +0 -72
  78. package/lib/transform/odata/structureFlattener.js +0 -171
package/CHANGELOG.md CHANGED
@@ -7,21 +7,145 @@
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 2.13.6 - 2022-25-03
10
+ ## Version 2.15.4 - 2022-06-09
11
+
12
+ ### Fixed
13
+
14
+ - for.odata:
15
+ + Fix derived type to scalar type resolution with intermediate `many`.
16
+ - to.edm(x):
17
+ + (V4 structured) Fix key paths in combination with `--odata-foreign-keys`.
18
+ + Add `Edm.PrimitiveType` to `@odata.Type`.
19
+ + (V4 JSON) Render constant expressions for `Edm.Stream` and `Edm.Untyped`.
20
+ + Fix a bug in target path calculation for `NavigationPropertyBinding`s to external references.
21
+ + Render inner annotations even if `$value` is missing.
22
+ - Update OData vocabularies 'Common', 'UI'.
23
+
24
+ ## Version 2.15.2 - 2022-05-12
25
+
26
+ ### Fixed
27
+
28
+ - Option `cdsHome` can be used instead of `global.cds.home` to specify the path to `@sap/cds/`.
29
+ - to.edm(x):
30
+ + Set anonymous nested proxy key elements to `Nullable:false` until first named type is reached.
31
+ + Enforce `odata-spec-violation-key-null` on explicit foreign keys of managed primary key associations.
32
+ + Proxies/service cross references are no longer created for associations with arbitrary ON conditions.
33
+ Only managed or `$self` backlink association targets are proxy/service cross reference candidates.
34
+ + Explicit foreign keys of a managed association that are not a primary key in the target are exposed in the the proxy.
35
+ + If an association is primary key, the resulting navigation property is set to `Nullable:false` in structured mode.
36
+
37
+ ## Version 2.15.0 - 2022-05-06
38
+
39
+ ### Added
40
+
41
+ - A new warning is emitted if `excluding` is used without a wildcard, since this does
42
+ not have any effect.
43
+ - All scalar types can now take named arguments, e.g. `MyString(length: 10)`.
44
+ For custom scalar types, one unnamed arguments is interpreted as length, two arguments are interpreted
45
+ as precision and scale, e.g. `MyDecimal(3,3)`.
46
+ - If the type `sap.common.Locale` exists, it will be used as type for the `locale` element
47
+ of generated texts entities. The type must be a `cds.String`.
48
+ - to.cdl: Extend statements (from `extensions`) can now be rendered.
49
+ - Add OData vocabulary 'Hierarchy'.
50
+ - CDL: New associations can be published in queries, e.g. `assoc : Association to Target on assoc.id = id`
51
+
52
+ ### Changed
53
+
54
+ - to.edm(x):
55
+ + perform inbound qualification and spec violation checks as well as most/feasible EDM preprocessing steps
56
+ on requested services only.
57
+ + Open up `@odata { Type, MaxLength, Precision, Scale, SRID }` annotation.
58
+ The annotations behavior is defined as follows:
59
+ + The element/parameter must have a scalar CDS type. The annotation is not applied on named types
60
+ (With the V2 exception where derived type chains terminating in a scalar type are resolved).
61
+ + The value of `@odata.Type` must be a valid `EDM` type for the rendered protocol version.
62
+ + If `@odata.Type` can be applied, all canonic type facets (`MaxLength`, `Precision`, `Scale`, `SRID`) are
63
+ removed from the Edm Node and the new facets `@odata { MaxLength, Precision, Scale, SRID }` are applied.
64
+ Non Edm type conformant facets are ignored (eg. `@odata { Type: 'Edm.Decimal', MaxLength: 10, SRID: 0 }`).
65
+ + Type facet values are not evaluated.
66
+ + V2: Propagate `@Core.MediaType` annotation from stream element to entity type if not set.
67
+ - to.edm: Render constant expressions in short notation.
68
+ - Update OData Vocabularies: 'Common', 'Graph', 'Validation'.
69
+
70
+ ### Fixed
71
+
72
+ - to.cdl:
73
+ + Annotations of elements of action `returns` are now rendered as `annotate` statements.
74
+ + Annotations on columns (query sub-elements) were not always rendered.
75
+ + Doc comments on bound actions were rendered twice.
76
+ + Unapplied annotations for action parameters were not rendered.
77
+ + Unions and joins are correctly put into parentheses.
78
+ + Add parentheses around certain expressions in function bodies that require it, such as `fct((1=1))`.
79
+ - to.edm(x):
80
+ + Fix a bug in top level and derived type `items` exposure leading to undefined type rendering.
81
+ + Fix a naming bug in type exposure leading to false reuse types, disguising invididual type
82
+ modifications (such as annotations, (auto-)redirections, element extensions).
83
+ + Ignore `@Aggregation.default`.
84
+ + Consolidate message texts and formatting.
85
+ + Fix navigation property binding in cross service rendering mode.
86
+ + Remove partner attribute in proxy/cross service navigations.
87
+ - Core engine (function `compile`):
88
+ + Annotations for new columns inside `extend projection` blocks were not used.
89
+ + Extending an unknown select item resulted in a crash.
90
+ + Extending a context/service with columns now correctly emits an error.
91
+ + Unmanaged `redirected to` in queries did not check whether the source is an association.
92
+ - parseCdl: `extend <art> with enum {...}` incorrectly threw a compiler error.
93
+ - API: `compile()` used a synchronous call `fs.realpathSync()` on the input filename array.
94
+ Now the asynchronous `fs.realpath()` is used.
95
+ - On-conditions in localized convenience views may be incorrectly rewritten if an element
96
+ has the same as a localized entity.
97
+ - to.sql/hdi/hdbcds:
98
+ + No referential constraint is generated for an association if its parent
99
+ or target entity are annotated with `@cds.persistence.exists: true`.
100
+ + Fix rendering of virtual elements in subqueries
101
+ + Correctly process subqueries in JOINs
102
+ - to.sql/hdi: Queries with `UNION`, `INTERSECT` and similar in expressions are now enclosed in parentheses.
103
+
104
+ ## Version 2.14.0 - 2022-04-08
105
+
106
+ ### Added
107
+
108
+ - cdsc:
109
+ + `--quiet` can now be used to suppress compiler output, including messages.
110
+ + `--options <file.json>` can be used to load compiler options. A JSON file is expected. Is compatible to CDS `package.json`
111
+ and `.cdsrc.json` by first looking for `cdsc` key in `cds`, then for a `cdsc` key and otherwise uses the full JSON file.
112
+ + `--[error|warn|info|debug] id1,id2` can be used to reclassify specific messages.
113
+ - Add OData Vocabularies: 'DataIntegration', 'JSON'.
114
+
115
+ ### Changed
116
+
117
+ - Update OData Vocabularies: 'UI'.
118
+
119
+ ### Fixed
120
+
121
+ - to.cdl:
122
+ + Delimited identifiers as the last elements of arrays in annotation values are now
123
+ rendered with spaces in between, to avoid accidentally escaping `]`.
124
+ + Identifiers in includes and redirection targets were not quoted if they are reserved keywords.
125
+ - to.edm(x): Correctly rewrite `@Capabilities.ReadRestrictions.ReadByKeyRestrictions` into
126
+ `@Capabilities.NavigationPropertyRestriction` in containment mode.
127
+
128
+ ## Version 2.13.8 - 2022-03-29
129
+
130
+ ### Fixed
131
+
132
+ - to.hdbcds/hdi/sql: Correctly handle `localized` in conjunction with `@cds.persistence.exists` and `@cds.persistence.skip`
133
+
134
+ ## Version 2.13.6 - 2022-03-25
11
135
 
12
136
  ### Fixed
13
137
 
14
138
  - to.hdbcds/hdi/sql: Correctly handle `localized` in conjunction with `@cds.persistence.exists`
15
139
 
16
- ## Version 2.13.4 - 2022-22-03
140
+ ## Version 2.13.4 - 2022-03-22
17
141
 
18
142
  No changes compared to Version 2.13.0; fixes latest NPM tag
19
143
 
20
- ## Version 2.13.2 - 2022-22-03
144
+ ## Version 2.13.2 - 2022-03-22
21
145
 
22
146
  No changes compared to Version 2.13.0; fixes latest NPM tag
23
147
 
24
- ## Version 2.13.0 - 2022-22-03
148
+ ## Version 2.13.0 - 2022-03-22
25
149
 
26
150
  ### Added
27
151
 
package/bin/cdsc.js CHANGED
@@ -44,6 +44,18 @@ class ProcessExitError extends Error {
44
44
  }
45
45
  }
46
46
 
47
+ try {
48
+ cdsc_main();
49
+ }
50
+ catch (err) {
51
+ // This whole try/catch is only here because process.exit does not work in combination with
52
+ // stdout/err - see comment at ProcessExitError
53
+ if (err instanceof ProcessExitError)
54
+ process.exitCode = err.exitCode;
55
+ else
56
+ throw err;
57
+ }
58
+
47
59
  function remapCmdOptions(options, cmdOptions) {
48
60
  if (!cmdOptions)
49
61
  return options;
@@ -73,6 +85,9 @@ function remapCmdOptions(options, cmdOptions) {
73
85
  options.variableReplacements.$user = {};
74
86
  options.variableReplacements.$user.locale = value;
75
87
  break;
88
+ case 'serviceNames':
89
+ options.serviceNames = value.split(',');
90
+ break;
76
91
  default:
77
92
  options[key] = value;
78
93
  }
@@ -80,8 +95,9 @@ function remapCmdOptions(options, cmdOptions) {
80
95
  return options;
81
96
  }
82
97
 
83
- // Parse the command line and translate it into options
84
- try {
98
+ function cdsc_main() {
99
+ // Parse the command line and translate it into options
100
+
85
101
  const cmdLine = optionProcessor.processCmdLine(process.argv);
86
102
  // Deal with '--version' explicitly
87
103
  if (cmdLine.options.version) {
@@ -115,6 +131,11 @@ try {
115
131
  displayUsage(cmdLine.errors, optionProcessor.helpText, 2);
116
132
  }
117
133
 
134
+ if (cmdLine.options.options) {
135
+ if (!loadOptionsFromJson(cmdLine))
136
+ return;
137
+ }
138
+
118
139
  // Default warning level is 2 (info)
119
140
  // FIXME: Is that not set anywhere in the API?
120
141
  if (!cmdLine.options.warning)
@@ -125,11 +146,7 @@ try {
125
146
  cmdLine.options.out = '-';
126
147
 
127
148
  // --cds-home <dir>: modules starting with '@sap/cds/' are searched in <dir>
128
- if (cmdLine.options.cdsHome) {
129
- if (!global.cds)
130
- global.cds = {};
131
- global.cds.home = cmdLine.options.cdsHome;
132
- }
149
+ // -> cmdLine.options.cdsHome is passed down to moduleResolve
133
150
 
134
151
  // Set default command if required
135
152
  cmdLine.command = cmdLine.command || 'toCsn';
@@ -147,8 +164,8 @@ try {
147
164
  if (cmdLine.options.directBackend)
148
165
  validateDirectBackendOption(cmdLine.command, cmdLine.options, cmdLine.args);
149
166
 
150
-
151
- if (cmdLine.options.beta) {
167
+ // If set through CLI (and not options file), `beta` is a string and needs processing.
168
+ if (cmdLine.options.beta && typeof cmdLine.options.beta === 'string') {
152
169
  const features = cmdLine.options.beta.split(',');
153
170
  cmdLine.options.beta = {};
154
171
  features.forEach((val) => {
@@ -156,35 +173,32 @@ try {
156
173
  });
157
174
  }
158
175
 
176
+ const to = cmdLine.options.toSql ? 'toSql' : 'toHana';
159
177
  // remap string values for `assertIntegrity` option to boolean
160
- if (cmdLine.options.assertIntegrity &&
161
- cmdLine.options.assertIntegrity === 'true' ||
162
- cmdLine.options.assertIntegrity === 'false'
178
+ if (cmdLine.options[to] && cmdLine.options[to].assertIntegrity &&
179
+ (cmdLine.options[to].assertIntegrity === 'true' ||
180
+ cmdLine.options[to].assertIntegrity === 'false')
163
181
  )
164
- cmdLine.options.assertIntegrity = cmdLine.options.assertIntegrity === 'true';
182
+ cmdLine.options[to].assertIntegrity = cmdLine.options[to].assertIntegrity === 'true';
165
183
 
166
184
  // Enable all beta-flags if betaMode is set to true
167
185
  if (cmdLine.options.betaMode)
168
186
  cmdLine.options.beta = availableBetaFlags;
169
187
 
170
- if (cmdLine.options.deprecated) {
188
+ // If set through CLI (and not options file), `deprecated` is a string and needs processing.
189
+ if (cmdLine.options.deprecated && typeof cmdLine.options.deprecated === 'string') {
171
190
  const features = cmdLine.options.deprecated.split(',');
172
191
  cmdLine.options.deprecated = {};
173
192
  features.forEach((val) => {
174
193
  cmdLine.options.deprecated[val] = true;
175
194
  });
176
195
  }
196
+
197
+ parseSeverityOptions(cmdLine);
198
+
177
199
  // Do the work for the selected command
178
200
  executeCommandLine(cmdLine.command, cmdLine.options, cmdLine.args);
179
201
  }
180
- catch (err) {
181
- // This whole try/catch is only here because process.exit does not work in combination with
182
- // stdout/err - see comment at ProcessExitError
183
- if (err instanceof ProcessExitError)
184
- process.exitCode = err.exitCode;
185
- else
186
- throw err;
187
- }
188
202
 
189
203
  /**
190
204
  * `--direct-backend` can only be used with certain backends and with certain files.
@@ -230,10 +244,10 @@ function displayUsage(error, helpText, code) {
230
244
  function executeCommandLine(command, options, args) {
231
245
  const normalizeFilename = options.testMode && process.platform === 'win32';
232
246
  const messageLevels = {
233
- Error: 0, Warning: 1, Info: 2, None: 3,
247
+ Error: 0, Warning: 1, Info: 2, Debug: 3,
234
248
  };
235
249
  // All messages are put into the message array, even those which should not
236
- // been displayed (severity 'None')
250
+ // been displayed (severity 'Debug')
237
251
 
238
252
  // Create output directory if necessary
239
253
  if (options.out && options.out !== '-' && !fs.existsSync(options.out))
@@ -329,17 +343,18 @@ function executeCommandLine(command, options, args) {
329
343
  options.toOdata.odataContainment = true;
330
344
  }
331
345
  const csn = options.directBackend ? model : compactModel(model, options);
332
- const odataCsn = main.for.odata(csn, remapCmdOptions(options, options.toOdata));
346
+ const odataOptions = remapCmdOptions(options, options.toOdata);
333
347
  if (options.toOdata && options.toOdata.csn) {
348
+ const odataCsn = main.for.odata(csn, odataOptions);
334
349
  displayNamedCsn(odataCsn, 'odata_csn');
335
350
  }
336
351
  else if (options.toOdata && options.toOdata.json) {
337
- const result = main.to.edm.all(odataCsn, options);
352
+ const result = main.to.edm.all(csn, odataOptions);
338
353
  for (const serviceName in result)
339
354
  writeToFileOrDisplay(options.out, `${serviceName}.json`, result[serviceName]);
340
355
  }
341
356
  else {
342
- const result = main.to.edmx.all(odataCsn, options);
357
+ const result = main.to.edmx.all(csn, odataOptions);
343
358
  for (const serviceName in result)
344
359
  writeToFileOrDisplay(options.out, `${serviceName}.xml`, result[serviceName]);
345
360
  }
@@ -447,7 +462,7 @@ function executeCommandLine(command, options, args) {
447
462
  * @param {CompileMessage[]} messages
448
463
  */
449
464
  function displayMessages( model, messages = options.messages ) {
450
- if (!Array.isArray(messages))
465
+ if (!Array.isArray(messages) || options.quiet)
451
466
  return model;
452
467
 
453
468
  const log = console.error;
@@ -552,6 +567,8 @@ function executeCommandLine(command, options, args) {
552
567
  content = JSON.stringify(content, null, 2);
553
568
 
554
569
  if (dir === '-') {
570
+ if (options.quiet)
571
+ return;
555
572
  if (!omitHeadline) {
556
573
  const sqlTypes = {
557
574
  sql: true, hdbconstraint: true, hdbtable: true, hdbview: true,
@@ -569,15 +586,73 @@ function executeCommandLine(command, options, args) {
569
586
  fs.writeFileSync(path.join(dir, fileName), content);
570
587
  }
571
588
  }
589
+ }
572
590
 
573
- function catchErrors(err) {
574
- // @ts-ignore
575
- if (err instanceof Error && err.hasBeenReported)
576
- return;
577
- console.error( '' );
578
- console.error( 'INTERNAL ERROR:' );
579
- console.error( util.inspect(err, false, null) );
580
- console.error( '' );
581
- process.exitCode = 70;
591
+ function loadOptionsFromJson(cmdLine) {
592
+ try {
593
+ let opt = JSON.parse(fs.readFileSync(cmdLine.options.options, 'utf-8'));
594
+ if (opt.cds)
595
+ opt = opt.cds;
596
+ if (opt.cdsc)
597
+ opt = opt.cdsc;
598
+ Object.assign(cmdLine.options, opt);
599
+ return true;
600
+ }
601
+ catch (e) {
602
+ catchErrors(e);
603
+ return false;
604
+ }
605
+ }
606
+
607
+ function catchErrors(err) {
608
+ // @ts-ignore
609
+ if (err instanceof Error && err.hasBeenReported)
610
+ return;
611
+ console.error( '' );
612
+ console.error( 'INTERNAL ERROR:' );
613
+ console.error( util.inspect(err, false, null) );
614
+ console.error( '' );
615
+ process.exitCode = 70;
616
+ }
617
+
618
+ /**
619
+ * Parses the options `--error` and similar.
620
+ * Sets the dictionary `severities` on the given options.
621
+ *
622
+ * @param {object} options
623
+ */
624
+ function parseSeverityOptions({ options }) {
625
+ if (!options.severities)
626
+ options.severities = Object.create(null);
627
+
628
+ const severityMap = {
629
+ error: 'Error',
630
+ warn: 'Warning',
631
+ info: 'Info',
632
+ debug: 'Debug',
633
+ };
634
+
635
+ // Note: We use a for loop to ensure that the order of the options on the command line is respected, i.e.
636
+ // `--warn id --error id` would lead to `id` being reclassified as an error and not a warning.
637
+ for (const key in options) {
638
+ switch (key) {
639
+ case 'error':
640
+ case 'warn':
641
+ case 'info':
642
+ case 'debug':
643
+ parseSeverityOption(options[key], severityMap[key]);
644
+ break;
645
+ default:
646
+ break;
647
+ }
648
+ }
649
+
650
+ function parseSeverityOption(list, severity) {
651
+ const ids = list.split(',');
652
+ for (let id of ids) {
653
+ id = id.trim();
654
+ if (id)
655
+ options.severities[id] = severity;
656
+ }
582
657
  }
583
658
  }
package/lib/api/main.js CHANGED
@@ -33,9 +33,10 @@ const propertyToCheck = {
33
33
  odata: 'toOdata',
34
34
  };
35
35
 
36
- const { cloneCsn } = require('../model/csnUtils');
36
+ const { cloneCsnNonDict } = require('../model/csnUtils');
37
37
  const { toHdbcdsSource } = require('../render/toHdbcds');
38
38
  const { ModelError } = require('../base/error');
39
+ const { forEach } = require('../utils/objectUtils');
39
40
 
40
41
  const relevantGeneralOptions = [ /* for future generic options */ ];
41
42
  const relevantOdataOptions = [ 'sqlMapping', 'odataFormat' ];
@@ -91,7 +92,7 @@ function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMism
91
92
  // Not able to check
92
93
  return;
93
94
  }
94
- const { error, warning, throwWithError } = makeMessageFunction(csn, options, module);
95
+ const { error, warning, throwWithAnyError } = makeMessageFunction(csn, options, module);
95
96
 
96
97
  for (const name of relevantOptionNames ) {
97
98
  if (options[name] !== csn.meta.options[name])
@@ -103,7 +104,7 @@ function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMism
103
104
  warning('options-mismatch-pretransformed-csn', null, `Expected pre-processed CSN to have option "${ name }" set to "${ options[name] }". Found: "${ csn.meta.options[name] }"`);
104
105
  }
105
106
 
106
- throwWithError();
107
+ throwWithAnyError();
107
108
  }
108
109
 
109
110
  /**
@@ -153,7 +154,7 @@ function odata(csn, options = {}) {
153
154
  */
154
155
  function cdl(csn, externalOptions = {}) {
155
156
  const internalOptions = prepareOptions.to.cdl(externalOptions);
156
- const { result } = backends.toCdlWithCsn(cloneCsn(csn, internalOptions), internalOptions);
157
+ const { result } = backends.toCdlWithCsn(cloneCsnNonDict(csn, internalOptions), internalOptions);
157
158
  return result;
158
159
  }
159
160
  /**
@@ -251,7 +252,7 @@ function hdi(csn, options = {}) {
251
252
  const sqlArtifactsWithCSNNamesToSort = Object.create(null);
252
253
  const sqlArtifactsNotToSort = Object.create(null);
253
254
 
254
- Object.keys(flat).forEach((key) => {
255
+ forEach(flat, (key) => {
255
256
  const artifactNameLikeInCsn = key.replace(/\.[^/.]+$/, '');
256
257
  nameMapping[artifactNameLikeInCsn] = key;
257
258
  if (key.endsWith('.hdbtable') || key.endsWith('.hdbview'))
@@ -269,7 +270,7 @@ function hdi(csn, options = {}) {
269
270
  }, Object.create(null));
270
271
 
271
272
  // now add the not-sorted stuff, like indices
272
- Object.keys(sqlArtifactsNotToSort).forEach((key) => {
273
+ forEach(sqlArtifactsNotToSort, (key) => {
273
274
  sorted[remapName(key, sqlCSN, k => !k.endsWith('.hdbindex'))] = sqlArtifactsNotToSort[key];
274
275
  });
275
276
 
@@ -291,10 +292,10 @@ function hdi(csn, options = {}) {
291
292
  function remapNames(dict, csn, filter) {
292
293
  const result = Object.create(null);
293
294
 
294
- for (const [ key, value ] of Object.entries(dict)) {
295
+ forEach(dict, (key, value) => {
295
296
  const name = remapName(key, csn, filter);
296
297
  result[name] = value;
297
- }
298
+ });
298
299
 
299
300
  return result;
300
301
  }
@@ -396,15 +397,15 @@ function hdiMigration(csn, options, beforeImage) {
396
397
  */
397
398
  function createDefinitions() {
398
399
  const result = [];
399
- for (const [ kind, artifacts ] of Object.entries(hdbkinds)) {
400
+ forEach(hdbkinds, (kind, artifacts) => {
400
401
  const suffix = `.${ kind }`;
401
- for (const [ name, sqlStatement ] of Object.entries(artifacts)) {
402
+ forEach(artifacts, (name, sqlStatement) => {
402
403
  if ( kind !== 'hdbindex' )
403
404
  result.push({ name: getFileName(name, afterImage), suffix, sql: sqlStatement });
404
405
  else
405
406
  result.push({ name, suffix, sql: sqlStatement });
406
- }
407
- }
407
+ });
408
+ });
408
409
  return result;
409
410
  }
410
411
  /**
@@ -414,9 +415,7 @@ function hdiMigration(csn, options, beforeImage) {
414
415
  */
415
416
  function createDeletions() {
416
417
  const result = [];
417
- for (const [ name ] of Object.entries(deletions))
418
- result.push({ name: getFileName(name, beforeImage), suffix: '.hdbtable' });
419
-
418
+ forEach(deletions, name => result.push({ name: getFileName(name, beforeImage), suffix: '.hdbtable' }));
420
419
  return result;
421
420
  }
422
421
  /**
@@ -426,9 +425,7 @@ function hdiMigration(csn, options, beforeImage) {
426
425
  */
427
426
  function createMigrations() {
428
427
  const result = [];
429
- for (const [ name, changeset ] of Object.entries(migrations))
430
- result.push({ name: getFileName(name, afterImage), suffix: '.hdbmigrationtable', changeset });
431
-
428
+ forEach(migrations, (name, changeset) => result.push({ name: getFileName(name, afterImage), suffix: '.hdbmigrationtable', changeset }));
432
429
  return result;
433
430
  }
434
431
  }
@@ -586,12 +583,13 @@ function edmxall(csn, options = {}) {
586
583
  */
587
584
  function flattenResultStructure(toProcess) {
588
585
  const result = {};
589
- for (const [ fileType, artifacts ] of Object.entries(toProcess)) {
586
+ forEach(toProcess, (fileType, artifacts) => {
590
587
  if (fileType === 'messages')
591
- continue;
592
- for (const filename of Object.keys(artifacts))
588
+ return;
589
+ forEach(artifacts, (filename) => {
593
590
  result[`${ filename }.${ fileType }`] = artifacts[filename];
594
- }
591
+ });
592
+ });
595
593
 
596
594
  return result;
597
595
  }
@@ -80,13 +80,12 @@ const overallOptions = publicOptionsNewAPI.concat(privateOptions);
80
80
  function translateOptions(input = {}, defaults = {}, hardRequire = {},
81
81
  customValidators = {}, combinationValidators = [], moduleName = '') {
82
82
  const options = Object.assign({}, defaults);
83
- const inputOptionNames = Object.keys(input);
84
83
  for (const name of overallOptions) {
85
84
  // Ensure that arrays are not passed as a reference!
86
85
  // This caused issues with the way messages are handled in processMessages
87
- if (Array.isArray(input[name]) && inputOptionNames.includes(name))
86
+ if (Array.isArray(input[name]))
88
87
  options[name] = [ ...input[name] ];
89
- else if (inputOptionNames.includes(name))
88
+ else if (Object.hasOwnProperty.call(input, name))
90
89
  options[name] = input[name];
91
90
  }
92
91
 
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { makeMessageFunction } = require('../base/messages');
4
+ const { forEach } = require('../utils/objectUtils');
4
5
 
5
6
  /* eslint-disable arrow-body-style */
6
7
  const booleanValidator = {
@@ -159,16 +160,15 @@ function validate(options, moduleName, customValidators = {}, combinationValidat
159
160
  // TODO: issuing messages in this function looks very strange...
160
161
  {
161
162
  const messageCollector = { messages: [] };
162
- const { error, throwWithError } = makeMessageFunction(null, messageCollector, moduleName);
163
+ const { error, throwWithAnyError } = makeMessageFunction(null, messageCollector, moduleName);
163
164
 
164
- for (const optionName of Object.keys(options)) {
165
- const optionValue = options[optionName];
165
+ forEach(options, (optionName, optionValue) => {
166
166
  const validator = customValidators[optionName] || validators[optionName] || booleanValidator;
167
167
 
168
168
  if (!validator.validate(optionValue))
169
169
  error('invalid-option', null, {}, `Expected option "${ optionName }" to have "${ validator.expected(optionValue) }". Found: "${ validator.found(optionValue) }"`);
170
- }
171
- throwWithError();
170
+ });
171
+ throwWithAnyError();
172
172
  }
173
173
 
174
174
  const message = makeMessageFunction(null, options, moduleName);
@@ -179,7 +179,7 @@ function validate(options, moduleName, customValidators = {}, combinationValidat
179
179
  message[combinationValidator.severity]('invalid-option-combination', null, {}, combinationValidator.getMessage(options));
180
180
  }
181
181
 
182
- message.throwWithError();
182
+ message.throwWithAnyError();
183
183
  }
184
184
  /* eslint-enable jsdoc/no-undefined-types */
185
185