@sap/cds-dk 8.2.3 → 8.4.0
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 +66 -11
- package/bin/build.js +1 -1
- package/bin/cds.js +17 -4
- package/bin/compile/index.js +12 -3
- package/bin/deploy/index.js +22 -3
- package/bin/env.js +3 -2
- package/bin/import.js +24 -14
- package/bin/init.js +8 -4
- package/bin/repl.js +21 -8
- package/bin/util/fuzzySearch.js +8 -5
- package/lib/build/plugins/helm/files/subcharts/content-deployment/Chart.yaml +1 -1
- package/lib/build/plugins/helm/files/subcharts/content-deployment/values.schema.json +1 -1
- package/lib/build/plugins/helm/files/subcharts/content-deployment/values.yaml +1 -1
- package/lib/build/plugins/helm/files/subcharts/web-application/Chart.yaml +1 -1
- package/lib/build/plugins/helm/files/subcharts/web-application/templates/virtual-service.yaml +23 -12
- package/lib/build/plugins/helm/files/subcharts/web-application/values.schema.json +1 -1
- package/lib/build/plugins/helm/files/subcharts/web-application/values.yaml +2 -2
- package/lib/build/util.js +32 -20
- package/lib/compile/to-mermaid.js +87 -0
- package/lib/deploy/to-hana/hana.js +2 -21
- package/lib/env/schemas/cds-rc.js +174 -2
- package/lib/import/asyncapi/parserContext.js +4 -30
- package/lib/import/common.js +2 -2
- package/lib/import/importapi.js +3 -3
- package/lib/import/odata/v2parser.js +3 -2
- package/lib/import/openapi/importOpenAPI.js +622 -537
- package/lib/import/openapi/utilities.js +7 -2
- package/lib/init/constants.js +2 -1
- package/lib/init/index.js +4 -0
- package/lib/init/merge.js +2 -2
- package/lib/init/mvn.js +2 -2
- package/lib/init/projectReader.js +2 -1
- package/lib/init/registries/mta.js +8 -1
- package/lib/init/registries/xs-app.js +10 -0
- package/lib/init/template/approuter/files/package.json +1 -1
- package/lib/init/template/cf-manifest/files/manifest.yml.hbs +3 -1
- package/lib/init/template/cf-manifest/index.js +2 -0
- package/lib/init/template/cloud-logging/files/mta.yaml.hbs +13 -2
- package/lib/init/template/cloud-logging/files/{package.json → package.json.hbs} +5 -1
- package/lib/init/template/cloud-logging/index.js +4 -3
- package/lib/init/template/data/as-csv.js +6 -0
- package/lib/init/template/data/as-json.js +8 -1
- package/lib/init/template/data/index.js +1 -1
- package/lib/init/template/destination/files/mta.yaml.hbs +5 -5
- package/lib/init/template/dynatrace/files/mta.yaml.hbs +22 -6
- package/lib/init/template/dynatrace/files/package.json.hbs +5 -2
- package/lib/init/template/dynatrace/files/values.yaml +15 -0
- package/lib/init/template/dynatrace/index.js +10 -5
- package/lib/init/template/enterprise-messaging-shared/index.js +1 -1
- package/lib/init/template/file-based-messaging/index.js +1 -1
- package/lib/init/template/hana/files/package.json.hbs +2 -0
- package/lib/init/template/hana/index.js +1 -1
- package/lib/init/template/handler/index.js +16 -1
- package/lib/init/template/helm/files/values.yaml.hbs +2 -2
- package/lib/init/template/helm/index.js +6 -1
- package/lib/init/template/html5-repo/files/app-package.json.hbs +3 -1
- package/lib/init/template/html5-repo/files/ui5-deploy.yaml.hbs +7 -0
- package/lib/init/template/html5-repo/index.js +3 -1
- package/lib/init/template/local-messaging/index.js +1 -1
- package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
- package/lib/init/template/mta/index.js +2 -0
- package/lib/init/template/nodejs/files/.vscode/extensions.json +0 -5
- package/lib/init/template/nodejs/files/.vscode/settings.json +1 -1
- package/lib/init/template/nodejs/files/.vscode/tasks.json +0 -2
- package/lib/init/template/nodejs/files/package.json.hbs +1 -1
- package/lib/init/template/postgres/index.js +1 -1
- package/lib/init/template/redis-messaging/index.js +1 -1
- package/lib/init/template/side-by-side-extensibility/files/mta.yaml.hbs +40 -0
- package/lib/init/template/side-by-side-extensibility/files/package.json.hbs +17 -0
- package/lib/init/template/side-by-side-extensibility/index.js +34 -0
- package/lib/init/template/typer/index.js +2 -1
- package/lib/init/template/typescript/files/package.json +2 -2
- package/lib/init/template/workzone-standard/files/manifest.json.hbs +15 -1
- package/lib/init/template/workzone-standard/files/mta.yaml.hbs +11 -2
- package/lib/init/template/workzone-standard/files/xs-app.json.hbs +18 -0
- package/lib/init/template/workzone-standard/index.js +25 -7
- package/lib/init/template/xsuaa/index.js +1 -1
- package/lib/mtx/auth_manager.js +7 -5
- package/lib/mtx/util/errors.js +4 -4
- package/lib/util/fs.js +1 -1
- package/lib/util/jsonc.js +1 -1
- package/lib/util/jsonc.pegjs +6 -2
- package/npm-shrinkwrap.json +78 -149
- package/package.json +1 -1
package/lib/build/util.js
CHANGED
|
@@ -6,6 +6,7 @@ const execAsync = require('util').promisify(cp.exec)
|
|
|
6
6
|
const IS_WIN = require('os').platform() === 'win32'
|
|
7
7
|
const { SEVERITY_ERROR, FILE_EXT_CDS } = require('./constants');
|
|
8
8
|
const DEBUG = cds.debug('cli|build')
|
|
9
|
+
const SECRETS = /(passw)|(cert)|(ca)|(secret)|(key)/i
|
|
9
10
|
|
|
10
11
|
function getProperty(src, segments) {
|
|
11
12
|
segments = Array.isArray(segments) ? segments : segments.split('.')
|
|
@@ -68,31 +69,42 @@ function relativePaths(root, qualifiedPaths) {
|
|
|
68
69
|
return qualifiedPaths
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
function redactCredentials(config
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
72
|
+
function redactCredentials(config) {
|
|
73
|
+
if (typeof config !== 'object' || config === null) {
|
|
74
|
+
return config;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (Array.isArray(config)) {
|
|
78
|
+
return config.map(item => redactCredentials(item));
|
|
79
|
+
} else {
|
|
80
|
+
const newConfig = Object.assign({}, config);
|
|
81
|
+
for (let key in newConfig) {
|
|
82
|
+
if (key === 'credentials') {
|
|
83
|
+
newConfig[key] = _redacted(newConfig[key]);
|
|
84
|
+
} else {
|
|
85
|
+
newConfig[key] = redactCredentials(newConfig[key]);
|
|
86
|
+
}
|
|
80
87
|
}
|
|
81
|
-
return
|
|
82
|
-
}
|
|
88
|
+
return newConfig;
|
|
89
|
+
}
|
|
83
90
|
}
|
|
84
91
|
|
|
85
|
-
/**
|
|
92
|
+
/**
|
|
93
|
+
* Masks password-like strings, also reducing clutter in output
|
|
94
|
+
* @param {any} cred - object or array with credentials
|
|
95
|
+
* @returns {any}
|
|
96
|
+
*/
|
|
86
97
|
function _redacted(cred) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
98
|
+
if (!cred) return cred
|
|
99
|
+
if (Array.isArray(cred)) return cred.map(c => typeof c === 'string' ? '...' : _redacted(c))
|
|
100
|
+
if (typeof cred === 'object') {
|
|
101
|
+
const newCred = Object.assign({}, cred)
|
|
102
|
+
Object.keys(newCred).forEach(k => (typeof newCred[k] === 'string' && SECRETS.test(k)) ? (newCred[k] = '...') : (newCred[k] = _redacted(newCred[k])))
|
|
103
|
+
return newCred
|
|
104
|
+
}
|
|
105
|
+
return cred
|
|
93
106
|
}
|
|
94
|
-
|
|
95
|
-
|
|
107
|
+
|
|
96
108
|
/**
|
|
97
109
|
* Returns a list of fully qualified model names belonging to the '@sap' namespace that cannot be resolved.
|
|
98
110
|
* E.g. the module might NOT have been installed.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
const cds = require('../cds')
|
|
2
2
|
|
|
3
3
|
module.exports = function to_mermaid (model, options={}) {
|
|
4
|
+
if (typeof model === 'string' && /mta.*\.ya?ml/.test(model)) return to_mta_mermaid(model)
|
|
5
|
+
|
|
4
6
|
options = Object.assign({
|
|
5
7
|
assocnames: false, // include association names
|
|
6
8
|
elements : false, // include all elements { falsy | 'all'|true | 'keys' }
|
|
@@ -119,3 +121,88 @@ function resolveTargets (query) {
|
|
|
119
121
|
|
|
120
122
|
return targets
|
|
121
123
|
}
|
|
124
|
+
|
|
125
|
+
function to_mta_mermaid (file) {
|
|
126
|
+
const content = cds.utils.fs.readFileSync(file, 'utf8')
|
|
127
|
+
const mta = cds.utils.yaml.parse(content)
|
|
128
|
+
const { modules = [], resources = [] } = mta
|
|
129
|
+
|
|
130
|
+
const all = new Set([...modules.map(m => m.name), ...resources.map(r => r.name)])
|
|
131
|
+
const provided = new Set()
|
|
132
|
+
const required = new Set()
|
|
133
|
+
|
|
134
|
+
let diag = 'graph LR\n'
|
|
135
|
+
|
|
136
|
+
const appModules = modules.filter(module => module.provides && module.provides.length > 0)
|
|
137
|
+
const utilityModules = modules.filter(module => !module.provides || module.provides.length === 0)
|
|
138
|
+
|
|
139
|
+
diag += ' subgraph Modules\n'
|
|
140
|
+
appModules.forEach(module => {
|
|
141
|
+
diag += ` subgraph ${module.name}\n`
|
|
142
|
+
module.provides.forEach(provide => {
|
|
143
|
+
provided.add(provide.name)
|
|
144
|
+
diag += ` ${provide.name}["${provide.name}"]\n`
|
|
145
|
+
})
|
|
146
|
+
diag += ` end\n`
|
|
147
|
+
})
|
|
148
|
+
utilityModules.forEach(module => {
|
|
149
|
+
diag += ` ${module.name}["${module.name}"]:::module\n`
|
|
150
|
+
})
|
|
151
|
+
diag += ' end\n'
|
|
152
|
+
|
|
153
|
+
diag += ' subgraph Resources\n'
|
|
154
|
+
resources.forEach(resource => {
|
|
155
|
+
diag += ` ${resource.name}["${resource.name}"]:::resource\n`
|
|
156
|
+
})
|
|
157
|
+
diag += ' end\n'
|
|
158
|
+
|
|
159
|
+
modules.forEach(module => {
|
|
160
|
+
if (module.requires) {
|
|
161
|
+
module.requires.forEach(require => {
|
|
162
|
+
required.add(require.name)
|
|
163
|
+
if (!all.has(require.name) && !provided.has(require.name)) {
|
|
164
|
+
diag += ` ${module.name} -->|requires| ${require.name}:::missing\n`
|
|
165
|
+
} else {
|
|
166
|
+
diag += ` ${module.name} -->|requires| ${require.name}\n`
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
})
|
|
171
|
+
resources.forEach(resource => {
|
|
172
|
+
if (resource.requires) {
|
|
173
|
+
resource.requires.forEach(require => {
|
|
174
|
+
required.add(require.name)
|
|
175
|
+
if (!all.has(require.name) && !provided.has(require.name)) {
|
|
176
|
+
diag += ` ${resource.name} -->|requires| ${require.name}:::missing\n`
|
|
177
|
+
} else {
|
|
178
|
+
diag += ` ${resource.name} -->|requires| ${require.name}\n`
|
|
179
|
+
}
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
provided.forEach(api => {
|
|
185
|
+
if (!required.has(api)) {
|
|
186
|
+
diag += ` class ${api} unused\n`
|
|
187
|
+
} else {
|
|
188
|
+
diag += ` class ${api} api\n`
|
|
189
|
+
}
|
|
190
|
+
})
|
|
191
|
+
modules.forEach(module => {
|
|
192
|
+
diag += ` class ${module.name} module\n`
|
|
193
|
+
})
|
|
194
|
+
resources.forEach(resource => {
|
|
195
|
+
diag += ` class ${resource.name} resource\n`
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
diag += `
|
|
199
|
+
classDef module fill:#36aeff,stroke:#333,stroke-width:2px;
|
|
200
|
+
classDef resource fill:#2bab43,stroke:#333,stroke-width:2px;
|
|
201
|
+
classDef api fill:#e03da4,stroke:#333,stroke-width:2px;
|
|
202
|
+
classDef missing fill:#ffcccc,stroke:#ff0000,stroke-width:2px,color:#ff0000;
|
|
203
|
+
classDef unused fill:#ffcccc,stroke:#ff0000,stroke-width:2px,color:#ff0000;
|
|
204
|
+
`
|
|
205
|
+
|
|
206
|
+
return diag
|
|
207
|
+
}
|
|
208
|
+
|
|
@@ -38,7 +38,7 @@ module.exports = new class HanaDeployer {
|
|
|
38
38
|
async deploy(options = {}) {
|
|
39
39
|
let { model, serviceName: pServiceName, tunnelAddress, vcapFile, undeployWhitelist, hdiOptions = {}, dry, storeCredentials } = options;
|
|
40
40
|
|
|
41
|
-
options.for
|
|
41
|
+
options.for ??= 'hybrid';
|
|
42
42
|
|
|
43
43
|
if (model) {
|
|
44
44
|
throw `Specifying a CDS model for HANA deployment is not supported.
|
|
@@ -168,7 +168,7 @@ Therefore, specifying the CDS model is not required when calling 'cds deploy'.`;
|
|
|
168
168
|
console.log(`Using container ${bold(cfServiceInstanceName)}`);
|
|
169
169
|
|
|
170
170
|
const cfConfig = cfServiceInstanceMta?.parameters?.config;
|
|
171
|
-
const serviceInstance = await
|
|
171
|
+
const serviceInstance = await cfUtil.getOrCreateService('hana', 'hdi-shared', cfServiceInstanceName, cfConfig);
|
|
172
172
|
|
|
173
173
|
const cfServiceInstanceKeyName = serviceKeyName ?? `${cfServiceInstanceName}-key`;
|
|
174
174
|
let credentials = await cfUtil.getOrCreateServiceKey(serviceInstance, cfServiceInstanceKeyName, { permissions: 'development' });
|
|
@@ -182,25 +182,6 @@ Therefore, specifying the CDS model is not required when calling 'cds deploy'.`;
|
|
|
182
182
|
return { cfServiceInstanceName, cfServiceInstanceKeyName, serviceKey: credentials, serviceInstance }
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
|
|
186
|
-
async createHanaService(instanceName, cfConfig) {
|
|
187
|
-
// hana or hanatrial, error if neither found
|
|
188
|
-
try {
|
|
189
|
-
return await cfUtil.getOrCreateService('hana', 'hdi-shared', instanceName, cfConfig);
|
|
190
|
-
} catch (error) {
|
|
191
|
-
if (error.command && /offering .* not found/i.test(error.command.stderr)) {
|
|
192
|
-
console.log(`Falling back to 'hanatrial'`);
|
|
193
|
-
return await cfUtil.getOrCreateService('hanatrial', 'hdi-shared', instanceName, cfConfig);
|
|
194
|
-
}
|
|
195
|
-
else if (error.command && /no database/i.test(error.command.stderr)) {
|
|
196
|
-
console.log(`No database connected to 'hana' service. Falling back to 'hanatrial'`);
|
|
197
|
-
return await cfUtil.getOrCreateService('hanatrial', 'hdi-shared', instanceName, cfConfig);
|
|
198
|
-
}
|
|
199
|
-
throw error;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
185
|
_validateCredentials(credentials, cfServiceInstanceKey) {
|
|
205
186
|
if (!credentials) {
|
|
206
187
|
throw `Could not create service key ${bold(cfServiceInstanceKey)}.`;
|
|
@@ -131,6 +131,141 @@ module.exports = {
|
|
|
131
131
|
}
|
|
132
132
|
},
|
|
133
133
|
|
|
134
|
+
import: {
|
|
135
|
+
type: "object",
|
|
136
|
+
description: "Set CDS import configurations.",
|
|
137
|
+
additionalProperties: false,
|
|
138
|
+
properties: {
|
|
139
|
+
as: {
|
|
140
|
+
type: "string",
|
|
141
|
+
description: "Converts the input file into one of these supported formats: cds, csn or json.",
|
|
142
|
+
$ref: "#/$defs/import-options/as"
|
|
143
|
+
},
|
|
144
|
+
from: {
|
|
145
|
+
type: "string",
|
|
146
|
+
description: "Imports the model from the one of the given options: edmx, openapi or asyncapi.",
|
|
147
|
+
$ref: "#/$defs/import-options/from"
|
|
148
|
+
},
|
|
149
|
+
force: {
|
|
150
|
+
type: "boolean",
|
|
151
|
+
description: "Forcefully overwrites the contents in the CDS file and updates the checksum",
|
|
152
|
+
},
|
|
153
|
+
no_save: {
|
|
154
|
+
type: "boolean",
|
|
155
|
+
description: "Skips updating ./package.json.",
|
|
156
|
+
},
|
|
157
|
+
out: {
|
|
158
|
+
type: "string",
|
|
159
|
+
description: "Output file written to the specified location."
|
|
160
|
+
},
|
|
161
|
+
dry: {
|
|
162
|
+
type: "boolean",
|
|
163
|
+
description: "Writes the converted csn to stdout only.",
|
|
164
|
+
},
|
|
165
|
+
keepNamespace: {
|
|
166
|
+
type: "boolean",
|
|
167
|
+
description: "Keeps the original namespace from the edmx content instead of using the filename by default.",
|
|
168
|
+
default: false
|
|
169
|
+
},
|
|
170
|
+
includeNamespaces: {
|
|
171
|
+
type: "string",
|
|
172
|
+
description: "Imports only entities matching to the given list of namespaces."
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
export: {
|
|
178
|
+
type: "object",
|
|
179
|
+
description: "Customize cds compile settings",
|
|
180
|
+
additionalProperties: false,
|
|
181
|
+
properties: {
|
|
182
|
+
asyncapi: {
|
|
183
|
+
type: "object",
|
|
184
|
+
description: "AsyncAPI settings for cds compile",
|
|
185
|
+
additionalProperties: false,
|
|
186
|
+
properties: {
|
|
187
|
+
application_namespace: {
|
|
188
|
+
type: "string",
|
|
189
|
+
description: "The registered namespace of the application"
|
|
190
|
+
},
|
|
191
|
+
merged: {
|
|
192
|
+
type: "object",
|
|
193
|
+
description: "properties that needs to be there when merged option is used",
|
|
194
|
+
additionalProperties: false,
|
|
195
|
+
properties: {
|
|
196
|
+
title: {
|
|
197
|
+
type: "string",
|
|
198
|
+
description: "Title to be used for merged doc"
|
|
199
|
+
},
|
|
200
|
+
version: {
|
|
201
|
+
type: "string",
|
|
202
|
+
description: "Version to be used for merged doc"
|
|
203
|
+
},
|
|
204
|
+
short_text: {
|
|
205
|
+
type: "string",
|
|
206
|
+
description: "Short decription of the AsyncAPIs"
|
|
207
|
+
},
|
|
208
|
+
description: {
|
|
209
|
+
type: "string",
|
|
210
|
+
description: "Description to be used for the merged doc"
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
event_spec_version: {
|
|
215
|
+
type: "string",
|
|
216
|
+
description: "Mentions the version of AsyncAPI spec"
|
|
217
|
+
},
|
|
218
|
+
event_source: {
|
|
219
|
+
type: "string",
|
|
220
|
+
description: "Event source information",
|
|
221
|
+
default: "{region}/{applicationNamespace}/{instanceId}",
|
|
222
|
+
},
|
|
223
|
+
event_source_params: {
|
|
224
|
+
type: "object",
|
|
225
|
+
description: "Parameters related to the source of event",
|
|
226
|
+
default: {
|
|
227
|
+
region: {
|
|
228
|
+
"description": "The regional context of the application.",
|
|
229
|
+
"schema": {
|
|
230
|
+
"type": "string"
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
applicationNamespace: {
|
|
234
|
+
"description": "The registered namespace of the application.",
|
|
235
|
+
"schema": {
|
|
236
|
+
"type": "string"
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
instanceId: {
|
|
240
|
+
"description": "The instance id (tenant, installation, ...) of the application.",
|
|
241
|
+
"schema": {
|
|
242
|
+
"type": "string"
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
additionalProperties: false,
|
|
247
|
+
region: {
|
|
248
|
+
type: "string",
|
|
249
|
+
description: "The regional context of the application"
|
|
250
|
+
},
|
|
251
|
+
applicationNamespace: {
|
|
252
|
+
type: "string",
|
|
253
|
+
description: "The registered namespace of the application"
|
|
254
|
+
},
|
|
255
|
+
instanceId: {
|
|
256
|
+
type: "string",
|
|
257
|
+
description: "The instance id (tenant, installation, ...) of the application."
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
event_characteristics: {
|
|
261
|
+
type: "object",
|
|
262
|
+
description: "The characteristics defined for events",
|
|
263
|
+
additionalProperties: true
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
},
|
|
134
269
|
// deploy specific schema
|
|
135
270
|
deploy: {
|
|
136
271
|
type: "object",
|
|
@@ -164,7 +299,8 @@ module.exports = {
|
|
|
164
299
|
"mtx-extension",
|
|
165
300
|
"mtx",
|
|
166
301
|
"node-cf",
|
|
167
|
-
"java-cf"
|
|
302
|
+
"java-cf",
|
|
303
|
+
"helm"
|
|
168
304
|
],
|
|
169
305
|
enumDescriptions: [
|
|
170
306
|
"Node.js build plugin",
|
|
@@ -174,7 +310,8 @@ module.exports = {
|
|
|
174
310
|
"MTX extension build plugin",
|
|
175
311
|
"MTX build plugin",
|
|
176
312
|
"Node.js Cloud Foundry build plugin",
|
|
177
|
-
"Java Cloud Foundry build plugin"
|
|
313
|
+
"Java Cloud Foundry build plugin",
|
|
314
|
+
"Helm chart build plugin"
|
|
178
315
|
]
|
|
179
316
|
},
|
|
180
317
|
|
|
@@ -193,6 +330,41 @@ module.exports = {
|
|
|
193
330
|
}
|
|
194
331
|
}
|
|
195
332
|
]
|
|
333
|
+
},
|
|
334
|
+
|
|
335
|
+
import_options: {
|
|
336
|
+
from: {
|
|
337
|
+
oneOf: [
|
|
338
|
+
{
|
|
339
|
+
const: "asyncapi",
|
|
340
|
+
description: "AsyncAPI specification"
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
const: "edmx",
|
|
344
|
+
description: "OData specification"
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
const: "openapi",
|
|
348
|
+
description: "OpenAPI specification"
|
|
349
|
+
}
|
|
350
|
+
]
|
|
351
|
+
},
|
|
352
|
+
as: {
|
|
353
|
+
oneOf: [
|
|
354
|
+
{
|
|
355
|
+
const: "cds",
|
|
356
|
+
description: "Converts the input file into cds format"
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
const: "csn",
|
|
360
|
+
description: "Converts the input file into csn format"
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
const: "json",
|
|
364
|
+
description: "Converts the input file into json format"
|
|
365
|
+
}
|
|
366
|
+
]
|
|
367
|
+
}
|
|
196
368
|
}
|
|
197
369
|
}
|
|
198
370
|
}
|
|
@@ -6,12 +6,11 @@ module.exports = class ParserContext {
|
|
|
6
6
|
* @constructor
|
|
7
7
|
*/
|
|
8
8
|
constructor(content) {
|
|
9
|
-
this.topics = this.getTopics(content);
|
|
10
9
|
this.services = this.getServicesFromContent(content);
|
|
11
10
|
}
|
|
12
11
|
|
|
13
|
-
getTopicName(
|
|
14
|
-
return
|
|
12
|
+
getTopicName(eventName) {
|
|
13
|
+
return eventName.startsWith('ce/') ? eventName.substring(3) : eventName;
|
|
15
14
|
}
|
|
16
15
|
|
|
17
16
|
getEventName(messageRefString) {
|
|
@@ -19,28 +18,6 @@ module.exports = class ParserContext {
|
|
|
19
18
|
return lastSlashIndex == -1 ? '' : messageRefString.substring(lastSlashIndex + 1);
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
/**
|
|
23
|
-
* Return an obect with topic annotations for messages
|
|
24
|
-
*/
|
|
25
|
-
getTopics(content) {
|
|
26
|
-
const topics = {};
|
|
27
|
-
|
|
28
|
-
Object.entries(content.channels).forEach(([key, value]) => {
|
|
29
|
-
const topic = this.getTopicName(key);
|
|
30
|
-
if (value.subscribe && value.subscribe.message && value.subscribe.message.$ref) {
|
|
31
|
-
const event = this.getEventName(value.subscribe.message.$ref);
|
|
32
|
-
topics[event] = topic;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (value.publish && value.publish.message && value.publish.message.$ref) {
|
|
36
|
-
const event = this.getEventName(value.publish.message.$ref);
|
|
37
|
-
topics[event] = topic;
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
return topics;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
21
|
/**
|
|
45
22
|
* Returns services from the asyncapi json object along with the events and annotations.
|
|
46
23
|
* @returns an object with all the services.
|
|
@@ -49,7 +26,7 @@ module.exports = class ParserContext {
|
|
|
49
26
|
const services = {};
|
|
50
27
|
const serviceAnnotations = this.getServiceAnnotations(content);
|
|
51
28
|
|
|
52
|
-
Object.entries(content.components.messages).forEach(([
|
|
29
|
+
Object.entries(content.components.messages).forEach(([, value]) => {
|
|
53
30
|
let eventName;
|
|
54
31
|
// Message name should be used to capture the event name
|
|
55
32
|
if (value.name) {
|
|
@@ -71,10 +48,7 @@ module.exports = class ParserContext {
|
|
|
71
48
|
const eventAnnotations = this.getEventAnnotations(value);
|
|
72
49
|
|
|
73
50
|
// add topic annotation
|
|
74
|
-
|
|
75
|
-
eventAnnotations['@topic'] = this.topics[key];
|
|
76
|
-
}
|
|
77
|
-
|
|
51
|
+
eventAnnotations['@topic'] = this.getTopicName(eventName);
|
|
78
52
|
let properties = {};
|
|
79
53
|
let types = {};
|
|
80
54
|
|
package/lib/import/common.js
CHANGED
|
@@ -17,7 +17,7 @@ let optionsMapping = {
|
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
let apiOptions = ['includeNamespaces', 'keepNamespace', 'beta'];
|
|
20
|
-
let commonOptions = ['no_copy', 'no_save', 'out', 'dry', 'as', 'from', 'force', 'config', 'destination'];
|
|
20
|
+
let commonOptions = ['no_copy', 'no_save', 'out', 'dry', 'as', 'from', 'force', 'config', 'destination', 'name'];
|
|
21
21
|
|
|
22
22
|
async function generateEDMX2JSON(edmx) {
|
|
23
23
|
let cjson = convert.xml2json(edmx, {
|
|
@@ -344,7 +344,7 @@ async function _updatePackageJson(dest, services, kind, cwd, config, destination
|
|
|
344
344
|
if (!config && destination) {
|
|
345
345
|
config = { "[production]": { credentials: { destination } } };
|
|
346
346
|
}
|
|
347
|
-
|
|
347
|
+
|
|
348
348
|
let package_json_updated = false;
|
|
349
349
|
for (let service of services) {
|
|
350
350
|
// existing service configuration data can be updated, e.g. in case of delta imports
|
package/lib/import/importapi.js
CHANGED
|
@@ -7,11 +7,11 @@ let asyncapi = require('./asyncapi');
|
|
|
7
7
|
let messages = require('./message').getMessages();
|
|
8
8
|
|
|
9
9
|
module.exports = Object.assign(cds_import, {
|
|
10
|
-
from:
|
|
10
|
+
from: {
|
|
11
11
|
edmx: cds_import_from_edmx,
|
|
12
12
|
openapi: cds_import_from_openapi,
|
|
13
13
|
asyncapi: cds_import_from_asyncapi
|
|
14
|
-
}
|
|
14
|
+
}
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -95,7 +95,7 @@ async function cds_import_from_openapi(filepath, options = {}) {
|
|
|
95
95
|
return csn;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
/**
|
|
98
|
+
/**
|
|
99
99
|
* This is the import API function to generate CSN from asyncapi files.
|
|
100
100
|
* @param {string} filepath
|
|
101
101
|
* - a single valid filepath
|
|
@@ -1650,8 +1650,9 @@ function _generateEDMXJSON2CSN(jsonObj, ignorePersistenceSkip, parserContext) {
|
|
|
1650
1650
|
}
|
|
1651
1651
|
|
|
1652
1652
|
// Construct CSN entity based on EDMX entity
|
|
1653
|
-
let entityJson = jsonObj["edmx:Edmx"]["edmx:DataServices"].Schema.EntityType;
|
|
1654
|
-
if (
|
|
1653
|
+
let entityJson = jsonObj["edmx:Edmx"]["edmx:DataServices"].Schema.EntityType;
|
|
1654
|
+
// if entityJson exists(ignoring the case of no entity) and is not an array, convert it to an array to handle the case of single entity
|
|
1655
|
+
if (entityJson && !Array.isArray(entityJson)) entityJson = [entityJson];
|
|
1655
1656
|
const definitions = [];
|
|
1656
1657
|
|
|
1657
1658
|
if (parserContext.mockServerUc) {
|