@sap/cds-compiler 2.4.4 → 2.10.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 (106) hide show
  1. package/CHANGELOG.md +241 -1
  2. package/bin/.eslintrc.json +17 -0
  3. package/bin/cds_update_identifiers.js +8 -7
  4. package/bin/cdsc.js +180 -132
  5. package/bin/cdshi.js +18 -11
  6. package/bin/cdsse.js +38 -32
  7. package/bin/cdsv2m.js +8 -7
  8. package/doc/CHANGELOG_BETA.md +36 -1
  9. package/lib/api/main.js +81 -100
  10. package/lib/api/options.js +17 -11
  11. package/lib/api/validate.js +12 -8
  12. package/lib/backends.js +0 -81
  13. package/lib/base/keywords.js +32 -2
  14. package/lib/base/location.js +2 -2
  15. package/lib/base/message-registry.js +66 -4
  16. package/lib/base/messages.js +84 -27
  17. package/lib/base/model.js +2 -61
  18. package/lib/checks/arrayOfs.js +0 -1
  19. package/lib/checks/defaultValues.js +27 -2
  20. package/lib/checks/elements.js +1 -6
  21. package/lib/checks/enricher.js +8 -2
  22. package/lib/checks/foreignKeys.js +0 -6
  23. package/lib/checks/managedWithoutKeys.js +17 -0
  24. package/lib/checks/nonexpandableStructured.js +38 -0
  25. package/lib/checks/onConditions.js +9 -45
  26. package/lib/checks/queryNoDbArtifacts.js +27 -9
  27. package/lib/checks/selectItems.js +25 -2
  28. package/lib/checks/types.js +26 -2
  29. package/lib/checks/unknownMagic.js +38 -0
  30. package/lib/checks/utils.js +61 -0
  31. package/lib/checks/validator.js +66 -13
  32. package/lib/compiler/assert-consistency.js +24 -12
  33. package/lib/compiler/builtins.js +2 -0
  34. package/lib/compiler/checks.js +6 -4
  35. package/lib/compiler/definer.js +101 -39
  36. package/lib/compiler/index.js +88 -59
  37. package/lib/compiler/resolver.js +455 -209
  38. package/lib/compiler/shared.js +57 -33
  39. package/lib/edm/annotations/genericTranslation.js +183 -187
  40. package/lib/edm/csn2edm.js +128 -99
  41. package/lib/edm/edm.js +18 -21
  42. package/lib/edm/edmPreprocessor.js +361 -127
  43. package/lib/edm/edmUtils.js +103 -33
  44. package/lib/gen/Dictionary.json +74 -28
  45. package/lib/gen/language.checksum +1 -1
  46. package/lib/gen/language.interp +18 -4
  47. package/lib/gen/language.tokens +124 -118
  48. package/lib/gen/languageLexer.interp +13 -1
  49. package/lib/gen/languageLexer.js +870 -839
  50. package/lib/gen/languageLexer.tokens +116 -111
  51. package/lib/gen/languageParser.js +5894 -5614
  52. package/lib/json/from-csn.js +152 -67
  53. package/lib/json/to-csn.js +334 -135
  54. package/lib/language/antlrParser.js +4 -3
  55. package/lib/language/errorStrategy.js +1 -0
  56. package/lib/language/genericAntlrParser.js +24 -14
  57. package/lib/language/language.g4 +188 -128
  58. package/lib/main.d.ts +435 -0
  59. package/lib/main.js +31 -7
  60. package/lib/model/api.js +78 -0
  61. package/lib/model/csnRefs.js +463 -187
  62. package/lib/model/csnUtils.js +280 -136
  63. package/lib/model/enrichCsn.js +75 -4
  64. package/lib/model/revealInternalProperties.js +2 -1
  65. package/lib/modelCompare/compare.js +70 -25
  66. package/lib/optionProcessor.js +13 -10
  67. package/lib/render/.eslintrc.json +4 -1
  68. package/lib/render/DuplicateChecker.js +8 -5
  69. package/lib/render/toCdl.js +123 -40
  70. package/lib/render/toHdbcds.js +156 -65
  71. package/lib/render/toSql.js +87 -11
  72. package/lib/render/utils/common.js +55 -9
  73. package/lib/render/utils/sql.js +3 -3
  74. package/lib/sql-identifier.js +6 -1
  75. package/lib/transform/{sql → db}/.eslintrc.json +0 -0
  76. package/lib/transform/{sql → db}/assertUnique.js +7 -8
  77. package/lib/transform/{sql → db}/constraints.js +35 -20
  78. package/lib/transform/db/draft.js +353 -0
  79. package/lib/transform/db/expansion.js +582 -0
  80. package/lib/transform/db/flattening.js +325 -0
  81. package/lib/transform/{sql → db}/groupByOrderBy.js +8 -16
  82. package/lib/transform/{sql → db}/helpers.js +0 -0
  83. package/lib/transform/{sql → db}/transformExists.js +256 -60
  84. package/lib/transform/forHanaNew.js +216 -765
  85. package/lib/transform/forOdataNew.js +60 -56
  86. package/lib/transform/localized.js +48 -26
  87. package/lib/transform/odata/attachPath.js +19 -4
  88. package/lib/transform/odata/expandStructKeysInAssociations.js +2 -2
  89. package/lib/transform/odata/generateForeignKeyElements.js +13 -12
  90. package/lib/transform/odata/referenceFlattener.js +60 -36
  91. package/lib/transform/odata/sortByAssociationDependency.js +4 -4
  92. package/lib/transform/odata/structuralPath.js +76 -0
  93. package/lib/transform/odata/structureFlattener.js +21 -22
  94. package/lib/transform/odata/toFinalBaseType.js +5 -5
  95. package/lib/transform/odata/typesExposure.js +27 -17
  96. package/lib/transform/odata/utils.js +2 -2
  97. package/lib/transform/transformUtilsNew.js +141 -77
  98. package/lib/transform/translateAssocsToJoins.js +17 -14
  99. package/lib/transform/universalCsnEnricher.js +67 -0
  100. package/lib/utils/file.js +0 -11
  101. package/lib/utils/moduleResolve.js +6 -8
  102. package/lib/utils/timetrace.js +6 -1
  103. package/package.json +2 -1
  104. package/lib/base/deepCopy.js +0 -66
  105. package/lib/json/walker.js +0 -26
  106. package/lib/utils/string.js +0 -17
