@sap/cds-dk 6.5.1 → 6.6.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 +35 -0
- package/bin/activate.js +7 -0
- package/bin/add.js +1 -2
- package/bin/build/all.js +14 -9
- package/bin/cds.js +11 -8
- package/bin/compile/index.js +13 -3
- package/bin/env.js +16 -25
- package/bin/extend.js +8 -0
- package/bin/init.js +0 -3
- package/bin/login.js +3 -7
- package/bin/logout.js +2 -7
- package/bin/migrate.js +5 -2
- package/bin/watch.js +4 -5
- package/lib/client/activate.js +1 -1
- package/lib/client/helper/errors.js +2 -1
- package/lib/client/params.js +4 -3
- package/lib/client/pull.js +31 -5
- package/lib/client/push.js +3 -3
- package/lib/client/settings_manager.js +6 -6
- package/lib/client/subscription.js +1 -1
- package/lib/compile/asyncapi/channels.js +22 -0
- package/lib/compile/asyncapi/components/messageTraits/index.js +89 -0
- package/lib/compile/asyncapi/components/messages/index.js +150 -0
- package/lib/compile/asyncapi/components/schemas/annotations.js +13 -0
- package/lib/compile/asyncapi/components/schemas/array.js +8 -0
- package/lib/compile/asyncapi/components/schemas/cache.js +14 -0
- package/lib/compile/asyncapi/components/schemas/definition.js +187 -0
- package/lib/compile/asyncapi/components/schemas/enum.js +16 -0
- package/lib/compile/asyncapi/components/schemas/examples.js +10 -0
- package/lib/compile/asyncapi/components/schemas/index.js +14 -0
- package/lib/compile/asyncapi/components/schemas/localized.js +29 -0
- package/lib/compile/asyncapi/components/schemas/primitiveElement.js +41 -0
- package/lib/compile/asyncapi/components/schemas/ref.js +45 -0
- package/lib/compile/asyncapi/components/schemas/utils.js +108 -0
- package/lib/compile/asyncapi/index.js +226 -0
- package/lib/compile/asyncapi/message.js +13 -0
- package/lib/compile/asyncapi/utils.js +27 -0
- package/lib/compile/index.js +1 -0
- package/lib/compile/openapi/csdl2openapi.js +40 -18
- package/lib/import/message.js +3 -1
- package/lib/import/odata/metadataconverter/MetadataConverter.js +1 -1
- package/lib/import/odata/v2parser.js +131 -50
- package/lib/import/odata/v4parser.js +160 -68
- package/lib/import/openapi/importOpenAPI.js +14 -14
- package/lib/init/constants.js +1 -1
- package/lib/init/index.js +11 -21
- package/lib/init/template/_merging/registry-mta.js +15 -26
- package/lib/init/template/approuter/files/package.json +2 -2
- package/lib/init/template/approuter/index.js +6 -12
- package/lib/init/template/auditlog/files/auditlog.yaml +4 -1
- package/lib/init/template/auditlog/index.js +23 -8
- package/lib/init/template/cf-manifest/index.js +4 -14
- package/lib/init/template/connectivity/files/connectivity-proxy-info.yaml +2 -6
- package/lib/init/template/connectivity/files/values.yaml.hbs +5 -8
- package/lib/init/template/connectivity/index.js +2 -9
- package/lib/init/template/data/index.js +0 -4
- package/lib/init/template/destinations/files/destination.yaml +4 -1
- package/lib/init/template/destinations/index.js +25 -10
- package/lib/init/template/enterprise-messaging/files/event-mesh.yaml +4 -1
- package/lib/init/template/enterprise-messaging/files/values.yaml +1 -2
- package/lib/init/template/enterprise-messaging/index.js +28 -20
- package/lib/init/template/extensibility/index.js +23 -31
- package/lib/init/template/hana/files/hana.yaml +4 -1
- package/lib/init/template/hana/index.js +44 -24
- package/lib/init/template/helm/chart/templates/_helpers.tpl +12 -0
- package/lib/init/template/helm/chart/values.root.schema.json +40 -0
- package/lib/init/template/helm/chart/values.schema.json +32 -69
- package/lib/init/template/helm/index.js +26 -16
- package/lib/init/template/helm/subcharts/content-deployment/templates/_helpers.tpl +13 -26
- package/lib/init/template/helm/subcharts/content-deployment/templates/job.yaml +3 -3
- package/lib/init/template/helm/subcharts/content-deployment/templates/service-account.yaml +2 -0
- package/lib/init/template/helm/subcharts/content-deployment/templates/service-binding.yaml +3 -3
- package/lib/init/template/helm/subcharts/content-deployment/templating.md +37 -0
- package/lib/init/template/helm/subcharts/content-deployment/values.md +182 -185
- package/lib/init/template/helm/subcharts/content-deployment/values.schema.json +18 -22
- package/lib/init/template/helm/subcharts/content-deployment/values.yaml +2 -0
- package/lib/init/template/helm/subcharts/service-instance/Chart.yaml +5 -0
- package/lib/init/template/helm/subcharts/service-instance/templates/_helpers.tpl +65 -0
- package/lib/init/template/helm/subcharts/service-instance/templates/serviceinstance.yaml +23 -0
- package/lib/init/template/helm/subcharts/service-instance/templating.md +18 -0
- package/lib/init/template/helm/subcharts/service-instance/values-lint.yaml +2 -0
- package/lib/init/template/helm/subcharts/service-instance/values.md +186 -0
- package/lib/init/template/helm/subcharts/service-instance/values.schema.json +102 -0
- package/lib/init/template/helm/subcharts/service-instance/values.yaml +15 -0
- package/lib/init/template/html5-repo/files/html5-apps-repo-host.yaml +4 -1
- package/lib/init/template/html5-repo/index.js +30 -21
- package/lib/init/template/java/index.js +2 -5
- package/lib/init/template/kibana-logging/index.js +7 -10
- package/lib/init/template/lint/index.js +2 -3
- package/lib/init/template/mta/files/mta.yaml.hbs +4 -2
- package/lib/init/template/mta/index.js +7 -11
- package/lib/init/template/mtx/index.js +0 -5
- package/lib/init/template/multitenancy/files/java/package.json +16 -7
- package/lib/init/template/multitenancy/files/mta.yaml.hbs +11 -3
- package/lib/init/template/multitenancy/files/saas-registry-secret.yaml +9 -0
- package/lib/init/template/multitenancy/files/saas-registry.yaml +4 -17
- package/lib/init/template/multitenancy/files/service-manager.yaml +4 -1
- package/lib/init/template/multitenancy/files/values.yaml.hbs +15 -3
- package/lib/init/template/multitenancy/index.js +56 -31
- package/lib/init/template/nodejs/index.js +4 -7
- package/lib/init/template/notebook/index.js +1 -3
- package/lib/init/template/pipeline/index.js +2 -5
- package/lib/init/template/samples/index.js +6 -11
- package/lib/init/template/templateBase.js +10 -17
- package/lib/init/template/toggles/index.js +2 -6
- package/lib/init/template/xsuaa/files/values.yaml.hbs +0 -1
- package/lib/init/template/xsuaa/files/xsuaa.yaml +4 -1
- package/lib/init/template/xsuaa/index.js +27 -23
- package/lib/init/types.d.ts +0 -81
- package/lib/init/util/merge.js +23 -25
- package/lib/init/util/projectReader.js +27 -24
- package/lib/lint/Linter.js +31 -13
- package/lib/watch/livereload-server.js +21 -14
- package/lib/watch/node-watch.js +51 -49
- package/npm-shrinkwrap.json +546 -453
- package/package.json +2 -2
- package/readme.md +5 -0
- package/lib/init/template/connectivity/files/connectivity-binding.yaml +0 -9
- package/lib/init/template/connectivity/files/connectivity.yaml +0 -1
- package/lib/init/template/multitenancy/files/xsuaa.yaml +0 -1
- /package/lib/init/template/hana/files/{chart.yaml → hana-deployer.yaml} +0 -0
- /package/lib/init/template/html5-repo/files/{chart.yaml → html5-apps-deployer.yaml} +0 -0
- /package/lib/init/template/multitenancy/files/{chart.yaml → sidecar.yaml} +0 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
|
|
2
|
+
function toString(element) {
|
|
3
|
+
let schema = getBaseTypeStructure("string");
|
|
4
|
+
|
|
5
|
+
if ('length' in element && typeof element.length === 'number') {
|
|
6
|
+
schema.maxLength = element.length;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return schema;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function getBaseTypeStructure(type) {
|
|
13
|
+
return { type: type };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function getFormatStructure(format, example) {
|
|
17
|
+
let schema = getBaseTypeStructure("string");
|
|
18
|
+
|
|
19
|
+
schema.format = format;
|
|
20
|
+
if (example) {
|
|
21
|
+
schema.example = [example];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return schema;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function isAssociation(entry) {
|
|
28
|
+
return !!entry && entry.type === 'cds.Association';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function isComposition(entry) {
|
|
32
|
+
return !!entry && entry.type === 'cds.Composition';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function isStructured(entry) {
|
|
36
|
+
return !!entry && typeof entry === 'object' && 'elements' in entry && isElements(entry.elements);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function isToMany(entry) {
|
|
40
|
+
return entry.cardinality?.max === '*' || (typeof entry.cardinality?.max === 'number' && entry.cardinality?.max > 1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isDefault(entry) {
|
|
44
|
+
return "default" in entry;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function isEnum(entry) {
|
|
48
|
+
return "enum" in entry;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function addDefaultValue(entry, schema) {
|
|
52
|
+
schema.default = entry.default.val;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function isVal(value) {
|
|
56
|
+
return typeof value === 'object' && !!value && 'val' in value && Object.keys(value).length === 1;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function isElements(value) {
|
|
60
|
+
return typeof value === 'object' && !!value && !Array.isArray(value) && !('=' in value) && !isVal(value);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isManyEntry(entry) {
|
|
64
|
+
return (
|
|
65
|
+
'items' in entry &&
|
|
66
|
+
typeof entry.items === 'object' &&
|
|
67
|
+
!!entry.items &&
|
|
68
|
+
(('type' in entry.items && typeof entry.items.type === 'string') ||
|
|
69
|
+
('elements' in entry.items && isElements(entry.items.elements)))
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function isLocalizedElement(name, element) {
|
|
74
|
+
return (((name === 'texts' && isComposition(element)) || (name === 'localized' && isAssociation(element))) &&
|
|
75
|
+
element.target.endsWith('.texts'));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function isToManyAssociation(entry) {
|
|
79
|
+
return isAssociation(entry) && isToMany(entry);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function elementIsRelevant(name, element) {
|
|
83
|
+
return !isLocalizedElement(name, element);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function isRefEntry(entry) {
|
|
87
|
+
let type = entry.type;
|
|
88
|
+
return typeof type === 'object' && !!type && 'ref' in type && Array.isArray(type.ref);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = {
|
|
92
|
+
toString,
|
|
93
|
+
getBaseTypeStructure,
|
|
94
|
+
getFormatStructure,
|
|
95
|
+
isAssociation,
|
|
96
|
+
isComposition,
|
|
97
|
+
isStructured,
|
|
98
|
+
isToMany,
|
|
99
|
+
isDefault,
|
|
100
|
+
addDefaultValue,
|
|
101
|
+
isEnum,
|
|
102
|
+
isVal,
|
|
103
|
+
elementIsRelevant,
|
|
104
|
+
isManyEntry,
|
|
105
|
+
isElements,
|
|
106
|
+
isRefEntry,
|
|
107
|
+
isToManyAssociation
|
|
108
|
+
}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
const csnToJSONSchema = require('./components/schemas');
|
|
2
|
+
const getMessageTraits = require('./components/messageTraits');
|
|
3
|
+
const definitionsToMessages = require('./components/messages');
|
|
4
|
+
const getChannels = require('./channels');
|
|
5
|
+
const cds = require('../../cds');
|
|
6
|
+
const messages = require("./message");
|
|
7
|
+
const presetMapping = {
|
|
8
|
+
'event_spec_version': 'x-sap-event-spec-version',
|
|
9
|
+
'event_source': 'x-sap-event-source',
|
|
10
|
+
'event_source_params': 'x-sap-event-source-parameters',
|
|
11
|
+
'event_characteristics': 'x-sap-event-characteristics'
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
module.exports = function processor(csn, options = {}) {
|
|
15
|
+
|
|
16
|
+
const envConf = cds.env.export?.asyncapi;
|
|
17
|
+
_serviceErrorHandling(csn, options);
|
|
18
|
+
|
|
19
|
+
const applicationNamespace = envConf?.application_namespace;
|
|
20
|
+
|
|
21
|
+
if (!applicationNamespace) {
|
|
22
|
+
throw new Error(messages.APPLICATION_NAMESPACE);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const presets = getPresets(envConf);
|
|
26
|
+
|
|
27
|
+
if (options.service === 'all') {
|
|
28
|
+
if (options["asyncapi:merged"]) {
|
|
29
|
+
if (!envConf?.merged?.title || !envConf.merged?.version ) {
|
|
30
|
+
throw new Error(messages.TITLE_VERSION_MERGED);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const infoObject = getInfoObject({}, envConf.merged);
|
|
34
|
+
// verify version follows the required pattern
|
|
35
|
+
isVersionValid(infoObject.version);
|
|
36
|
+
const shortTextObj = getShortText({}, envConf.merged.short_text);
|
|
37
|
+
|
|
38
|
+
const events = getEvents(csn.definitions);
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
asyncapi: '2.0.0',
|
|
42
|
+
'x-sap-catalog-spec-version': '1.2',
|
|
43
|
+
'x-sap-application-namespace': applicationNamespace,
|
|
44
|
+
...Object.keys(shortTextObj).length && { 'x-sap-shortText': shortTextObj },
|
|
45
|
+
info: infoObject,
|
|
46
|
+
defaultContentType: 'application/json',
|
|
47
|
+
channels: getChannels(csn.definitions, events),
|
|
48
|
+
components: getComponents(csn.definitions, events, presets)
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
const services = getServicesWithEvents(csn.definitions);
|
|
52
|
+
return _iterate(services, csn, applicationNamespace, presets);
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
const events = getEvents(csn.definitions, options.service);
|
|
56
|
+
|
|
57
|
+
if (events.length === 0) {
|
|
58
|
+
throw new Error(messages.NO_EVENTS);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return _getAsyncApi(csn, events, options.service, applicationNamespace, presets);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getPresets(envConf) {
|
|
66
|
+
let projectPresets = {};
|
|
67
|
+
for (const [key, value] of Object.entries(envConf)) {
|
|
68
|
+
if (presetMapping[key]) projectPresets[presetMapping[key]] = value;
|
|
69
|
+
}
|
|
70
|
+
return projectPresets;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function _getAsyncApi(csn, events, serviceName, applicationNamespace, presets) {
|
|
74
|
+
|
|
75
|
+
const infoObject = getInfoObject(csn.definitions[serviceName]);
|
|
76
|
+
const stateObj = getStateInfo(csn.definitions[serviceName]);
|
|
77
|
+
const shortTextObj = getShortText(csn.definitions[serviceName]);
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
asyncapi: '2.0.0',
|
|
81
|
+
'x-sap-catalog-spec-version': '1.2',
|
|
82
|
+
'x-sap-application-namespace': applicationNamespace,
|
|
83
|
+
...Object.keys(stateObj).length && { 'x-sap-stateInfo': stateObj },
|
|
84
|
+
...Object.keys(shortTextObj).length && { 'x-sap-shortText': shortTextObj },
|
|
85
|
+
info: infoObject,
|
|
86
|
+
defaultContentType: 'application/json',
|
|
87
|
+
channels: getChannels(csn.definitions, events),
|
|
88
|
+
components: getComponents(csn.definitions, events, presets)
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function getShortText(serviceCsn, presetValue = undefined) {
|
|
93
|
+
let shortTextValue = presetValue || serviceCsn["@AsyncAPI.ShortText"];
|
|
94
|
+
if (shortTextValue) {
|
|
95
|
+
return shortTextValue;
|
|
96
|
+
}
|
|
97
|
+
return {};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function getStateInfo(serviceCsn) {
|
|
101
|
+
const stateProperties = ['state', 'deprecationDate', 'decomissionedDate', 'link'];
|
|
102
|
+
const stateObj = {};
|
|
103
|
+
|
|
104
|
+
stateProperties.forEach(function (item) {
|
|
105
|
+
if (serviceCsn['@AsyncAPI.StateInfo.' + item]) {
|
|
106
|
+
stateObj[item] = serviceCsn['@AsyncAPI.StateInfo.' + item];
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
return stateObj;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function getInfoObject(serviceCsn, mergedPresetObject = undefined) {
|
|
114
|
+
const info = {};
|
|
115
|
+
|
|
116
|
+
if (mergedPresetObject) {
|
|
117
|
+
Object.keys(mergedPresetObject).forEach(key => {
|
|
118
|
+
if (key !== "short_text") info[key] = mergedPresetObject[key];
|
|
119
|
+
});
|
|
120
|
+
return info;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (!serviceCsn['@AsyncAPI.SchemaVersion'] || !serviceCsn['@AsyncAPI.Title']) {
|
|
124
|
+
throw new Error(messages.TITLE_VERSION_ANNOTATIONS);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
isVersionValid(serviceCsn['@AsyncAPI.SchemaVersion']);
|
|
128
|
+
|
|
129
|
+
info.version = serviceCsn['@AsyncAPI.SchemaVersion'];
|
|
130
|
+
info.title = serviceCsn['@AsyncAPI.Title'];
|
|
131
|
+
|
|
132
|
+
if (serviceCsn['@AsyncAPI.Description']) {
|
|
133
|
+
info.description = serviceCsn['@AsyncAPI.Description'];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return info;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function isVersionValid(version) {
|
|
140
|
+
version.split('.').forEach(element => {
|
|
141
|
+
if (isNaN(element)) {
|
|
142
|
+
throw new Error(messages.UNSUPPORTED_VERSION);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function getEvents(definitions, service = '') {
|
|
149
|
+
let events = [];
|
|
150
|
+
for (const [key, value] of Object.entries(definitions)) {
|
|
151
|
+
if (value.kind === 'event' && value._service !== undefined) {
|
|
152
|
+
if (service === '' || value._service.name === service) {
|
|
153
|
+
events.push(key);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return events;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function getServicesWithEvents(definitions) {
|
|
161
|
+
const services = {};
|
|
162
|
+
|
|
163
|
+
// traverse the definitions list and extract services
|
|
164
|
+
for (const [key, value] of Object.entries(definitions)) {
|
|
165
|
+
if (value.kind === 'service') {
|
|
166
|
+
services[key] = {
|
|
167
|
+
events: []
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// traverse the definitions list and map events to services
|
|
173
|
+
for (const [key, value] of Object.entries(definitions)) {
|
|
174
|
+
if (value.kind === 'event' && value._service) {
|
|
175
|
+
services[value._service.name].events.push(key);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// traverse the services list and remove service with no events
|
|
180
|
+
for (const [key, value] of Object.entries(services)) {
|
|
181
|
+
if (value.events.length === 0) {
|
|
182
|
+
delete services[key];
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return services;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function getComponents(definitions, events, presets) {
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
messageTraits: getMessageTraits(),
|
|
193
|
+
messages: definitionsToMessages(definitions, events, presets),
|
|
194
|
+
schemas: csnToJSONSchema(definitions, events)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function _serviceErrorHandling(csn, options) {
|
|
199
|
+
const services = cds.linked(csn).services;
|
|
200
|
+
|
|
201
|
+
if (services.length < 1) throw new Error(messages.NO_SERVICES);
|
|
202
|
+
|
|
203
|
+
if (!options.service && services.length > 1) throw new Error(`\n
|
|
204
|
+
Found multiple service definitions in given model(s).
|
|
205
|
+
Please choose by adding one of... \n
|
|
206
|
+
-s all ${services.map(s => `\n -s ${s.name}`).join('')}
|
|
207
|
+
`);
|
|
208
|
+
|
|
209
|
+
if (!options.service) {
|
|
210
|
+
options.service = services[0].name;
|
|
211
|
+
} else if (options.service !== 'all') {
|
|
212
|
+
const srv = services.find(s => s.name === options.service);
|
|
213
|
+
if (!srv) throw new Error(`Service definition with given ${options.service} not found in the model(s).`);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (options["asyncapi:merged"] && options.service !== 'all') {
|
|
217
|
+
throw new Error(messages.MERGED_FLAG);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function* _iterate(services, csn, applicationNamespace, presets) {
|
|
222
|
+
for (const [key, value] of Object.entries(services)) {
|
|
223
|
+
const generatedAsyncAPI = _getAsyncApi(csn, value.events, key, applicationNamespace, presets);
|
|
224
|
+
yield [generatedAsyncAPI, { file: key }];
|
|
225
|
+
}
|
|
226
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const errorMessages = {
|
|
4
|
+
APPLICATION_NAMESPACE: 'Preset for application namespace needs to be added.',
|
|
5
|
+
TITLE_VERSION_MERGED: 'Preset for Title and Version info needs to be added when merged flag is used.',
|
|
6
|
+
NO_EVENTS: 'No events found in the service.',
|
|
7
|
+
TITLE_VERSION_ANNOTATIONS: 'Title and Version info annotations needs to be added to the service(s).',
|
|
8
|
+
UNSUPPORTED_VERSION: 'The version value provided is unsupported.',
|
|
9
|
+
NO_SERVICES: 'There are no service definitions found in the given model(s).',
|
|
10
|
+
MERGED_FLAG: 'Merged flag cannot be used with single service definition.',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
module.exports = errorMessages;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns value of EventType Annotation if it is present. Otherwise it returns the definition name only.
|
|
3
|
+
*/
|
|
4
|
+
function getEventName(eventName, eventDefinition) {
|
|
5
|
+
|
|
6
|
+
if (eventDefinition["@AsyncAPI.EventType"]) {
|
|
7
|
+
eventName = eventDefinition["@AsyncAPI.EventType"];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return eventName;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Gets the property value from the entry if it is defined otherwise returns undefined.
|
|
15
|
+
*/
|
|
16
|
+
function getOwnValue(entry, key) {
|
|
17
|
+
if (Object.prototype.hasOwnProperty.call(entry, key)) {
|
|
18
|
+
return entry[key];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = {
|
|
25
|
+
getEventName,
|
|
26
|
+
getOwnValue
|
|
27
|
+
}
|
package/lib/compile/index.js
CHANGED
|
@@ -4,6 +4,7 @@ const { defineProperty } = Object
|
|
|
4
4
|
|
|
5
5
|
'xsuaa' in comp_to || defineProperty (comp_to, 'xsuaa', {enumerable:true, get:()=> require('./to-xsuaa')})
|
|
6
6
|
'openapi' in comp_to || defineProperty (comp_to, 'openapi', {enumerable:true, get:()=> require('./openapi')})
|
|
7
|
+
'asyncapi' in comp_to || defineProperty (comp_to, 'asyncapi', {enumerable:true, get:()=> require('./asyncapi')})
|
|
7
8
|
|
|
8
9
|
'edmx-v2' in comp_to || defineProperty (comp_to, 'edmx-v2', {enumerable:true, value: (csn,o) => comp_to.edmx(csn,{...o,flavor:'v2'})})
|
|
9
10
|
'edmx-v4' in comp_to || defineProperty (comp_to, 'edmx-v4', {enumerable:true, value: (csn,o) => comp_to.edmx(csn,{...o,flavor:'v4'})})
|
|
@@ -24,14 +24,23 @@ const SUFFIX = {
|
|
|
24
24
|
read: "",
|
|
25
25
|
create: "-create",
|
|
26
26
|
update: "-update",
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const TITLE_SUFFIX = {
|
|
30
30
|
"": "",
|
|
31
31
|
"-create": " (for create)",
|
|
32
32
|
"-update": " (for update)",
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* ODM annotations in CDS that should be converted into OpenAPI.
|
|
37
|
+
*/
|
|
38
|
+
const ODM_ANNOTATIONS = Object.freeze(
|
|
39
|
+
{
|
|
40
|
+
'@ODM.entityName': 'x-sap-odm-entity-name',
|
|
41
|
+
'@ODM.oid': 'x-sap-odm-oid',
|
|
42
|
+
});
|
|
43
|
+
|
|
35
44
|
/**
|
|
36
45
|
* Construct an OpenAPI description from a CSDL document
|
|
37
46
|
* @param {object} csdl CSDL document
|
|
@@ -210,7 +219,7 @@ module.exports.csdl2openapi = function (
|
|
|
210
219
|
const terms = {
|
|
211
220
|
Authorization: ['Authorizations', 'SecuritySchemes'],
|
|
212
221
|
Capabilities: ['BatchSupport', 'BatchSupported', 'ChangeTracking', 'CountRestrictions', 'DeleteRestrictions', 'DeepUpdateSupport', 'ExpandRestrictions',
|
|
213
|
-
'FilterRestrictions', 'IndexableByKey', 'InsertRestrictions', 'KeyAsSegmentSupported', 'NavigationRestrictions', 'OperationRestrictions',
|
|
222
|
+
'FilterRestrictions', 'IndexableByKey', 'InsertRestrictions', 'KeyAsSegmentSupported', 'NavigationRestrictions', 'OperationRestrictions',
|
|
214
223
|
'ReadRestrictions', 'SearchRestrictions', 'SelectSupport', 'SkipSupported', 'SortRestrictions', 'TopSupported', 'UpdateRestrictions'],
|
|
215
224
|
Core: ['AcceptableMediaTypes', 'Computed', 'DefaultNamespace', 'Description', 'Example', 'Immutable', 'LongDescription',
|
|
216
225
|
'OptionalParameter', 'Permissions', 'SchemaVersion'],
|
|
@@ -248,8 +257,8 @@ module.exports.csdl2openapi = function (
|
|
|
248
257
|
description = containerSchema[voc.Core.LongDescription];
|
|
249
258
|
}
|
|
250
259
|
else {
|
|
251
|
-
description = ('This service is located at [' + serviceRoot + '/]('
|
|
252
|
-
|
|
260
|
+
description = ('This service is located at [' + serviceRoot + '/]('
|
|
261
|
+
+ serviceRoot.replace(/\(/g, '%28').replace(/\)/g, '%29') + '/)');
|
|
253
262
|
}
|
|
254
263
|
description += (diagram ? getResourceDiagram(csdl, entityContainer) : '');
|
|
255
264
|
let title;
|
|
@@ -266,7 +275,7 @@ module.exports.csdl2openapi = function (
|
|
|
266
275
|
title = 'OData CSDL document';
|
|
267
276
|
}
|
|
268
277
|
return {
|
|
269
|
-
title: title,
|
|
278
|
+
title: title,
|
|
270
279
|
description: csdl.$EntityContainer ? description : '',
|
|
271
280
|
version: containerSchema[voc.Core.SchemaVersion] || ''
|
|
272
281
|
};
|
|
@@ -437,7 +446,7 @@ module.exports.csdl2openapi = function (
|
|
|
437
446
|
throw new Error(`The input server object is invalid.`);
|
|
438
447
|
}
|
|
439
448
|
|
|
440
|
-
if(!servers.length){
|
|
449
|
+
if (!servers.length) {
|
|
441
450
|
throw new Error(`The input server object should be an array.`);
|
|
442
451
|
}
|
|
443
452
|
} else {
|
|
@@ -712,7 +721,7 @@ module.exports.csdl2openapi = function (
|
|
|
712
721
|
tags: [sourceName],
|
|
713
722
|
parameters: [],
|
|
714
723
|
responses: response(200, 'Retrieved ' + (byKey ? pluralize.singular(lname) : lname), { $Type: element.$Type, $Collection: collection },
|
|
715
|
-
|
|
724
|
+
byKey ? readByKeyRestrictions?.ErrorResponses : readRestrictions?.ErrorResponses)
|
|
716
725
|
};
|
|
717
726
|
const deltaSupported = element[voc.Capabilities.ChangeTracking] && element[voc.Capabilities.ChangeTracking].Supported;
|
|
718
727
|
if (!byKey && deltaSupported) {
|
|
@@ -1412,7 +1421,7 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
|
|
|
1412
1421
|
summary: actionImport[voc.Core.Description] || overload[voc.Core.Description] || 'Invoke action ' + name,
|
|
1413
1422
|
tags: [overload[voc.Common.Label] || sourceName || 'Service Operations'],
|
|
1414
1423
|
responses: overload.$ReturnType ? response(200, "Success", overload.$ReturnType, overload[voc.Capabilities.OperationRestrictions]?.ErrorResponses)
|
|
1415
|
-
|
|
1424
|
+
: response(204, "Success", undefined, overload[voc.Capabilities.OperationRestrictions]?.ErrorResponses),
|
|
1416
1425
|
}
|
|
1417
1426
|
};
|
|
1418
1427
|
const description = actionImport[voc.Core.LongDescription] || overload[voc.Core.LongDescription];
|
|
@@ -1599,7 +1608,7 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
|
|
|
1599
1608
|
* @param {object} type Response type object
|
|
1600
1609
|
* @param {array} errors Array of operation-specific status codes with descriptions
|
|
1601
1610
|
*/
|
|
1602
|
-
|
|
1611
|
+
function response(code, description, type, errors) {
|
|
1603
1612
|
const r = {};
|
|
1604
1613
|
r[code] = {
|
|
1605
1614
|
description: description
|
|
@@ -1829,6 +1838,8 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
|
|
|
1829
1838
|
if (Object.keys(schemaProperties).length > 0)
|
|
1830
1839
|
schemas[schemaName].properties = schemaProperties;
|
|
1831
1840
|
|
|
1841
|
+
odmExtensions(type, schemas[schemaName]);
|
|
1842
|
+
|
|
1832
1843
|
if (suffix === SUFFIX.create && required.length > 0)
|
|
1833
1844
|
schemas[schemaName].required = [...new Set(required)];
|
|
1834
1845
|
|
|
@@ -1846,6 +1857,17 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
|
|
|
1846
1857
|
}
|
|
1847
1858
|
}
|
|
1848
1859
|
|
|
1860
|
+
/**
|
|
1861
|
+
* Add ODM extensions to OpenAPI schema for a structured type
|
|
1862
|
+
* @param {object} type Structured type
|
|
1863
|
+
* @param {object} schema OpenAPI schema to augment
|
|
1864
|
+
*/
|
|
1865
|
+
function odmExtensions(type, schema) {
|
|
1866
|
+
for (const [annotation, openApiExtension] of Object.entries(ODM_ANNOTATIONS)) {
|
|
1867
|
+
if (type[annotation]) schema[openApiExtension] = type[annotation];
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1849
1871
|
/**
|
|
1850
1872
|
* Collect all properties of a structured type along the inheritance hierarchy
|
|
1851
1873
|
* @param {object} type Structured type
|
|
@@ -2022,7 +2044,7 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
|
|
|
2022
2044
|
break;
|
|
2023
2045
|
case 'Edm.Decimal':
|
|
2024
2046
|
s = {
|
|
2025
|
-
anyOf: [{ type: 'number', format: 'decimal'}, { type: 'string' }],
|
|
2047
|
+
anyOf: [{ type: 'number', format: 'decimal' }, { type: 'string' }],
|
|
2026
2048
|
example: 0
|
|
2027
2049
|
};
|
|
2028
2050
|
// eslint-disable-next-line no-case-declarations
|
|
@@ -2164,13 +2186,13 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
|
|
|
2164
2186
|
if (forFunction) {
|
|
2165
2187
|
if (s.example && typeof s.example === "string") {
|
|
2166
2188
|
s.example = `${pathValuePrefix(element.$Type)}${s.example
|
|
2167
|
-
}${pathValueSuffix(element.$Type)}`;
|
|
2189
|
+
}${pathValueSuffix(element.$Type)} `;
|
|
2168
2190
|
}
|
|
2169
2191
|
if (s.pattern) {
|
|
2170
2192
|
const pre = pathValuePrefix(element.$Type);
|
|
2171
2193
|
const suf = pathValueSuffix(element.$Type);
|
|
2172
|
-
s.pattern = s.pattern.replace(/^\^/,
|
|
2173
|
-
s.pattern = s.pattern.replace(/\$$/, `)${suf}$`);
|
|
2194
|
+
s.pattern = s.pattern.replace(/^\^/, `^ ${pre} (`);
|
|
2195
|
+
s.pattern = s.pattern.replace(/\$$/, `)${suf} $`);
|
|
2174
2196
|
} else if (!element.$Type || element.$Type === "Edm.String") {
|
|
2175
2197
|
s.pattern = "^'([^']|'')*'$";
|
|
2176
2198
|
}
|
|
@@ -2388,4 +2410,4 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
|
|
|
2388
2410
|
return !name.startsWith('$') && !name.includes('@');
|
|
2389
2411
|
}
|
|
2390
2412
|
|
|
2391
|
-
};
|
|
2413
|
+
};
|
package/lib/import/message.js
CHANGED
|
@@ -15,7 +15,9 @@ const messages = {
|
|
|
15
15
|
INCORRECT_INPUT_NAMESPACES: 'Invalid value for --include-namespaces option. Specify namespaces as comma-separated list or "*"',
|
|
16
16
|
MISSING_ASSOCIATION: 'Association is missing in the input file provided. Please check the edmx file.',
|
|
17
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.'
|
|
18
|
+
INVALID_OPENAPI_FILE: 'The OpenAPI file is not valid. Specify the correct OpenAPI file.',
|
|
19
|
+
UNRESOLVED_TYPE: 'Could not resolve the type: ',
|
|
20
|
+
NO_RETURN_TYPE: 'No ReturnType found in Function: '
|
|
19
21
|
};
|
|
20
22
|
|
|
21
23
|
function getMessages() {
|
|
@@ -2198,7 +2198,7 @@ class ReturnTypeExpression extends Expression {
|
|
|
2198
2198
|
const target = {};
|
|
2199
2199
|
this.setTarget(target);
|
|
2200
2200
|
|
|
2201
|
-
this.buildTypeCollectionAndFacets('$Type', '$Nullable', '$Precision', '$Scale');
|
|
2201
|
+
this.buildTypeCollectionAndFacets('$Type', '$MaxLength', '$Nullable', '$Precision', '$Scale');
|
|
2202
2202
|
super.interpret();
|
|
2203
2203
|
return { $ReturnType: target };
|
|
2204
2204
|
}
|