@sap/cds-dk 4.9.6 → 6.0.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 (143) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/bin/activate.js +4 -4
  3. package/bin/add.js +11 -5
  4. package/bin/bind.js +16 -28
  5. package/bin/build/all.js +2 -2
  6. package/bin/build/index.js +12 -19
  7. package/bin/cds.js +16 -17
  8. package/bin/compile/index.js +12 -3
  9. package/bin/deploy/index.js +14 -14
  10. package/bin/deploy/to-hana.js +4 -4
  11. package/bin/deploy/to-sqlite.js +1 -1
  12. package/bin/env.js +13 -4
  13. package/bin/eval.js +1 -1
  14. package/bin/fix-redirects.js +1 -1
  15. package/bin/import.js +44 -179
  16. package/bin/repl.js +1 -1
  17. package/bin/watch.js +10 -15
  18. package/lib/bind/BindingManager.js +87 -0
  19. package/lib/bind/bindingResolver.js +14 -85
  20. package/lib/bind/bindingUtil.js +18 -11
  21. package/lib/bind/cfKeyProvider.js +58 -29
  22. package/lib/bind/kubernetesCredentialsProvider.js +44 -21
  23. package/lib/bind/userCdsrcJsonStorageProvider.js +12 -18
  24. package/lib/cds.js +13 -0
  25. package/lib/client/base_command.js +3 -2
  26. package/lib/client/extend.js +6 -7
  27. package/lib/client/helper/fs_helper.js +7 -8
  28. package/lib/client/settings_manager.js +14 -10
  29. package/lib/compile/index.js +9 -10
  30. package/lib/compile/openapi/csdl2openapi.js +151 -43
  31. package/lib/compile/openapi/index.js +2 -2
  32. package/lib/compile/to-xsuaa.js +3 -2
  33. package/lib/import/common.js +342 -27
  34. package/lib/import/importapi.js +81 -13
  35. package/lib/import/message.js +4 -4
  36. package/lib/import/odata/index.js +141 -0
  37. package/lib/import/{utils → odata/metadataconverter}/MetadataConverter.js +2 -2
  38. package/lib/import/{utils → odata/metadataconverter}/MetadataConverterFactory.js +1 -1
  39. package/lib/import/{utils → odata/util}/MultiMap.js +0 -0
  40. package/lib/import/{v2parser.js → odata/v2parser.js} +405 -468
  41. package/lib/import/{v4parser.js → odata/v4parser.js} +311 -322
  42. package/lib/import/{vocabularies → odata/vocabularies}/Org.OData.Aggregation.V1.json +0 -0
  43. package/lib/import/{vocabularies → odata/vocabularies}/Org.OData.Authorization.V1.json +0 -0
  44. package/lib/import/{vocabularies → odata/vocabularies}/Org.OData.Capabilities.V1.json +0 -0
  45. package/lib/import/{vocabularies → odata/vocabularies}/Org.OData.Core.V1.json +0 -0
  46. package/lib/import/{vocabularies → odata/vocabularies}/Org.OData.Measures.V1.json +0 -0
  47. package/lib/import/{vocabularies → odata/vocabularies}/Org.OData.Validation.V1.json +0 -0
  48. package/lib/import/openapi/importOpenAPI.js +521 -0
  49. package/lib/import/openapi/index.js +19 -0
  50. package/lib/import/openapi/utilities.js +38 -0
  51. package/lib/index.js +1 -1
  52. package/lib/init/constants.js +7 -2
  53. package/lib/init/index.js +10 -3
  54. package/lib/init/template/_merging/existences.js +79 -19
  55. package/lib/init/template/approuter/files/mta.yaml.hbs +25 -11
  56. package/lib/init/template/approuter/files/package.json +1 -1
  57. package/lib/init/template/approuter/files/xs-app.json.hbs +7 -0
  58. package/lib/init/template/approuter/index.js +61 -54
  59. package/lib/init/template/auditlog/index.js +2 -2
  60. package/lib/init/template/data/index.js +2 -2
  61. package/lib/init/template/hana/files/mta.yaml.hbs +17 -17
  62. package/lib/init/template/hana/index.js +8 -4
  63. package/lib/init/template/helm/index.js +39 -0
  64. package/lib/init/template/helm/update/index.js +28 -0
  65. package/lib/init/template/java/index.js +7 -9
  66. package/lib/init/template/kibana-logging/index.js +5 -6
  67. package/lib/init/template/mta/index.js +4 -4
  68. package/lib/init/template/mtx/files/java/package.json +9 -9
  69. package/lib/init/template/mtx/files/mta.yaml.hbs +0 -7
  70. package/lib/init/template/mtx/files/xs-security.json.hbs +11 -20
  71. package/lib/init/template/mtx/index.js +50 -57
  72. package/lib/init/template/nodejs/files/package.json.hbs +2 -2
  73. package/lib/init/template/notebook/index.js +2 -0
  74. package/lib/init/template/templateBase.js +6 -4
  75. package/lib/init/template/xsuaa/index.js +9 -5
  76. package/lib/init/util/fsUtil.js +25 -10
  77. package/lib/init/util/logger.js +1 -1
  78. package/lib/init/util/mvnArchetypeUtil.js +4 -10
  79. package/lib/init/util/projectReader.js +16 -8
  80. package/lib/init/util/templateUtil.js +30 -34
  81. package/lib/k8s/ChartAdder.js +65 -0
  82. package/lib/k8s/ChartBuilder.js +186 -0
  83. package/lib/k8s/Context.js +71 -0
  84. package/lib/k8s/ImageUtil.js +21 -0
  85. package/lib/k8s/Model.d.ts +53 -0
  86. package/lib/k8s/auditlog/index.js +29 -0
  87. package/lib/k8s/auditlog/templates/auditlog.yaml +1 -0
  88. package/lib/k8s/buildModel.js +70 -0
  89. package/lib/k8s/connectivity/index.js +74 -0
  90. package/lib/k8s/connectivity/templates/connectivity-binding.yaml +9 -0
  91. package/lib/k8s/connectivity/templates/connectivity-proxy-info.yaml +16 -0
  92. package/lib/k8s/connectivity/templates/connectivity.yaml +1 -0
  93. package/lib/k8s/deployment/index.js +81 -0
  94. package/lib/k8s/deployment/subchart/Chart.yaml +6 -0
  95. package/lib/k8s/deployment/subchart/templates/_helpers.tpl +156 -0
  96. package/lib/k8s/deployment/subchart/templates/api-rule.yaml +24 -0
  97. package/lib/k8s/deployment/subchart/templates/deployment.yaml +110 -0
  98. package/lib/k8s/deployment/subchart/templates/network-policy.yaml +16 -0
  99. package/lib/k8s/deployment/subchart/templates/pod-disruption-budget.yaml +11 -0
  100. package/lib/k8s/deployment/subchart/templates/secret.yaml +10 -0
  101. package/lib/k8s/deployment/subchart/templates/service-binding.yaml +27 -0
  102. package/lib/k8s/deployment/subchart/templates/service.yaml +11 -0
  103. package/lib/k8s/deployment/subchart/values-lint.yaml +8 -0
  104. package/lib/k8s/deployment/subchart/values.schema.json +449 -0
  105. package/lib/k8s/deployment/subchart/values.yaml +76 -0
  106. package/lib/k8s/deployment/subchart-override/templates/_web_application_helpers.tpl +81 -0
  107. package/lib/k8s/destinations/index.js +40 -0
  108. package/lib/k8s/destinations/lib.js +16 -0
  109. package/lib/k8s/destinations/templates/destinations.yaml +1 -0
  110. package/lib/k8s/docker/push.js +8 -0
  111. package/lib/k8s/event-mesh/index.js +53 -0
  112. package/lib/k8s/event-mesh/lib.js +9 -0
  113. package/lib/k8s/event-mesh/templates/event-mesh.yaml +1 -0
  114. package/lib/k8s/hana-deployer/index.js +38 -0
  115. package/lib/k8s/hana-deployer/templates/hana-deployer-job.yaml +41 -0
  116. package/lib/k8s/helm/Release.js +80 -0
  117. package/lib/k8s/html5-apps-deployer/index.js +43 -0
  118. package/lib/k8s/html5-apps-deployer/templates/_html5_deployment_helpers.tpl +16 -0
  119. package/lib/k8s/html5-apps-deployer/templates/html5-apps-deployer-job.yaml +53 -0
  120. package/lib/k8s/html5-apps-repo-host/index.js +26 -0
  121. package/lib/k8s/html5-apps-repo-host/lib.js +16 -0
  122. package/lib/k8s/html5-apps-repo-host/templates/html5-apps-repo-host.yaml +1 -0
  123. package/lib/k8s/index.js +153 -0
  124. package/lib/k8s/modules.js +36 -0
  125. package/lib/k8s/multitenancy/index.js +24 -0
  126. package/lib/k8s/multitenancy/lib.js +25 -0
  127. package/lib/k8s/multitenancy/templates/saas-registry.yaml +19 -0
  128. package/lib/k8s/readProject.js +14 -0
  129. package/lib/k8s/resources/helm/chart/templates/NOTES.txt +11 -0
  130. package/lib/k8s/resources/helm/chart/templates/_deployment_helpers.tpl +221 -0
  131. package/lib/k8s/resources/helm/chart/templates/_helpers.tpl +167 -0
  132. package/lib/k8s/resources/helm/chart/templates/_sapcp_helpers.tpl +103 -0
  133. package/lib/k8s/util.js +186 -0
  134. package/lib/k8s/wrapFeature.js +55 -0
  135. package/lib/k8s/xsuaa/index.js +64 -0
  136. package/lib/k8s/xsuaa/lib.js +14 -0
  137. package/lib/k8s/xsuaa/templates/xsuaa.yaml +1 -0
  138. package/lib/util/exec.js +1 -1
  139. package/lib/util/write.js +1 -1
  140. package/lib/watch/node-watch.js +43 -14
  141. package/npm-shrinkwrap.json +914 -2745
  142. package/package.json +5 -5
  143. package/lib/import/index.js +0 -235