package/bin/cdsc.js CHANGED
@@ -17,15 +17,16 @@
17
17
 
18
18
  const compiler = require('../lib/compiler');
19
19
  const main = require('../lib/main');
20
+ const { for_sql, for_hdi, for_hdbcds } = require('../lib/api/main');
20
21
  const { compactModel } = require('../lib/json/to-csn');
21
- const { toOdataWithCsn, toHanaWithCsn, toSqlWithCsn, toCdlWithCsn, toRenameWithCsn, alterConstraintsWithCsn } = require('../lib/backends');
22
- var util = require('util');
23
- var fs = require('fs');
24
- var path = require('path');
25
- var { reveal } = require('../lib/model/revealInternalProperties');
22
+ const { toRenameWithCsn, alterConstraintsWithCsn } = require('../lib/backends');
23
+ const util = require('util');
24
+ const fs = require('fs');
25
+ const path = require('path');
26
+ const { reveal } = require('../lib/model/revealInternalProperties');
26
27
  const enrichCsn = require('../lib/model/enrichCsn');
27
28
  const { optionProcessor } = require('../lib/optionProcessor');
28
- const { explainMessage, hasMessageExplanation, sortMessages } = require('../lib/base/messages')
29
+ const { explainMessage, hasMessageExplanation, sortMessages } = require('../lib/base/messages');
29
30
  const term = require('../lib/utils/term');
30
31
  const { splitLines } = require('../lib/utils/file');
31
32
  const { addLocalizationViews } = require('../lib/transform/localized');
@@ -35,27 +36,59 @@ const { availableBetaFlags } = require('../lib/base/model');
35
36
  // but that might truncate the output of stdout and stderr, both of which are async (or rather,
36
37
  // may possibly be async, depending on OS and whether I/O goes to TTY, socket, file, ... sigh)
