@sap/cds-dk 4.9.5 → 6.0.1
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.
- package/CHANGELOG.md +73 -0
- package/bin/activate.js +4 -4
- package/bin/add.js +11 -5
- package/bin/bind.js +16 -28
- package/bin/build/all.js +2 -2
- package/bin/build/index.js +12 -19
- package/bin/cds.js +16 -17
- package/bin/compile/index.js +12 -3
- package/bin/deploy/index.js +14 -14
- package/bin/deploy/to-hana.js +4 -4
- package/bin/deploy/to-sqlite.js +1 -1
- package/bin/env.js +13 -4
- package/bin/eval.js +1 -1
- package/bin/fix-redirects.js +1 -1
- package/bin/import.js +44 -179
- package/bin/repl.js +1 -1
- package/bin/watch.js +10 -15
- package/lib/bind/BindingManager.js +87 -0
- package/lib/bind/bindingResolver.js +14 -85
- package/lib/bind/bindingUtil.js +18 -11
- package/lib/bind/cfKeyProvider.js +58 -29
- package/lib/bind/kubernetesCredentialsProvider.js +44 -21
- package/lib/bind/userCdsrcJsonStorageProvider.js +12 -18
- package/lib/cds.js +13 -0
- package/lib/client/base_command.js +3 -2
- package/lib/client/extend.js +6 -7
- package/lib/client/helper/fs_helper.js +7 -8
- package/lib/client/helper/string_helper.js +6 -1
- package/lib/client/settings_manager.js +38 -45
- package/lib/compile/index.js +9 -10
- package/lib/compile/openapi/csdl2openapi.js +151 -43
- package/lib/compile/openapi/index.js +2 -2
- package/lib/compile/to-xsuaa.js +3 -2
- package/lib/import/common.js +342 -27
- package/lib/import/importapi.js +81 -13
- package/lib/import/message.js +4 -4
- package/lib/import/odata/index.js +141 -0
- package/lib/import/{utils → odata/metadataconverter}/MetadataConverter.js +2 -2
- package/lib/import/{utils → odata/metadataconverter}/MetadataConverterFactory.js +1 -1
- package/lib/import/{utils → odata/util}/MultiMap.js +0 -0
- package/lib/import/{v2parser.js → odata/v2parser.js} +405 -468
- package/lib/import/{v4parser.js → odata/v4parser.js} +311 -322
- package/lib/import/{vocabularies → odata/vocabularies}/Org.OData.Aggregation.V1.json +0 -0
- package/lib/import/{vocabularies → odata/vocabularies}/Org.OData.Authorization.V1.json +0 -0
- package/lib/import/{vocabularies → odata/vocabularies}/Org.OData.Capabilities.V1.json +0 -0
- package/lib/import/{vocabularies → odata/vocabularies}/Org.OData.Core.V1.json +0 -0
- package/lib/import/{vocabularies → odata/vocabularies}/Org.OData.Measures.V1.json +0 -0
- package/lib/import/{vocabularies → odata/vocabularies}/Org.OData.Validation.V1.json +0 -0
- package/lib/import/openapi/importOpenAPI.js +521 -0
- package/lib/import/openapi/index.js +19 -0
- package/lib/import/openapi/utilities.js +38 -0
- package/lib/index.js +1 -1
- package/lib/init/constants.js +7 -2
- package/lib/init/index.js +10 -3
- package/lib/init/template/_merging/existences.js +79 -19
- package/lib/init/template/approuter/files/mta.yaml.hbs +25 -11
- package/lib/init/template/approuter/files/package.json +1 -1
- package/lib/init/template/approuter/files/xs-app.json.hbs +7 -0
- package/lib/init/template/approuter/index.js +61 -54
- package/lib/init/template/auditlog/index.js +2 -2
- package/lib/init/template/data/index.js +2 -2
- package/lib/init/template/hana/files/mta.yaml.hbs +17 -17
- package/lib/init/template/hana/index.js +8 -4
- package/lib/init/template/helm/index.js +39 -0
- package/lib/init/template/helm/update/index.js +28 -0
- package/lib/init/template/java/index.js +7 -9
- package/lib/init/template/kibana-logging/index.js +5 -6
- package/lib/init/template/mta/index.js +4 -4
- package/lib/init/template/mtx/files/java/package.json +9 -9
- package/lib/init/template/mtx/files/mta.yaml.hbs +0 -7
- package/lib/init/template/mtx/files/xs-security.json.hbs +11 -20
- package/lib/init/template/mtx/index.js +50 -57
- package/lib/init/template/nodejs/files/package.json.hbs +2 -2
- package/lib/init/template/notebook/index.js +2 -0
- package/lib/init/template/templateBase.js +6 -4
- package/lib/init/template/xsuaa/index.js +9 -5
- package/lib/init/util/fsUtil.js +25 -10
- package/lib/init/util/logger.js +1 -1
- package/lib/init/util/mvnArchetypeUtil.js +4 -10
- package/lib/init/util/projectReader.js +16 -8
- package/lib/init/util/templateUtil.js +30 -34
- package/lib/k8s/ChartAdder.js +65 -0
- package/lib/k8s/ChartBuilder.js +186 -0
- package/lib/k8s/Context.js +71 -0
- package/lib/k8s/ImageUtil.js +21 -0
- package/lib/k8s/Model.d.ts +53 -0
- package/lib/k8s/auditlog/index.js +29 -0
- package/lib/k8s/auditlog/templates/auditlog.yaml +1 -0
- package/lib/k8s/buildModel.js +70 -0
- package/lib/k8s/connectivity/index.js +74 -0
- package/lib/k8s/connectivity/templates/connectivity-binding.yaml +9 -0
- package/lib/k8s/connectivity/templates/connectivity-proxy-info.yaml +16 -0
- package/lib/k8s/connectivity/templates/connectivity.yaml +1 -0
- package/lib/k8s/deployment/index.js +81 -0
- package/lib/k8s/deployment/subchart/Chart.yaml +6 -0
- package/lib/k8s/deployment/subchart/templates/_helpers.tpl +156 -0
- package/lib/k8s/deployment/subchart/templates/api-rule.yaml +24 -0
- package/lib/k8s/deployment/subchart/templates/deployment.yaml +110 -0
- package/lib/k8s/deployment/subchart/templates/network-policy.yaml +16 -0
- package/lib/k8s/deployment/subchart/templates/pod-disruption-budget.yaml +11 -0
- package/lib/k8s/deployment/subchart/templates/secret.yaml +10 -0
- package/lib/k8s/deployment/subchart/templates/service-binding.yaml +27 -0
- package/lib/k8s/deployment/subchart/templates/service.yaml +11 -0
- package/lib/k8s/deployment/subchart/values-lint.yaml +8 -0
- package/lib/k8s/deployment/subchart/values.schema.json +449 -0
- package/lib/k8s/deployment/subchart/values.yaml +76 -0
- package/lib/k8s/deployment/subchart-override/templates/_web_application_helpers.tpl +81 -0
- package/lib/k8s/destinations/index.js +40 -0
- package/lib/k8s/destinations/lib.js +16 -0
- package/lib/k8s/destinations/templates/destinations.yaml +1 -0
- package/lib/k8s/docker/push.js +8 -0
- package/lib/k8s/event-mesh/index.js +53 -0
- package/lib/k8s/event-mesh/lib.js +9 -0
- package/lib/k8s/event-mesh/templates/event-mesh.yaml +1 -0
- package/lib/k8s/hana-deployer/index.js +38 -0
- package/lib/k8s/hana-deployer/templates/hana-deployer-job.yaml +41 -0
- package/lib/k8s/helm/Release.js +80 -0
- package/lib/k8s/html5-apps-deployer/index.js +43 -0
- package/lib/k8s/html5-apps-deployer/templates/_html5_deployment_helpers.tpl +16 -0
- package/lib/k8s/html5-apps-deployer/templates/html5-apps-deployer-job.yaml +53 -0
- package/lib/k8s/html5-apps-repo-host/index.js +26 -0
- package/lib/k8s/html5-apps-repo-host/lib.js +16 -0
- package/lib/k8s/html5-apps-repo-host/templates/html5-apps-repo-host.yaml +1 -0
- package/lib/k8s/index.js +153 -0
- package/lib/k8s/modules.js +36 -0
- package/lib/k8s/multitenancy/index.js +24 -0
- package/lib/k8s/multitenancy/lib.js +25 -0
- package/lib/k8s/multitenancy/templates/saas-registry.yaml +19 -0
- package/lib/k8s/readProject.js +14 -0
- package/lib/k8s/resources/helm/chart/templates/NOTES.txt +11 -0
- package/lib/k8s/resources/helm/chart/templates/_deployment_helpers.tpl +221 -0
- package/lib/k8s/resources/helm/chart/templates/_helpers.tpl +167 -0
- package/lib/k8s/resources/helm/chart/templates/_sapcp_helpers.tpl +103 -0
- package/lib/k8s/util.js +186 -0
- package/lib/k8s/wrapFeature.js +55 -0
- package/lib/k8s/xsuaa/index.js +64 -0
- package/lib/k8s/xsuaa/lib.js +14 -0
- package/lib/k8s/xsuaa/templates/xsuaa.yaml +1 -0
- package/lib/util/exec.js +1 -1
- package/lib/util/write.js +1 -1
- package/lib/watch/node-watch.js +43 -14
- package/npm-shrinkwrap.json +1272 -2792
- package/package.json +5 -5
- package/lib/import/index.js +0 -235
package/lib/import/common.js
CHANGED
|
@@ -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
|
|
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
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
112
|
-
|
|
113
|
-
"
|
|
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
|
|
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
|
};
|
package/lib/import/importapi.js
CHANGED
|
@@ -1,21 +1,89 @@
|
|
|
1
|
-
|
|
2
|
-
let
|
|
3
|
-
|
|
4
|
-
|
|
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
|
|
11
|
-
* -
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
}
|
package/lib/import/message.js
CHANGED
|
@@ -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 .
|
|
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
|
+
};
|