@@ -1,6 +1,23 @@
1
1
  'use strict';
2
2
 
3
- let convert = require('xml-js')
3
+ let convert = require('xml-js');
4
+ let axios = require('axios');
5
+ const messages = require("./message").getMessages();
6
+ const cds = require('../cds');
7
+ const { fs, path, write, mkdirp, exists, read } = cds.utils;
8
+ const cdsCompiler = require('../compile').compile.to;
9
+ const md5 = require('md5');
10
+
11
+ let optionsMapping = {
12
+ 'keep-namespace': 'keepNamespace',
13
+ 'include-namespaces': 'includeNamespaces',
14
+ 'no-copy': 'no_copy',
15
+ 'no-save': 'no_save'
16
+ };
17
+
18
+ let apiOptions = ['includeNamespaces', 'keepNamespace'];
19
+ let commonOptions = ['no_copy', 'no_save', 'out', 'dry', 'as', 'from', 'force'];
20
+
4
21
  function _isJson(edmx) {
5
22
  let isJson = false;
6
23
  try {
@@ -12,8 +29,7 @@ function _isJson(edmx) {
12
29
  return isJson;
13
30
  }
14
31
 
15
- async function _generateEDMX2JSON(edmx) {
16
- // Reinitialize
32
+ async function generateEDMX2JSON(edmx) {
17
33
  let cjson = convert.xml2json(edmx, {
18
34
  compact: true,
19
35
  spaces: 4
@@ -21,21 +37,15 @@ async function _generateEDMX2JSON(edmx) {
21
37
  return JSON.parse(cjson);
22
38
  }
23
39
 
24
- function checkForEmptyKeys(element, oDataVersion) {
25
- if (oDataVersion === "V2") {
26
- return (element.includes(["cds.Association"]) && !element.includes(['"on":']));
40
+ async function _isValidXML(edmx) {
41
+ let isValid = false;
42
+ try {
43
+ generateEDMX2JSON(edmx);
44
+ isValid = true;
45
+ } catch (err) {
46
+ isValid = false;
27
47
  }
28
- else {
29
- return (['cds.Association'].includes(element.type)) && !element.on && !element.keys;
30
- }
31
- }
32
-
33
- //to replace the alias value with original schema namespace value
34
- function replaceAliasValue(schemaContent, schemaNamespaceValue, aliasValue){
35
- const re = RegExp(`([("/])${aliasValue}([/").])`, 'g');
36
- const val = `$1${schemaNamespaceValue}$2`;
37
- schemaContent = schemaContent.replace(re, val);
38
- return JSON.parse(schemaContent);
48
+ return isValid;
39
49
  }
40
50
 
41
51
  async function _getODataVersion(edmx) {
@@ -47,7 +57,7 @@ async function _getODataVersion(edmx) {
47
57
  if (_isJson(edmx)) {
48
58
  return '';
49
59
  }
50
- jsonObj = await _generateEDMX2JSON(edmx);
60
+ jsonObj = await generateEDMX2JSON(edmx);
51
61
  try {
52
62
  dataServices = jsonObj['edmx:Edmx']['edmx:DataServices'];
53
63
  dataServicesAttributes = dataServices._attributes;
@@ -84,11 +94,10 @@ async function _isOdataV4(fileInputStream) {
84
94
  if (_isJson(fileInputStream)) {
85
95
  edmj = JSON.parse(fileInputStream);
86
96
  version = edmj.$Version;
87
- // read $Version from JSON
88
97
  } else {
89
98
  version = await _getODataVersion(fileInputStream);
90
99
  }
91
- if (version === '4.0') {
100
+ if (version === '4.0' || version === "4.01") {
92
101
  isV4 = true;
93
102
  }
94
103
  return isV4;
@@ -108,21 +117,327 @@ async function getVersion(fileInputStream) {
108
117
  return oDataVersion;
109
118
  }
110
119
 
111
- function getSuffix(outputFormat) {
112
- const suffix = { edmx: 'xml', "edmx-v2": 'xml', "edmx-v4": 'xml', "edmx-w4": 'xml',
113
- "edmx-x4": 'xml', openapi: 'openapi3.json', sql: 'sql', edm: 'json', "cdl": "cds" };
120
+ function checkForEmptyKeys(element, oDataVersion) {
121
+ if (oDataVersion === "V2") {
122
+ return (element.includes(["cds.Association"]) && !element.includes(['"on":']));
123
+ }
124
+ else {
125
+ return (['cds.Association'].includes(element.type)) && !element.on && !element.keys;
126
+ }
127
+ }
128
+
129
+ // to replace the alias value with original schema namespace value
130
+ function replaceAliasValue(schemaContent, schemaNamespaceValue, aliasValue) {
131
+ const re = RegExp(`([("/])${aliasValue}([/").])`, 'g');
132
+ const val = `$1${schemaNamespaceValue}$2`;
133
+ schemaContent = schemaContent.replace(re, val);
134
+ return JSON.parse(schemaContent);
135
+ }
136
+
137
+ async function getContentFromFile(path) {
138
+ let fileContent;
139
+ fileContent = await read(path, "utf-8");
140
+ return fileContent;
141
+ }
142
+
143
+ async function getContentFromURL(url) {
144
+ let edmx;
145
+ const response = await axios.get(url);
146
+ edmx = response["data"];
147
+ if (edmx && (await _isValidXML(edmx))) {
148
+ return edmx;
149
+ } else {
150
+ throw new Error(messages.INVALID_EDMX_METADATA);
151
+ }
152
+ }
153
+
154
+ function _getSuffix(outputFormat) {
155
+ const suffix = {
156
+ edmx: 'xml', "edmx-v2": 'xml', "edmx-v4": 'xml', "edmx-w4": 'xml',
157
+ "edmx-x4": 'xml', openapi: 'openapi3.json', sql: 'sql', edm: 'json', "cdl": "cds"
158
+ };
114
159
  // find the output file extension based on the target conversion selected
115
160
  return (outputFormat) ? (suffix[outputFormat] || outputFormat) : 'csn';
116
161
  }
117
162
 
118
- function supportedFormats() {
163
+ function _supportedAsFormats() {
119
164
  return ["cds", "csn", "json"];
120
165
  }
121
166
 
167
+ function _supportedFileExtensions() {
168
+ return ["edmx", "xml", "json"];
169
+ }
170
+
171
+ function _getInputFileExtension(inputFile) {
172
+ let startIndex = inputFile.lastIndexOf(".");
173
+ return inputFile.substring(startIndex + 1);
174
+ }
175
+
176
+ async function isValidInputFile(inputFileLoc) {
177
+ const fileResolved = await fs.isfile(inputFileLoc);
178
+ if (!fileResolved) throw new Error(messages.SPECIFY_INPUT_FILE);
179
+ let fileExtension = _getInputFileExtension(inputFileLoc);
180
+ if (_supportedFileExtensions().includes(fileExtension)) return fileResolved;
181
+ else throw new Error(messages.INVALID_INPUT_FILE);
182
+ }
183
+
184
+ async function _copyToSrvExternal(file, dst, cwd) {
185
+ const dstDir = path.dirname(dst), srcDir = path.dirname(file)
186
+ if (!file.startsWith(dstDir + path.sep)) {
187
+ await mkdirp(dstDir);
188
+ const copyOrMove = srcDir === cwd || srcDir == process.cwd() ? fs.renameSync : fs.copyFileSync;
189
+ await copyOrMove(file, dst);
190
+ return dst;
191
+ }
192
+ return file;
193
+ }
194
+
195
+ async function preProcess(file, options, cwd) {
196
+ let srcFilePath = await isValidInputFile(path.resolve(cwd, file));
197
+ if (options.as && !_supportedAsFormats().includes(options.as))
198
+ throw new Error(messages.INVALID_AS_OPTION);
199
+
200
+ const external = path.resolve(cwd, 'srv/external');
201
+ const destFilePath = path.join(external, path.basename(srcFilePath));
202
+
203
+ if (!options.dry && !options.no_copy)
204
+ srcFilePath = await _copyToSrvExternal(srcFilePath, destFilePath, cwd);
205
+
206
+ return [srcFilePath, destFilePath];
207
+ }
208
+
209
+ async function processOptions(cliOptions, odataOptions) {
210
+ //maps to renaming of variables
211
+ for (let [key, value] of Object.entries(optionsMapping)) {
212
+ if (cliOptions[key]) {
213
+ cliOptions[value] = cliOptions[key];
214
+ delete cliOptions[key];
215
+ }
216
+ }
217
+ //segregating cli/odata options
218
+ apiOptions.forEach(function (item) {
219
+ odataOptions[item] = cliOptions[item];
220
+ delete cliOptions[item];
221
+ });
222
+ //reads cli options from environment
223
+ readEnvVariables(cliOptions, true);
224
+
225
+
226
+ }
227
+
228
+ function _getServiceName(csn) {
229
+ for (let each in csn.definitions) {
230
+ if (csn.definitions[each].kind === 'service') return each;
231
+ }
232
+ }
233
+
234
+ function _validateAndComputeOutputFilePath(outputFileLoc, as, destFilePath) {
235
+ let index, extension, expectedExtension, supportedExtension;
236
+ if (typeof (outputFileLoc) !== 'boolean') {
237
+ index = outputFileLoc.lastIndexOf(".");
238
+ extension = outputFileLoc.substring(index + 1);
239
+ expectedExtension = (as) ? _getSuffix(as) : "csn";
240
+ supportedExtension = (index > 0) ? _supportedAsFormats().includes(extension) : false;
241
+ }
242
+
243
+ if (outputFileLoc === true || // if output file is not mentioned
244
+ outputFileLoc[0] === "-" || // if output file is missing and "--as" is considered as output file
245
+ outputFileLoc.trim() === "") {
246
+ throw new Error(messages.SPECIFY_OUTPUT_FILE);
247
+ } else if (index > 0 && !supportedExtension) {
248
+ // extension not supported, eg., "test.abs", "./sv/external.test.abcs", "./a."
249
+ throw new Error(messages.INVALID_OUTPUT_FILE);
250
+ } else if (index > 0 && !as && extension != "json" && extension != "csn") {
251
+ // --as option is not provided but output file is like: "test.cds", "./srv/external/test.cds"
252
+ throw new Error(messages.INCORRECT_EXTENSION);
253
+ } else if (index > 0 && as && extension != expectedExtension) {
254
+ // extension not supported by --as option, e.g., "cds import <file> --out test.yml --as cds"
255
+ throw new Error(messages.OUTPUT_FILE_MISMATCH);
256
+ } else if (supportedExtension || (!outputFileLoc.endsWith("\\") && !outputFileLoc.endsWith("/"))) {
257
+ // eg., "./a.csn", "tst.cds", "./srv/external/test", "test", "c:\windows\output\test"
258
+ return outputFileLoc;
259
+ } else if (outputFileLoc.endsWith("/") || outputFileLoc.endsWith("\\")) {
260
+ // File name not specified ("./srv/external/", "c:\windows\output\test\")
261
+ return outputFileLoc + path.parse(destFilePath).name;
262
+ }
263
+ }
264
+
265
+ async function _generateChecksumValidate(dest, output, force) {
266
+ let fileExists = await exists(dest);
267
+
268
+ // force flag disabled and cds file already exists, then throw error
269
+ if (!force && fileExists) {
270
+ throw new Error(messages.FILE_MODIFIED);
271
+ }
272
+
273
+ const currentChecksum = md5(output);
274
+ let existingFileContent, existingFileContentWithoutChecksum;
275
+ let existingFileContentChecksum, existingChecksumValue;
276
+
277
+ if (fileExists) {
278
+ existingFileContent = await read(dest, "utf-8");
279
+ const checksumStartIndex = existingFileContent.indexOf(`/* checksum : `);
280
+ const checksumEndIndex = existingFileContent.indexOf(" */");
281
+
282
+ if (checksumStartIndex >= 0) {
283
+ existingFileContentWithoutChecksum = existingFileContent.substring(
284
+ checksumEndIndex + 4
285
+ );
286
+ existingChecksumValue = existingFileContent.substring(
287
+ checksumStartIndex + 14, checksumEndIndex
288
+ );
289
+ existingFileContentChecksum = md5(existingFileContentWithoutChecksum);
290
+ }
291
+ }
292
+
293
+ // if force flag enbabled
294
+ if (force) {
295
+ // current and existing file content are same, and the existing
296
+ // checksum is not modified, then return the existing file content
297
+ if (currentChecksum == existingFileContentChecksum &&
298
+ currentChecksum == existingChecksumValue) {
299
+ return existingFileContent;
300
+ }
301
+ }
302
+ /*
303
+ * 1. current and existing checksum are different.
304
+ * 2. checksum is missing in the existing file:
305
+ * a. existing and current file content are same.
306
+ * b. existing and current file content are different.
307
+ * 3. cds file doesn't exist.
308
+ * 4. checksum of the existing file is modified.
309
+ */
310
+ return "/* checksum : " + currentChecksum + " */\n" + output;
311
+ }
312
+
313
+ async function _getResult(output, as, dest, force, version) {
314
+ let extension = dest.substring(dest.lastIndexOf(".") + 1);
315
+ as = (as === "cds") ? "cdl" : as;
316
+
317
+ // output filepath should simply contain .csn as extension
318
+ if (version === 'rest' && ['swagger', 'openapi3'].includes(extension)) {
319
+ dest = dest.replace('.' + extension, '');
320
+ }
321
+
322
+ if (!_supportedAsFormats().includes(extension)) {
323
+ // dest doesn't have any file extension, so get it
324
+ extension = _getSuffix(as);
325
+ dest += '.' + extension;
326
+ }
327
+
328
+ if (as && as != "csn" && as != "json") {
329
+ // cdsCompiler[as] will convert the csn output into various output formats
330
+ output = cdsCompiler[as](output);
331
+ }
332
+
333
+ switch (as) {
334
+ case "cdl":
335
+ output = await _generateChecksumValidate(dest, output, force);
336
+ break;
337
+ case undefined:
338
+ case "csn":
339
+ case "json":
340
+ output = JSON.stringify(output, null, ' ');
341
+ break;
342
+ default:
343
+ break;
344
+ }
345
+
346
+ return [output, dest];
347
+ }
348
+
349
+ async function _write(result, service, cwd) {
350
+ let dest, output, using, message, extenstion;
351
+ output = result[0];
352
+ dest = result[1];
353
+ await write(dest, output, "utf-8");
354
+
355
+ extenstion = dest.substring(dest.lastIndexOf('.'));
356
+ dest = dest.replace(extenstion, '');
357
+ using = `using { ${service} as external } from './${path.relative('srv', dest).replace(/\\/g, '/')}'`;
358
+ using = require('../util/term').info(using);
359
+ message = `[cds] - imported API to ${path.relative(cwd, dest)}
360
+ > use it in your CDS models through the like of:
361
+
362
+ ${using}
363
+ `;
364
+
365
+ console.log(message);
366
+ }
367
+
368
+ async function _updatePackageJson(dest, service, version, cwd) {
369
+ const package_json = path.resolve(cwd, 'package.json');
370
+ const conf = await exists(package_json) ? require(package_json) : {};
371
+ const requires = ['cds', 'requires'].reduce((p, n) => p[n] || (p[n] = {}), conf);
372
+ if (version !== 'rest') {
373
+ version = (version === "V2") ? 'odata-v2' : 'odata';
374
+ }
375
+ if (!requires[service]) {
376
+ const model = path.relative(cwd, dest);
377
+ cds.env.requires[service] = requires[service] = { kind: version, model };
378
+ await write(package_json, JSON.stringify(conf, null, ' '));
379
+ console.log(`[cds] - updated ./package.json`);
380
+ }
381
+ }
382
+
383
+ async function postProcess(filePath, options, csn, cwd) {
384
+ const service = _getServiceName(csn);
385
+ if (options.out) options.out = _validateAndComputeOutputFilePath(options.out, options.as, filePath);
386
+ const version = options.inputFileVersion;
387
+ const result = await _getResult(csn, options.as, options.out || filePath.replace(/\.[^.]+$/, ''), options.force, version);
388
+ const written = options.dry || await _write(result, service, cwd);
389
+ const registered = options.dry || options.no_save || await _updatePackageJson(result[1].replace(/\.[^.]+$/, ''), service, version, cwd);
390
+ if (options.dry) return console.log(result[0]);
391
+ return Promise.all([written, registered]);
392
+ }
393
+
394
+ async function identifyFile(filepath) {
395
+ let extension = _getInputFileExtension(filepath);
396
+ if (["edmx", "xml"].includes(extension)) {
397
+ return "edmx";
398
+ } else if (["json", "yaml", "yml"].includes(extension)) {
399
+ // based on the file content determine if it is openapi or asyncapi file and return the correct type
400
+ filepath = await isValidInputFile(path.resolve(process.cwd(), filepath));
401
+ const src = await getContentFromFile(filepath);
402
+ //for openapi
403
+ let jsonSrc = JSON.parse(src);
404
+ // eslint-disable-next-line no-prototype-builtins
405
+ if (jsonSrc.hasOwnProperty('openapi') || jsonSrc.hasOwnProperty('swagger')) {
406
+ return "openapi";
407
+ }
408
+ } else
409
+ return extension;
410
+ }
411
+
412
+ function readEnvVariables(options, cliCheck) {
413
+ if (cds.env.import) {
414
+ if (cliCheck) {
415
+ for (let key of commonOptions) {
416
+ if (key !== 'force' && !options[key]) {
417
+ options[key] = cds.env.import[key];
418
+ }
419
+ }
420
+ if (options.as && !options.force) options.force = cds.env.import.force;
421
+ }
422
+ else {
423
+ for (let [key, value] of Object.entries(options)) {
424
+ if (!value) options[key] = cds.env.import[key];
425
+ }
426
+ }
427
+ }
428
+ }
429
+
122
430
  module.exports = {
431
+ generateEDMX2JSON,
123
432
  getVersion,
124
- getSuffix,
125
- supportedFormats,
126
433
  checkForEmptyKeys,
127
- replaceAliasValue
434
+ replaceAliasValue,
435
+ getContentFromFile,
436
+ getContentFromURL,
437
+ isValidInputFile,
438
+ preProcess,
439
+ postProcess,
440
+ identifyFile,
441
+ readEnvVariables,
442
+ processOptions
128
443
  };
@@ -1,21 +1,89 @@
1
- const edm2csn = require('.');
2
- let context={};
3
- context.oDataInfo = {};
4
- context.namespaces = [];
1
+ let cds = require('../cds');
2
+ let { path } = cds.utils;
3
+ let common = require('./common');
4
+ let odata = require('./odata');
5
+ let openapi = require('./openapi');
6
+ let messages = require('./message').getMessages();
7
+
8
+ module.exports = Object.assign(cds_import, {
9
+ from: cds.lazified({
10
+ edmx: cds_import_from_edmx,
11
+ openapi: cds_import_from_openapi
12
+ })
13
+ });
14
+
5
15
  /**
6
16
  * This is the import API function to generate CSN from XML/EDMX files.
7
17
  * @param {string} filepath
8
18
  * - a single valid filepath
9
- * @param {{} | {keepNamespace:_keepNamespace, ...}} options
10
- * - an options object specifying the keepNamespace option on how CSN is to be generated
11
- * - optional parameter
19
+ * @param {{} | {keepNamespace:_keepNamespace, includeNamespaces:_includeNamespaces...}} options
20
+ * - an options object for importing OData files specifying the keepNamespace, includeNamespaces options
21
+ * - Default values for OData V2: {keepNamespace: false, includeNamespaces:"edmx,m,sap"}
22
+ * - Default values for OData V4: {keepNamespace: false, includeNamespaces:"edmx"}
23
+ * - optional parameters
12
24
  * - other import options not supported
13
25
  * @returns {object} CSN
14
26
  */
15
- module.exports = async function cds_import(filepath, options = {keepNamespace : false}) //namespace will be taken as false in case it is not mentioned
16
- {
17
- filepath = await edm2csn.isValidInputFile(filepath);
18
- let edmx= await edm2csn.getMetadataFromFile(filepath);
19
- let csn = await edm2csn.edmx2csn(edmx, !options.keepNamespace && filepath, context);
20
- return csn;
27
+ async function cds_import(filepath, options = { keepNamespace: false }) {
28
+ // identifies the file and calls the respective api
29
+ let fileType = await common.identifyFile(filepath);
30
+ let csn;
31
+ switch (fileType) {
32
+ case "edmx":
33
+ csn = await cds_import_from_edmx(filepath, options);
34
+ break;
35
+ case "openapi":
36
+ csn = await cds_import_from_openapi(filepath, options);
37
+ break;
38
+ default:
39
+ throw new Error(messages.INVALID_INPUT_FILE);
40
+ }
41
+ return csn;
42
+ }
43
+
44
+ /**
45
+ * This is the import API function to generate CSN from XML/EDMX files.
46
+ * @param {string} filepath
47
+ * - a single valid filepath
48
+ * @param {{} | {keepNamespace:_keepNamespace, includeNamespaces:_includeNamespaces...}} options
49
+ * - an options object specifying the keepNamespace, includeNamespaces options on how CSN is to be generated
50
+ * - Default values for OData V2: {keepNamespace: false, includeNamespaces:"edmx,m,sap"}
51
+ * - Default values for OData V4: {keepNamespace: false, includeNamespaces:"edmx"}
52
+ * - optional parameters
53
+ * - other import options not supported
54
+ * @returns {object} CSN
55
+ */
56
+ async function cds_import_from_edmx(filepath, options = { keepNamespace: false }) {
57
+ // validates and reads the input file
58
+ filepath = await common.isValidInputFile(path.resolve(process.cwd(), filepath));
59
+ const src = await common.getContentFromFile(filepath);
60
+ // takes the api specific options and reads it from env
61
+ let odataOptions = { include_namespaces: options.includeNamespaces, keep_namespace: options.keepNamespace };
62
+ if (cds.env.import) {
63
+ common.readEnvVariables(odataOptions, false);
64
+ }
65
+ // generates csn
66
+ odataOptions.include_all_namespaces = false;
67
+ odataOptions.namespaces = [];
68
+ if (odataOptions.include_namespaces) odata.getNamespaces(odataOptions);
69
+ let csn = await odata.edmx2csn(src, !odataOptions.keep_namespace && filepath, odataOptions);
70
+ //reading the file version
71
+ options.inputFileVersion = odataOptions.inputFileVersion;
72
+ // return the csn
73
+ return csn;
74
+ }
75
+
76
+ /**
77
+ * This is the import API function to generate CSN from openapi files.
78
+ * @param {string} filepath
79
+ * - a single valid filepath
80
+ * @returns {object} CSN
81
+ */
82
+ async function cds_import_from_openapi(filepath, options = {}) {
83
+ // validates the input file
84
+ filepath = await common.isValidInputFile(path.resolve(process.cwd(), filepath));
85
+ const src = await common.getContentFromFile(filepath);
86
+ let csn = openapi.openAPI2csn(src);
87
+ options.inputFileVersion = 'rest';
88
+ return csn;
21
89
  }
@@ -3,19 +3,19 @@
3
3
  const messages = {
4
4
  INVALID_EDMX_METADATA: 'The OData model is not valid. Specify the correct OData model.',
5
5
  INVALID_OUTPUT_FILE: 'Please provide an output file with one of these [cds, csn, json] file extension.',
6
- MISSING_ENTITIES: 'There are no entities in the OData model. Specify the correct OData model in the provided file.',
7
6
  SPECIFY_INPUT_FILE: 'Specify an input file that exists.',
8
7
  SPECIFY_OUTPUT_FILE: 'Specify an output file or correct the output file path provided.',
9
8
  MISSING_ENTITY_CONTAINER: 'There is no entity container in the OData model. Specify the correct OData model.',
10
9
  MISSING_ENTITY_SETS: 'There are no entity sets in the OData model. Specify the correct OData model.',
11
- INVALID_INPUT_FILE: 'Input file provided is not valid. Please provide a file with either .edmx or .xml extension.',
10
+ INVALID_INPUT_FILE: 'Input file provided is not valid. Please provide a valid file with either .edmx, .xml extension for OData or .json extension for OpenAPI.',
12
11
  FILE_MODIFIED: 'The file with the same name exists and is been modified. Use --force flag to forcefully overwrite the file.',
13
12
  OUTPUT_FILE_MISMATCH: 'Specify the file extension that --as option supports.',
14
13
  INVALID_AS_OPTION: 'For --as option, please specify one of these output file format [cds, csn, json].',
15
14
  INCORRECT_EXTENSION: 'If --as option is not provided, then please provide either .json or .csn output file extension.',
16
15
  INCORRECT_INPUT_NAMESPACES: 'Invalid value for --include-namespaces option. Specify namespaces as comma-separated list or "*"',
17
16
  MISSING_ASSOCIATION_SETS: 'Input file provided has missing Association Sets. Please check the edmx file.',
18
- COLLECTION_IN_KEY: 'Key Property of an Entity cannot be of the type Collection.'
17
+ COLLECTION_IN_KEY: 'Key Property of an Entity cannot be of the type Collection.',
18
+ INVALID_OPENAPI_FILE: 'The OpenAPI file is not valid. Specify the correct OpenAPI file.'
19
19
  };
20
20
 
21
21
  function getMessages() {
@@ -24,4 +24,4 @@ function getMessages() {
24
24
 
25
25
  module.exports = {
26
26
  getMessages
27
- };
27
+ };