37
38
  class ProcessExitError extends Error {
38
- constructor(exitCode,...args) {
39
+ constructor(exitCode, ...args) {
39
40
  super(...args);
40
41
  this.exitCode = exitCode;
41
42
  }
42
43
  }
43
44
 
45
+ function remapCmdOptions(options, cmdOptions) {
46
+ if (!cmdOptions)
47
+ return options;
48
+
49
+ for (const [ key, value ] of Object.entries(cmdOptions)) {
50
+ switch (key) {
51
+ case 'names':
52
+ options.sqlMapping = value;
53
+ break;
54
+ case 'user':
55
+ if (!options.magicVars)
56
+ options.magicVars = {};
57
+ options.magicVars.user = value;
58
+ break;
59
+ case 'dialect':
60
+ options.sqlDialect = value;
61
+ break;
62
+ case 'version':
63
+ options.odataVersion = value;
64
+ break;
65
+ case 'locale':
66
+ if (!options.magicVars)
67
+ options.magicVars = {};
68
+ options.magicVars.locale = value;
69
+ break;
70
+ default:
71
+ options[key] = value;
72
+ }
73
+ }
74
+ return options;
75
+ }
76
+
44
77
  // Parse the command line and translate it into options
45
78
  try {
46
- let cmdLine = optionProcessor.processCmdLine(process.argv);
79
+ const cmdLine = optionProcessor.processCmdLine(process.argv);
47
80
  // Deal with '--version' explicitly
48
81
  if (cmdLine.options.version) {
49
- process.stdout.write(main.version() + '\n');
82
+ process.stdout.write(`${main.version()}\n`);
50
83
  throw new ProcessExitError(0);
51
84
  }
52
85
  // Deal with '--help' explicitly
53
86
  if (cmdLine.command) {
54
87
  // Command specific help
55
- if (cmdLine.options.help || cmdLine.options[cmdLine.command] && cmdLine.options[cmdLine.command].help) {
88
+ if (cmdLine.options.help || cmdLine.options[cmdLine.command] && cmdLine.options[cmdLine.command].help)
56
89
  displayUsage(null, optionProcessor.commands[cmdLine.command].helpText, 0);
57
- }
58
- } else if (cmdLine.options.help) {
90
+ }
91
+ else if (cmdLine.options.help) {
59
92
  // General help
60
93
  displayUsage(null, optionProcessor.helpText, 0);
61
94
  }
@@ -70,20 +103,21 @@ try {
70
103
  if (cmdLine.cmdErrors.length > 0) {
71
104
  // Command specific errors
72
105
  displayUsage(cmdLine.cmdErrors, optionProcessor.commands[cmdLine.command].helpText, 2);
73
- } else if (cmdLine.errors.length > 0) {
106
+ }
107
+ else if (cmdLine.errors.length > 0) {
74
108
  // General errors
75
109
  displayUsage(cmdLine.errors, optionProcessor.helpText, 2);
76
110
  }
77
111
 
78
112
  // Default warning level is 2 (info)
79
113
  // FIXME: Is that not set anywhere in the API?
80
- if (!cmdLine.options.warning) {
114
+ if (!cmdLine.options.warning)
81
115
  cmdLine.options.warning = 2;
82
- }
116
+
83
117
  // Default output goes to stdout
84
- if (!cmdLine.options.out) {
118
+ if (!cmdLine.options.out)
85
119
  cmdLine.options.out = '-';
86
- }
120
+
87
121
  // --cds-home <dir>: modules starting with '@sap/cds/' are searched in <dir>
88
122
  if (cmdLine.options.cdsHome) {
89
123
  if (!global.cds)
@@ -105,39 +139,43 @@ try {
105
139
  cmdLine.options.parseCdl = true;
106
140
  if (cmdLine.args.files.length > 1) {
107
141
  const err = `'parseCdl' expects exactly one file! ${cmdLine.args.files.length} provided.`;
108
- displayUsage(err, optionProcessor.commands['parseCdl'].helpText, 2);
142
+ displayUsage(err, optionProcessor.commands.parseCdl.helpText, 2);
109
143
  }
110
144
  }
111
145
 
112
- if (cmdLine.options.directBackend) {
146
+ if (cmdLine.options.directBackend)
113
147
  validateDirectBackendOption(cmdLine.command, cmdLine.options, cmdLine.args);
114
- }
148
+
115
149
 
116
150
  if (cmdLine.options.beta) {
117
151
  const features = cmdLine.options.beta.split(',');
118
152
  cmdLine.options.beta = {};
119
- features.forEach((val) => cmdLine.options.beta[val] = true);
153
+ features.forEach((val) => {
154
+ cmdLine.options.beta[val] = true;
155
+ });
120
156
  }
121
157
 
122
158
  // Enable all beta-flags if betaMode is set to true
123
- if(cmdLine.options.betaMode) {
159
+ if (cmdLine.options.betaMode)
124
160
  cmdLine.options.beta = availableBetaFlags;
125
- }
161
+
126
162
  if (cmdLine.options.deprecated) {
127
163
  const features = cmdLine.options.deprecated.split(',');
128
164
  cmdLine.options.deprecated = {};
129
- features.forEach((val) => cmdLine.options.deprecated[val] = true);
165
+ features.forEach((val) => {
166
+ cmdLine.options.deprecated[val] = true;
167
+ });
130
168
  }
131
169
  // Do the work for the selected command
132
170
  executeCommandLine(cmdLine.command, cmdLine.options, cmdLine.args);
133
- } catch (err) {
171
+ }
172
+ catch (err) {
134
173
  // This whole try/catch is only here because process.exit does not work in combination with
135
174
  // stdout/err - see comment at ProcessExitError
136
- if (err instanceof ProcessExitError) {
175
+ if (err instanceof ProcessExitError)
137
176
  process.exitCode = err.exitCode;
138
- } else {
177
+ else
139
178
  throw err;
140
- }
141
179
  }
142
180
 
143
181
  /**
@@ -150,33 +188,32 @@ try {
150
188
  * @param {object} args
151
189
  */
152
190
  function validateDirectBackendOption(command, options, args) {
153
- if (!['toCdl', 'toOdata', 'toHana', 'toCsn', 'toSql'].includes(command)) {
191
+ if (![ 'toCdl', 'toOdata', 'toHana', 'toCsn', 'toSql' ].includes(command)) {
154
192
  displayUsage(`Option '--direct-backend' can't be used with command '${command}'`,
155
- optionProcessor.helpText, 2);
193
+ optionProcessor.helpText, 2);
156
194
  }
157
195
  if (!args.files || args.files.length !== 1) {
158
196
  displayUsage(`Option '--direct-backend' expects exactly one JSON file, but ${args.files.length} given`,
159
- optionProcessor.helpText, 2);
197
+ optionProcessor.helpText, 2);
160
198
  }
161
199
  const filename = args.files[0];
162
200
  if (!filename.endsWith('.csn') && !filename.endsWith('.json')) {
163
- displayUsage(`Option '--direct-backend' expects a filename with a *.csn or *.json suffix`,
164
- optionProcessor.helpText, 2);
201
+ displayUsage('Option \'--direct-backend\' expects a filename with a *.csn or *.json suffix',
202
+ optionProcessor.helpText, 2);
165
203
  }
166
204
  }
167
205
 
168
206
  // Display help text 'helpText' and 'error' (if any), then exit with exit code <code>
169
207
  function displayUsage(error, helpText, code) {
170
208
  // Display non-error output (like help) to stdout
171
- let out = (code === 0 && !error) ? process.stdout : process.stderr;
209
+ const out = (code === 0 && !error) ? process.stdout : process.stderr;
172
210
  // Display help text first, error at the end (more readable, no scrolling)
173
211
  out.write(`${helpText}\n`);
174
212
  if (error) {
175
- if (error instanceof Array) {
176
- out.write(error.map(error => `cdsc: ERROR: ${error}`).join('\n') + '\n');
177
- } else {
213
+ if (error instanceof Array)
214
+ out.write(`${error.map(error => `cdsc: ERROR: ${error}`).join('\n')}\n`);
215
+ else
178
216
  out.write(`cdsc: ERROR: ${error}\n`);
179
- }
180
217
  }
181
218
  throw new ProcessExitError(code);
182
219
  }
@@ -184,14 +221,16 @@ function displayUsage(error, helpText, code) {
184
221
  // Executes a command line that has been translated to 'command' (what to do), 'options' (how) and 'args' (which files)
185
222
  function executeCommandLine(command, options, args) {
186
223
  const normalizeFilename = options.testMode && process.platform === 'win32';
187
- const messageLevels = { Error: 0, Warning: 1, Info: 2, None: 3 };
224
+ const messageLevels = {
225
+ Error: 0, Warning: 1, Info: 2, None: 3,
226
+ };
188
227
  // All messages are put into the message array, even those which should not
189
228
  // been displayed (severity 'None')
190
229
 
191
230
  // Create output directory if necessary
192
- if (options.out && options.out !== '-' && !fs.existsSync(options.out)) {
231
+ if (options.out && options.out !== '-' && !fs.existsSync(options.out))
193
232
  fs.mkdirSync(options.out);
194
- }
233
+
195
234
 
196
235
  // Add implementation functions corresponding to commands here
197
236
  const commands = {
@@ -207,9 +246,9 @@ function executeCommandLine(command, options, args) {
207
246
  explain,
208
247
  };
209
248
 
210
- if (!commands[command] && !commandsWithoutCompilation[command]) {
249
+ if (!commands[command] && !commandsWithoutCompilation[command])
211
250
  throw new Error(`Missing implementation for command ${command}`);
212
- }
251
+
213
252
 
214
253
  if (commandsWithoutCompilation[command]) {
215
254
  commandsWithoutCompilation[command]();
@@ -218,14 +257,14 @@ function executeCommandLine(command, options, args) {
218
257
 
219
258
  options.messages = [];
220
259
 
221
- const fileCache = Object.create(null)
222
- const compiled = options.directBackend ?
223
- util.promisify(fs.readFile)( args.files[0], 'utf-8' ).then((str) => JSON.parse( str )) :
224
- compiler.compileX( args.files, undefined, options, fileCache );
260
+ const fileCache = Object.create(null);
261
+ const compiled = options.directBackend
262
+ ? util.promisify(fs.readFile)( args.files[0], 'utf-8' ).then(str => JSON.parse( str ))
263
+ : compiler.compileX( args.files, undefined, options, fileCache );
225
264
 
226
265
  compiled.then( commands[command] )
227
- .then( displayMessages, displayErrors )
228
- .catch( catchErrors );
266
+ .then( displayMessages, displayErrors )
267
+ .catch( catchErrors );
229
268
 
230
269
  return; // below are only command implementations.
231
270
 
@@ -233,10 +272,10 @@ function executeCommandLine(command, options, args) {
233
272
  // Return the original model (for chaining)
234
273
  function toCdl( model ) {
235
274
  const csn = options.directBackend ? model : compactModel(model, options);
236
- const cdlResult = toCdlWithCsn(csn, options).result;
237
- for (const name in cdlResult) {
238
- writeToFileOrDisplay(options.out, name + '.cds', cdlResult[name]);
239
- }
275
+ const cdlResult = main.to.cdl(csn, remapCmdOptions(options));
276
+ for (const name in cdlResult)
277
+ writeToFileOrDisplay(options.out, `${name}.cds`, cdlResult[name]);
278
+
240
279
  return model;
241
280
  }
242
281
 
@@ -245,7 +284,8 @@ function executeCommandLine(command, options, args) {
245
284
  function toCsn( model ) {
246
285
  if (options.directBackend) {
247
286
  displayNamedCsn(model, 'csn', options);
248
- } else {
287
+ }
288
+ else {
249
289
  // Result already provided by caller
250
290
  displayNamedXsn(model, 'csn', options);
251
291
  }
@@ -256,99 +296,105 @@ function executeCommandLine(command, options, args) {
256
296
  // Return the original model (for chaining)
257
297
  function toHana( model ) {
258
298
  const csn = options.directBackend ? model : compactModel(model, options);
259
- const hanaResult = toHanaWithCsn(csn, options);
260
- for( const pluginName of ['hdbcds', 'hdbconstraint']){
261
- for(const name in hanaResult[pluginName]){
262
- writeToFileOrDisplay(options.out, `${name}.${pluginName}`, hanaResult[pluginName][name]);
263
- }
299
+
300
+ if (options.toHana && options.toHana.csn) {
301
+ displayNamedCsn(for_hdbcds(csn, remapCmdOptions(options, options.toHana)), 'hana_csn', options);
264
302
  }
265
- displayNamedCsn(hanaResult.csn, 'hana_csn', options);
303
+ else {
304
+ const hanaResult = main.to.hdbcds(csn, remapCmdOptions(options, options.toHana));
305
+ for (const name in hanaResult)
306
+ writeToFileOrDisplay(options.out, name, hanaResult[name]);
307
+ }
308
+
266
309
  return model;
267
310
  }
268
311
 
269
312
  // Execute the command line option '--to-odata' and display the results.
270
313
  // Return the original model (for chaining)
271
314
  function toOdata( model ) {
272
- if(options.toOdata &&
315
+ if (options.toOdata &&
273
316
  options.toOdata.version === 'v4x') {
274
317
  options.toOdata.version = 'v4';
275
318
  options.toOdata.odataFormat = 'structured';
276
319
  options.toOdata.odataContainment = true;
277
320
  }
278
- let csn = options.directBackend ? model : compactModel(model, options);
279
- const odataResult = toOdataWithCsn(csn, options);
280
- for (let serviceName in odataResult.services) {
281
- // <service>_metadata.xml (metadata)
282
- if (odataResult.services[serviceName].metadata) {
283
- writeToFileOrDisplay(options.out, serviceName + '_metadata.xml', odataResult.services[serviceName].metadata);
284
- }
285
- // <service>_annotations.xml (annotations)
286
- if (odataResult.services[serviceName].annotations) {
287
- writeToFileOrDisplay(options.out, serviceName + '_annotations.xml', odataResult.services[serviceName].annotations);
288
- }
289
- // <service>.xml (combined)
290
- if (odataResult.services[serviceName].combined) {
291
- writeToFileOrDisplay(options.out, serviceName + '.xml', odataResult.services[serviceName].combined);
292
- }
293
- // <service>.json (metadata_json)
294
- if (odataResult.services[serviceName].metadata_json) {
295
- writeToFileOrDisplay(options.out, serviceName + '.json', odataResult.services[serviceName].metadata_json);
296
- }
321
+ const csn = options.directBackend ? model : compactModel(model, options);
322
+ const odataCsn = main.for.odata(csn, remapCmdOptions(options, options.toOdata));
323
+ if (options.toOdata && options.toOdata.csn) {
324
+ displayNamedCsn(odataCsn, 'odata_csn', options);
325
+ }
326
+ else if (options.toOdata && options.toOdata.json) {
327
+ const result = main.to.edm.all(odataCsn, options);
328
+ for (const serviceName in result)
329
+ writeToFileOrDisplay(options.out, `${serviceName}.json`, result[serviceName]);
330
+ }
331
+ else {
332
+ const result = main.to.edmx.all(odataCsn, options);
333
+ for (const serviceName in result)
334
+ writeToFileOrDisplay(options.out, `${serviceName}.xml`, result[serviceName]);
297
335
  }
298
- displayNamedCsn(odataResult.csn, 'odata_csn', options);
299
336
  return model;
300
337
  }
301
338
 
302
339
  // Execute the command line option '--to-rename' and display the results.
303
340
  // Return the original model (for chaining)
304
341
  //
305
- /// THIS MUST SURVIVE IF WE REMOVE THE OLD API
306
- /// DO NOT DELETE THIS TORENAME FUNCTIONALITY!!
342
+ // / THIS MUST SURVIVE IF WE REMOVE THE OLD API
343
+ // / DO NOT DELETE THIS TORENAME FUNCTIONALITY!!
307
344
  function toRename( model ) {
308
- let csn = options.directBackend ? model : compactModel(model, options);
309
- let renameResult = toRenameWithCsn(csn, options);
310
- let storedProcedure = 'PROCEDURE RENAME_' + renameResult.options.toRename.names.toUpperCase() + '_TO_PLAIN LANGUAGE SQLSCRIPT AS BEGIN\n';
311
- for (let name in renameResult.rename) {
312
- storedProcedure += ' --\n -- ' + name + '\n --\n';
345
+ const csn = options.directBackend ? model : compactModel(model, options);
346
+ const renameResult = toRenameWithCsn(csn, options);
347
+ let storedProcedure = `PROCEDURE RENAME_${renameResult.options.toRename.names.toUpperCase()}_TO_PLAIN LANGUAGE SQLSCRIPT AS BEGIN\n`;
348
+ for (const name in renameResult.rename) {
349
+ storedProcedure += ` --\n -- ${name}\n --\n`;
313
350
  storedProcedure += renameResult.rename[name];
314
351
  }
315
- storedProcedure += "END;\n";
316
- writeToFileOrDisplay(options.out, 'storedProcedure_' + renameResult.options.toRename.names + '_to_plain.sql', storedProcedure, true);
352
+ storedProcedure += 'END;\n';
353
+ writeToFileOrDisplay(options.out, `storedProcedure_${renameResult.options.toRename.names}_to_plain.sql`, storedProcedure, true);
317
354
  return model;
318
355
  }
319
356
 
320
- // Execute the command line option 'manageConstraints' and display the results.
357
+ // Execute the command line option 'manageConstraints' and display the results.
321
358
  function manageConstraints( model ) {
322
359
  const csn = options.directBackend ? model : compactModel(model, options);
323
360
  const alterConstraintsResult = alterConstraintsWithCsn(csn, options);
324
361
  const { src } = options.manageConstraints || {};
325
362
  Object.keys(alterConstraintsResult).forEach((id) => {
326
363
  const renderedConstraintStatement = alterConstraintsResult[id];
327
- if(src === 'hdi')
364
+ if (src === 'hdi')
328
365
  writeToFileOrDisplay(options.out, `${id}.hdbconstraint`, renderedConstraintStatement);
329
366
  else
330
367
  writeToFileOrDisplay(options.out, `${id}.sql`, renderedConstraintStatement);
331
- })
368
+ });
332
369
  }
333
370
 
334
371
  // Execute the command line option '--to-sql' and display the results.
335
372
  // Return the original model (for chaining)
336
373
  function toSql( model ) {
337
374
  const csn = options.directBackend ? model : compactModel(model, options);
338
- const sqlResult = toSqlWithCsn(csn, options);
339
-
340
- ['hdbtabletype', 'hdbtable', 'hdbindex', 'hdbfulltextindex', 'hdbview', 'hdbconstraint', 'sql'].forEach(pluginName => {
341
- for(let name in sqlResult[pluginName]) {
342
- writeToFileOrDisplay(options.out, name + '.' + pluginName, sqlResult[pluginName][name] + '\n', true);
375
+ if (options.toSql && options.toSql.src === 'hdi') {
376
+ if (options.toSql.csn) {
377
+ displayNamedCsn(for_hdi(csn, remapCmdOptions(options, options.toSql)), 'hdi_csn', options);
343
378
  }
344
- });
345
- displayNamedCsn(sqlResult.csn, 'sql_csn', options);
379
+ else {
380
+ const hdiResult = main.to.hdi(csn, remapCmdOptions(options, options.toSql));
381
+ for (const name in hdiResult)
382
+ writeToFileOrDisplay(options.out, name, hdiResult[name]);
383
+ }
384
+ }
385
+ else if (options.toSql && options.toSql.csn) {
386
+ displayNamedCsn(for_sql(csn, remapCmdOptions(options, options.toSql)), 'sql_csn', options);
387
+ }
388
+ else {
389
+ const sqlResult = main.to.sql(csn, remapCmdOptions(options, options.toSql));
390
+ writeToFileOrDisplay(options.out, 'model.sql', sqlResult.join('\n'), true);
391
+ }
346
392
  return model;
347
393
  }
348
394
 
349
395
  function explain() {
350
396
  if (args.length !== 1)
351
- displayUsage(`Command 'explain' expects exactly one message-id.`, optionProcessor.commands['explain'].helpText, 2);
397
+ displayUsage('Command \'explain\' expects exactly one message-id.', optionProcessor.commands.explain.helpText, 2);
352
398
 
353
399
  const id = args.files[0];
354
400
  if (!hasMessageExplanation(id))
@@ -360,23 +406,24 @@ function executeCommandLine(command, options, args) {
360
406
  // Display error messages in `err` resulting from a compilation. Also set
361
407
  // process.exitCode - process.exit() will force the process to exit as quickly
362
408
  // as possible = is problematic, since console.error() might be asynchronous
363
- function displayErrors (err) {
409
+ function displayErrors(err) {
364
410
  if (err instanceof main.CompilationError) {
365
411
  if (options.rawOutput)
366
412
  console.error( util.inspect( reveal( err.model, options.rawOutput ), false, null ));
367
413
  else
368
- displayMessages( err.model, err.errors );
414
+ displayMessages( err.model, err.messages );
369
415
  process.exitCode = 1;
370
416
  }
371
417
  else if (err instanceof compiler.InvocationError) {
372
418
  console.error( '' );
373
- for (let sub of err.errors)
419
+ for (const sub of err.errors)
374
420
  console.error( sub.message );
375
421
  console.error( '' );
376
422
  process.exitCode = 2;
377
423
  }
378
- else
424
+ else {
379
425
  throw err;
426
+ }
380
427
 
381
428
  err.hasBeenReported = true;
382
429
  throw err;
@@ -397,11 +444,11 @@ function executeCommandLine(command, options, args) {
397
444
  sortMessages(messages);
398
445
 
399
446
  if (options.internalMsg) {
400
- messages.map(msg => util.inspect( msg, { depth: null, maxArrayLength: null} ) )
447
+ messages.map(msg => util.inspect( msg, { depth: null, maxArrayLength: null } ) )
401
448
  .forEach(msg => log(msg));
402
449
  }
403
450
  else if (options.noMessageContext) {
404
- messages.filter(msg => (messageLevels[ msg.severity ] <= options.warning))
451
+ messages.filter(msg => (messageLevels[msg.severity] <= options.warning))
405
452
  .forEach(msg => log(main.messageString(msg, normalizeFilename, !options.showMessageId)));
406
453
  }
407
454
  else {
@@ -413,19 +460,20 @@ function executeCommandLine(command, options, args) {
413
460
  return splitCache[name];
414
461
  };
415
462
  let hasAtLeastOneExplanation = false;
416
- messages.filter(msg => messageLevels[ msg.severity ] <= options.warning).forEach(msg => {
417
- hasAtLeastOneExplanation = hasAtLeastOneExplanation || main.hasMessageExplanation(msg.messageId)
463
+ messages.filter(msg => messageLevels[msg.severity] <= options.warning).forEach((msg) => {
464
+ hasAtLeastOneExplanation = hasAtLeastOneExplanation || main.hasMessageExplanation(msg.messageId);
418
465
  const name = msg.location && msg.location.file;
419
466
  const fullFilePath = name ? path.resolve('', name) : undefined;
420
467
  const context = fullFilePath && sourceLines(fullFilePath);
421
- log(main.messageStringMultiline(msg, { normalizeFilename, noMessageId: !options.showMessageId, withLineSpacer: true, hintExplanation: true }));
468
+ log(main.messageStringMultiline(msg, {
469
+ normalizeFilename, noMessageId: !options.showMessageId, withLineSpacer: true, hintExplanation: true,
470
+ }));
422
471
  if (context)
423
472
  log(main.messageContext(context, msg));
424
- log() // newline
473
+ log(); // newline
425
474
  });
426
- if (options.showMessageId && hasAtLeastOneExplanation) {
427
- log(`${term.help('help')}: Messages marked with '…' have an explanation text. Use \`cdsc explain <message-id>\` for a more detailed error description.`)
428
- }
475
+ if (options.showMessageId && hasAtLeastOneExplanation)
476
+ log(`${term.help('help')}: Messages marked with '…' have an explanation text. Use \`cdsc explain <message-id>\` for a more detailed error description.`);
429
477
  }
430
478
  return model;
431
479
  }
@@ -436,18 +484,18 @@ function executeCommandLine(command, options, args) {
436
484
  // written in raw form to '<name>_raw.txt'.
437
485
  function displayNamedXsn(xsn, name, options) {
438
486
  if (options.rawOutput) {
439
- writeToFileOrDisplay(options.out, name + '_raw.txt', util.inspect(reveal(xsn, options.rawOutput), false, null), true);
487
+ writeToFileOrDisplay(options.out, `${name}_raw.txt`, util.inspect(reveal(xsn, options.rawOutput), false, null), true);
440
488
  }
441
489
  else if (options.internalMsg) {
442
- writeToFileOrDisplay(options.out, name + '_raw.txt', util.inspect(reveal(xsn).messages, { depth: null, maxArrayLength: null}), true);
490
+ writeToFileOrDisplay(options.out, `${name}_raw.txt`, util.inspect(reveal(xsn).messages, { depth: null, maxArrayLength: null }), true);
443
491
  }
444
492
  else if (!options.lintMode) {
445
- let csn = compactModel(xsn, options);
493
+ const csn = compactModel(xsn, options);
446
494
  if (command === 'toCsn' && options.toCsn && options.toCsn.withLocalized)
447
495
  addLocalizationViews(csn, options);
448
496
  if (options.enrichCsn)
449
497
  enrichCsn( csn, options );
450
- writeToFileOrDisplay(options.out, name + '.json', csn, true);
498
+ writeToFileOrDisplay(options.out, `${name}.json`, csn, true);
451
499
  }
452
500
  }
453
501
 
@@ -460,12 +508,12 @@ function executeCommandLine(command, options, args) {
460
508
  if (!csn) // only print CSN if it is set.
461
509
  return;
462
510
  if (options.internalMsg) {
463
- writeToFileOrDisplay(options.out, name + '_raw.txt', options.messages, true);
511
+ writeToFileOrDisplay(options.out, `${name}_raw.txt`, options.messages, true);
464
512
  }
465
513
  else if (!options.lintMode && !options.internalMsg) {
466
514
  if (command === 'toCsn' && options.toCsn && options.toCsn.withLocalized)
467
515
  addLocalizationViews(csn, options);
468
- writeToFileOrDisplay(options.out, name + '.json', csn, true);
516
+ writeToFileOrDisplay(options.out, `${name}.json`, csn, true);
469
517
  }
470
518
  }
471
519
 
@@ -480,28 +528,28 @@ function executeCommandLine(command, options, args) {
480
528
  fileName = fileName.replace(/[:/\\]/g, '_');
481
529
 
482
530
  // replace all dots with underscore to get deployable .hdbcds sources (except the one before the file extension)
483
- if(options.toHana)
484
- fileName = fileName.replace(/\.(?=.*?\.)/g, '_')
531
+ if (options.transformation === 'hdbcds')
532
+ fileName = fileName.replace(/\.(?=.*?\.)/g, '_');
485
533
 
486
- if (!(content instanceof String || typeof content === 'string')) {
534
+ if (!(content instanceof String || typeof content === 'string'))
487
535
  content = JSON.stringify(content, null, 2);
488
- }
536
+
489
537
  if (dir === '-') {
490
- if (!omitHeadline) {
538
+ if (!omitHeadline)
491
539
  process.stdout.write(`// ------------------- ${fileName} -------------------\n`);
492
- }
540
+
493
541
  process.stdout.write(`${content}\n`);
494
- if (!omitHeadline) {
495
- process.stdout.write(`\n`);
496
- }
497
- } else {
542
+ if (!omitHeadline)
543
+ process.stdout.write('\n');
544
+ }
545
+ else {
498
546
  // TODO: We might consider using async file-system API ...
499
547
  fs.writeFileSync(path.join(dir, fileName), content);
500
548
  }
501
549
  }
502
550
 
503
- function catchErrors (err) {
504
- if (err instanceof Error && err['hasBeenReported'])
551
+ function catchErrors(err) {
552
+ if (err instanceof Error && err.hasBeenReported)
505
553
  return;
506
554
  console.error( '' );
507
555
  console.error( 'INTERNAL ERROR: %s', err );
package/bin/cdshi.js CHANGED
@@ -16,28 +16,35 @@ const fs = require('fs');
16
16
  fs.readFile( '/dev/stdin', 'utf8', highlight );
17
17
 
18
18
  const categoryChars = {
19
- artref: 'm', paramname: 'b',
20
- Entity: 'D', Enum: 'H', Index: 'J', AnnoDef: 'V', Extend: 'Z', Annotate: 'Z', Event: 'Y'
21
- }
19
+ artref: 'm',
20
+ paramname: 'b',
21
+ Entity: 'D',
22
+ Enum: 'H',
23
+ Index: 'J',
24
+ AnnoDef: 'V',
25
+ Extend: 'Z',
26
+ Annotate: 'Z',
27
+ Event: 'Y',
28
+ };
22
29
 
23
30
  function highlight( err, buf ) {
24
31
  if (err) {
25
32
  console.error( 'ERROR:', err.toString() );
26
33
  return;
27
34
  }
28
- let ts = compiler.parseX( buf, 'hi.cds', { attachTokens: true, messages: [] } ).tokenStream;
35
+ const ts = compiler.parseX( buf, 'hi.cds', { attachTokens: true, messages: [] } ).tokenStream;
29
36
  if (!buf.length || !ts.tokens || !ts.tokens.length)
30
37
  return;
31
- let chars = [...buf];
32
- for (let tok of ts.tokens) {
33
- let cat = tok.isIdentifier;
38
+ const chars = [ ...buf ];
39
+ for (const tok of ts.tokens) {
40
+ const cat = tok.isIdentifier;
34
41
  if (cat && tok.start >= 0) {
35
- if (cat !== 'ref' || chars[ tok.start ] !== '$')
36
- chars[ tok.start ] = categoryChars[ cat ] || cat.charAt(0);
42
+ if (cat !== 'ref' || chars[tok.start] !== '$')
43
+ chars[tok.start] = categoryChars[cat] || cat.charAt(0);
37
44
  if (tok.stop > tok.start) // stop in ANTLR at last char, not behind
38
- chars[ tok.start+1 ] = '_';
45
+ chars[tok.start + 1] = '_';
39
46
  }
40
47
  }
41
- for (let c of chars)
48
+ for (const c of chars)
42
49
  process.stdout.write( c );
43
50
  }