@cap-js/ord 1.0.3 → 1.2.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/lib/templates.js CHANGED
@@ -1,25 +1,33 @@
1
- const defaults = require("./defaults");
2
1
  const cds = require("@sap/cds");
3
- const fReplaceSpecialCharacters = (namespace) => {
4
- return namespace.replace(/customer\.(.+)/, (match, group1) => 'customer.' + group1.replace(/[^a-zA-Z0-9]/g, ''))
2
+ const defaults = require("./defaults");
3
+ const _ = require("lodash");
4
+ const {
5
+ DESCRIPTION_PREFIX,
6
+ ORD_EXTENSIONS_PREFIX,
7
+ ORD_RESOURCE_TYPE,
8
+ RESOURCE_VISIBILITY,
9
+ SHORT_DESCRIPTION_PREFIX
10
+ } = require("./constants");
11
+ const { Logger } = require("./logger");
12
+
13
+ function unflatten(flattedObject) {
14
+ let result = {}
15
+ _.keys(flattedObject).forEach(function (key) {
16
+ _.set(result, key, flattedObject[key])
17
+ })
18
+ return result
5
19
  }
6
20
 
7
- /**
8
- * Reads the ORD (Open Resource Discovery) annotation from a given service definition object and returns them as an object.
9
- *
10
- * @param {Object} srv The service definition object.
11
- * @returns {Object} An object containing ORD annotation.
12
- */
13
- const fReadORDExtensions = (srv) =>
14
- Object.entries(srv)
15
- .filter(([key]) => key.startsWith("@ORD.Extensions."))
16
- .reduce(
17
- (ordExtensions, [key, value]) => ({
18
- ...ordExtensions,
19
- [key.slice("@ORD.Extensions.".length)]: value,
20
- }),
21
- {}
22
- );
21
+ function readORDExtensions(model) {
22
+ const ordExtensions = {};
23
+ for (const key in model) {
24
+ if (key.startsWith(ORD_EXTENSIONS_PREFIX)) {
25
+ const ordKey = key.replace(ORD_EXTENSIONS_PREFIX, "");
26
+ ordExtensions[ordKey] = model[key];
27
+ }
28
+ }
29
+ return unflatten(ordExtensions);
30
+ }
23
31
 
24
32
  /**
25
33
  * Reads the service definition and returns an array of entryPoint paths.
@@ -29,28 +37,28 @@ const fReadORDExtensions = (srv) =>
29
37
  * @returns {Array} An array containing paths and it's kind.
30
38
  */
31
39
 
32
- const fGeneratePaths = (srv, srvDefinition) => {
33
- const srvObj = { name: srv, definition: srvDefinition };
34
- const protocols = cds.service.protocols;
40
+ const _generatePaths = (srv, srvDefinition) => {
41
+ const srvObj = { name: srv, definition: srvDefinition };
42
+ const protocols = cds.service.protocols;
35
43
 
36
- const paths = protocols.endpoints4(srvObj);
44
+ const paths = protocols.endpoints4(srvObj);
37
45
 
38
- //TODO: check graphql replication in paths object and re-visit logic
39
- //removing instances of graphql protocol from paths
40
- for (var index = paths.length - 1; index >= 0; index--) {
41
- if (paths[index].kind === "graphql") {
42
- console.warn("Graphql protocol is not supported.");
43
- paths.splice(index, 1);
46
+ //TODO: check graphql replication in paths object and re-visit logic
47
+ //removing instances of graphql protocol from paths
48
+ for (var index = paths.length - 1; index >= 0; index--) {
49
+ if (paths[index].kind === "graphql") {
50
+ Logger.warn('Graphql protocol is not supported.');
51
+ paths.splice(index, 1);
52
+ }
44
53
  }
45
- }
46
54
 
47
- //putting default as odata in case no supported protcol is there
48
- if (paths.length === 0) {
49
- srvDefinition["@odata"] = true;
50
- paths.push({ kind: "odata", path: protocols.path4(srvDefinition) });
51
- }
55
+ //putting OData as default in case of non-supported protocol
56
+ if (paths.length === 0) {
57
+ srvDefinition["@odata"] = true;
58
+ paths.push({ kind: "odata", path: protocols.path4(srvDefinition) });
59
+ }
52
60
 
53
- return paths;
61
+ return paths;
54
62
  };
55
63
 
56
64
  /**
@@ -59,30 +67,21 @@ const fGeneratePaths = (srv, srvDefinition) => {
59
67
  * @param {string} entity The name of the entity.
60
68
  * @returns {Object} An object for the entity type.
61
69
  */
62
- const fCreateEntityTypeTemplate = (entity) => ({
63
- ordId: `sap.odm:entityType:${entity["@ODM.entityName"]}:v1`,
70
+ const createEntityTypeTemplate = (entity) => ({
71
+ ordId: `sap.odm:entityType:${entity["@ODM.entityName"]}:v1`,
64
72
  });
65
73
 
66
- /**
67
- * This is a template function to form the group id.
68
- *
69
- * @param {string} fullyQualifiedName The fully qualified name of the service or event.
70
- * @param {string} groupTypeId The group type id.
71
- * @returns {string} a group id.
72
- */
73
- function _getGroupID(fullyQualifiedName, groupTypeId = defaults.groupTypeId, isService = true) {
74
- if (isService) {
75
- return `${groupTypeId}:${fReplaceSpecialCharacters(global.namespace)}:${fullyQualifiedName}`;
76
- } else {
77
- return `${groupTypeId}:${fReplaceSpecialCharacters(global.namespace)}:` +
78
- `${fullyQualifiedName.slice(0, fullyQualifiedName.lastIndexOf("."))}`;
79
- }
74
+ function _getGroupID(
75
+ fullyQualifiedName,
76
+ groupTypeId = defaults.groupTypeId,
77
+ appConfig,
78
+ ) {
79
+ return `${groupTypeId}:${appConfig.ordNamespace}:${fullyQualifiedName}`;
80
80
  }
81
81
 
82
-
83
82
  /**
84
83
  * This is a function to resolve the title of the service group.
85
- *
84
+ *
86
85
  * @param {string} srv The name of the service.
87
86
  * @returns {string} The title of the service group.
88
87
  */
@@ -90,265 +89,157 @@ function _getTitleFromServiceName(srv) {
90
89
  let serviceName = srv.substring(srv.lastIndexOf(".") + 1);
91
90
  let index = serviceName.indexOf("Service");
92
91
  if (index >= 0) {
93
- return `${serviceName.substring(0, index)} Service Title`;
92
+ return `${serviceName.substring(0, index)} Service`;
94
93
  } else {
95
- return `${serviceName} Service Title`;
94
+ return `${serviceName} Service`;
96
95
  }
97
96
  }
98
97
 
99
-
100
98
  /**
101
99
  * This is a template function to create group object of a service for groups array in ORD doc.
102
- *
103
- * @param {string} srv The name of the service.
104
- * @param {object} srvDefinition The definition of the service
105
- * @param {Set} groupIds A set of group ids.
106
- * @returns {Object} A group object.
107
- */
108
- const fCreateGroupsTemplateForService = (srv, srvDefinition, groupIds) => {
109
- const ordExtensions = fReadORDExtensions(srvDefinition);
110
-
111
- let fullyQualifiedServiceName = srv;
112
- if(!srv.includes(global.capNamespace)){
113
- fullyQualifiedServiceName = global.capNamespace + "." + srv;
114
- }
115
-
116
- if (checkEntityFunctionAction(srvDefinition, global).length > 0) {
117
- let groupId = _getGroupID(fullyQualifiedServiceName, defaults.groupTypeId);
118
- if (groupIds.has(groupId)) {
119
- return null;
120
- } else {
121
- groupIds.add(groupId);
122
- return {
123
- groupId: groupId,
124
- groupTypeId: `${defaults.groupTypeId}`,
125
- title: ordExtensions.title ?? _getTitleFromServiceName(srv)
126
- };
127
- }
128
- }
129
- }
130
-
131
- /**
132
- *
133
- * @param {string} event The name of the event.
134
- * @returns {string} The title of the event group.
135
- */
136
- function _getEventTitle(event) {
137
- let serviceName = event.substring(0, event.lastIndexOf("."));
138
- return _getTitleFromServiceName(serviceName);
139
- }
140
-
141
- /**
142
- * This is a template function to create group object of an event for groups array in ORD doc.
143
- *
144
- * @param {string} event The name of the event.
145
- * @param {object} eventDefinition The definition of the event.
100
+ *
101
+ * @param {string} serviceName The name of the service.
102
+ * @param {object} serviceDefinition The definition of the service
146
103
  * @param {Set} groupIds A set of group ids.
147
104
  * @returns {Object} A group object.
148
105
  */
149
- const fCreateGroupsTemplateForEvent = (event, eventDefinition, groupIds) => {
150
- const ordExtensions = fReadORDExtensions(eventDefinition);
106
+ const createGroupsTemplateForService = (serviceName, serviceDefinition, appConfig) => {
107
+ const ordExtensions = readORDExtensions(serviceDefinition);
151
108
 
152
- let fullyQualifiedEventName = event;
153
- if(!event.includes(global.capNamespace)){
154
- fullyQualifiedEventName = global.capNamespace + "." + event;
109
+ if (!serviceDefinition) {
110
+ Logger.warn('Unable to find service definition:', serviceName)
111
+ return undefined
155
112
  }
156
113
 
157
- let groupId = _getGroupID(fullyQualifiedEventName, defaults.groupTypeId, global, false);
158
- if (groupIds.has(groupId)) {
159
- return null;
160
- } else {
161
- groupIds.add(groupId);
162
- return {
163
- groupId: groupId,
164
- groupTypeId: `${defaults.groupTypeId}`,
165
- title: ordExtensions.title ?? _getEventTitle(event)
166
- };
167
- }
114
+ const groupId = _getGroupID(serviceName, defaults.groupTypeId, appConfig);
115
+ return {
116
+ groupId: groupId,
117
+ groupTypeId: defaults.groupTypeId,
118
+ title: ordExtensions.title ?? _getTitleFromServiceName(serviceName)
119
+ };
168
120
  }
169
121
 
170
122
  /**
171
123
  * This is a template function to create API Resource object for API Resource Array.
172
- *
173
- * @param {string} srv The name of the service.
174
- * @param {object} srvDefinition The definition of the service
124
+ * Properties of an API resource can be overwritten by the ORD extensions. Example: visibility.
125
+
126
+ * @param {string} serviceName The name of the service.
127
+ * @param {object} serviceDefinition The definition of the service
175
128
  * @returns {Array} An array of objects for the API Resources.
176
129
  */
177
- const fCreateAPIResourceTemplate = (srv, srvDefinition, global,packageIds) => {
178
- const ordExtensions = fReadORDExtensions(srvDefinition);
179
- const paths = fGeneratePaths(srv, srvDefinition);
180
- const apiResources = [];
181
-
182
- let srvName = srv;
183
- if (!srvName.includes(global.capNamespace)) {
184
- srvName = global.capNamespace + "." + srv;
185
- }
130
+ const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, packageIds) => {
131
+ const ordExtensions = readORDExtensions(serviceDefinition);
132
+ const paths = _generatePaths(serviceName, serviceDefinition);
133
+ const apiResources = [];
186
134
 
187
- if (checkEntityFunctionAction(srvDefinition, global).length > 0) {
188
135
  paths.forEach((generatedPath) => {
189
- let resourceDefinitions = [
190
- {
191
- type: "openapi-v3",
192
- mediaType: "application/json",
193
- url: `/.well-known/open-resource-discovery/v1/api-metadata/${srv}.oas3.json`,
194
- accessStrategies: [{ type: "open" }],
195
- },
196
- ];
197
-
198
- if (generatedPath.kind !== "rest") {
199
- //edmx resource definition is not generated in case of 'rest' protocol
200
- resourceDefinitions.push({
201
- type: "edmx",
202
- mediaType: "application/xml",
203
- url: `/.well-known/open-resource-discovery/v1/api-metadata/${srv}.edmx`,
204
- accessStrategies: [{ type: "open" }],
205
- });
206
- }
207
-
208
- let obj = {
209
- ordId: `${fReplaceSpecialCharacters(global.namespace)}:apiResource:${srvName}:v1`,
210
- title:
211
- ordExtensions.title ??
212
- srvDefinition["@title"] ??
213
- srvDefinition["@Common.Label"] ??
214
- `The service is for ${srv}`,
215
- shortDescription:
216
- ordExtensions.shortDescription ??
217
- `Here we have the shortDescription for ${srv}`,
218
- description:
219
- ordExtensions.description ??
220
- srvDefinition["@Core.Description"] ??
221
- `Here we have the description for ${srv}`,
222
- version: ordExtensions.version ?? "1.0.0",
223
- visibility: ordExtensions.visibility ?? "public",
224
- partOfPackage: _getPackageID(global.capNamespace,packageIds,'api'),
225
- partOfGroups: [_getGroupID(srvName, defaults.groupTypeId, global)],
226
- releaseStatus: ordExtensions.active ?? "active",
227
- partOfConsumptionBundles: [
228
- {
229
- ordId: `${fReplaceSpecialCharacters(global.namespace)}:consumptionBundle:noAuth:v1`,
230
- },
231
- ],
232
- apiProtocol:
233
- generatedPath.kind === "odata" ? "odata-v4" : generatedPath.kind,
234
- resourceDefinitions: resourceDefinitions,
235
- entryPoints: [generatedPath.path],
236
- extensible: {
237
- supported: ordExtensions["extensible.supported"] ?? "no",
238
- },
239
- entityTypeMappings: [{ entityTypeTargets: global.aODMEntity }],
240
- };
136
+ let resourceDefinitions = [
137
+ {
138
+ type: "openapi-v3",
139
+ mediaType: "application/json",
140
+ url: `/.well-known/open-resource-discovery/v1/api-metadata/${serviceName}.oas3.json`,
141
+ accessStrategies: [{ type: "open" }],
142
+ },
143
+ ];
144
+
145
+ if (generatedPath.kind !== "rest") {
146
+ //edmx resource definition is not generated in case of 'rest' protocol
147
+ resourceDefinitions.push({
148
+ type: "edmx",
149
+ mediaType: "application/xml",
150
+ url: `/.well-known/open-resource-discovery/v1/api-metadata/${serviceName}.edmx`,
151
+ accessStrategies: [{ type: "open" }],
152
+ });
153
+ }
154
+
155
+ let obj = {
156
+ ordId: `${appConfig.ordNamespace}:apiResource:${serviceName}:v1`,
157
+ title:
158
+ serviceDefinition["@title"] ??
159
+ serviceDefinition["@Common.Label"] ??
160
+ serviceName,
161
+ shortDescription: SHORT_DESCRIPTION_PREFIX + serviceName,
162
+ description:
163
+ serviceDefinition["@Core.Description"] ??
164
+ DESCRIPTION_PREFIX + serviceName,
165
+ version: "1.0.0",
166
+ lastUpdate: appConfig.lastUpdate,
167
+ visibility: RESOURCE_VISIBILITY.public,
168
+ partOfPackage: _getPackageID(appConfig.ordNamespace, packageIds, ORD_RESOURCE_TYPE.api),
169
+ partOfGroups: [_getGroupID(serviceName, defaults.groupTypeId, appConfig)],
170
+ releaseStatus: "active",
171
+ apiProtocol:
172
+ generatedPath.kind === "odata" ? "odata-v4" : generatedPath.kind,
173
+ resourceDefinitions: resourceDefinitions,
174
+ entryPoints: [generatedPath.path],
175
+ extensible: {
176
+ supported: "no",
177
+ },
178
+ entityTypeMappings: [{ entityTypeTargets: appConfig.odmEntity }],
179
+ ...ordExtensions,
180
+ };
241
181
 
242
- apiResources.push(obj);
182
+ if (obj.visibility === RESOURCE_VISIBILITY.public) apiResources.push(obj);
243
183
  });
244
- }
245
- if (apiResources.length > 0) return apiResources;
184
+
185
+ return apiResources;
246
186
  };
247
187
 
248
188
  /**
249
189
  * This is a template function to create Event Resource object for Event Resource Array.
190
+ * There can be only one event resource per service because all events are using the same protocol, they are always Cloud Events.
191
+ * Properties of an event resource can be overwritten by the ORD extensions. Example: visibility.
250
192
  *
251
- * @param {string} srv The name of the event.
252
- * @param {object} srvDefinition The definition of the event.
253
- * @returns {Object} An object for the Event Resource.
193
+ * @param {string} serviceName The name of the service.
194
+ * @param {object} serviceDefinition The definition of the service
195
+ * @returns {Array} An single-item array of objects for the Event Resources.
254
196
  */
255
- const fCreateEventResourceTemplate = (srv, srvDefinition, global,packageIds) => {
256
- const ordExtensions = fReadORDExtensions(srvDefinition);
257
- let srvName = srv;
258
- if(!srvName.includes(global.capNamespace)){
259
- srvName = global.capNamespace + "." + srv;
260
- }
261
- return {
262
- ordId: `${fReplaceSpecialCharacters(global.namespace)}:eventResource:${srvName}:v1`,
263
- title: ordExtensions.title ?? srvDefinition['@title'] ?? srvDefinition['@Common.Label'] ?? `ODM ${global.appName.replace(/[^a-zA-Z0-9]/g, '')} Events`,
264
- shortDescription: ordExtensions.shortDescription ?? "Example ODM Event",
265
- description: ordExtensions.description ??
266
- srvDefinition['@description'] ?? srvDefinition['@Core.Description'] ??
267
- `This is an example event catalog that contains only a partial ODM ${global.appName} V1 event`,
268
- version: ordExtensions.version ?? "1.0.0",
269
- releaseStatus: ordExtensions.releaseStatus ?? "beta",
270
- partOfPackage: _getPackageID(global.capNamespace,packageIds,'event'),
271
- partOfGroups: [_getGroupID(srvName, defaults.groupTypeId, global, false)],
272
- visibility: ordExtensions.visibility ?? "public",
273
- resourceDefinitions: [
274
- {
275
- type: "asyncapi-v2",
276
- mediaType: "application/json",
277
- url: `/.well-known/open-resource-discovery/v1/api-metadata/${srvDefinition._service.name}.asyncapi2.json`,
278
- accessStrategies: [
279
- {
280
- type: "open",
281
- },
197
+ const createEventResourceTemplate = (serviceName, serviceDefinition, appConfig, packageIds) => {
198
+ const ordExtensions = readORDExtensions(serviceDefinition);
199
+ if (!!ordExtensions.visibility && ordExtensions.visibility !== RESOURCE_VISIBILITY.public) return [];
200
+ return [{
201
+ ordId: `${appConfig.ordNamespace}:eventResource:${serviceName}:v1`,
202
+ title:
203
+ serviceDefinition["@title"] ??
204
+ serviceDefinition["@Common.Label"] ??
205
+ `ODM ${appConfig.appName.replace(/[^a-zA-Z0-9]/g, "")} Events`,
206
+ shortDescription: `${serviceName} event resource`,
207
+ description:
208
+ serviceDefinition['@description'] ?? serviceDefinition['@Core.Description'] ??
209
+ "CAP Event resource describing events / messages.",
210
+ version: "1.0.0",
211
+ lastUpdate: appConfig.lastUpdate,
212
+ releaseStatus: "active",
213
+ partOfPackage: _getPackageID(appConfig.ordNamespace, packageIds, ORD_RESOURCE_TYPE.event),
214
+ partOfGroups: [_getGroupID(serviceName, defaults.groupTypeId, appConfig)],
215
+ visibility: RESOURCE_VISIBILITY.public,
216
+ resourceDefinitions: [
217
+ {
218
+ type: "asyncapi-v2",
219
+ mediaType: "application/json",
220
+ url: `/.well-known/open-resource-discovery/v1/api-metadata/${serviceName}.asyncapi2.json`,
221
+ accessStrategies: [
222
+ {
223
+ type: "open",
224
+ },
225
+ ],
226
+ },
282
227
  ],
283
- },
284
- ],
285
- extensible: { supported: ordExtensions["extensible.supported"] ?? "no" },
286
- };
287
- };
288
-
228
+ extensible: { supported: "no" },
289
229
 
290
- /**
291
- * This is a function to check whether entity is a function or action.
292
- * @param {object} srvDefinition The definition of the event.
293
- * @returns {Object} An object for the Event Resource.
294
- */
295
- function checkEntityFunctionAction(srvDefinition, global) {
296
- if (srvDefinition.entities) {
297
- return srvDefinition.entities.map((entity) => {
298
- return {
299
- type: "entity",
300
- name: entity.name,
301
- entityType: entity.name,
302
- entitySet: entity.name,
303
- entityTypeMapping: `${global.namespace}:entityType:${entity.name}:v1`,
304
- entitySetMapping: `${global.namespace}:entitySet:${entity.name}:v1`,
305
- };
306
- });
307
- } else if (srvDefinition.actions) {
308
- return srvDefinition.actions.map((action) => {
309
- return {
310
- type: "action",
311
- name: action.name,
312
- actionType: action.name,
313
- actionMapping: `${global.namespace}:action:${action.name}:v1`,
314
- };
315
- });
316
- } else if (srvDefinition.functions) {
317
- return srvDefinition.functions.map((func) => {
318
- return {
319
- type: "function",
320
- name: func.name,
321
- functionType: func.name,
322
- functionMapping: `${global.namespace}:function:${func.name}:v1`,
323
- };
324
- });
325
- }
326
- }
230
+ ...ordExtensions
231
+ }]
232
+ };
327
233
 
328
- /**
329
- * This is a function to get the corresponding package ordId mapped to the service.
330
- */
234
+ function _getPackageID(namespace, packageIds, resourceType) {
235
+ if (!packageIds) return;
331
236
 
332
- function _getPackageID(capNamespace, packageIds, apiOrEvent) {
333
- if (packageIds instanceof Set) {
334
- const packageArray = Array.from(packageIds);
335
-
336
- if (apiOrEvent === "api") {
337
- const apiPackage = packageArray.find(pkg => pkg.includes("-api"));
338
- if (apiPackage) return apiPackage;
339
- } else if (apiOrEvent === "event") {
340
- const eventPackage = packageArray.find(pkg => pkg.includes("-event"));
341
- if (eventPackage) return eventPackage;
342
- }
343
-
344
- return packageArray.find(pkg => pkg.includes(capNamespace));
345
- }
237
+ return packageIds.find((id) => id.includes("-" + resourceType)) || packageIds.find((id) => id.includes(namespace));
346
238
  }
347
239
 
348
240
  module.exports = {
349
- fCreateEntityTypeTemplate,
350
- fCreateGroupsTemplateForService,
351
- fCreateGroupsTemplateForEvent,
352
- fCreateAPIResourceTemplate,
353
- fCreateEventResourceTemplate,
241
+ createEntityTypeTemplate,
242
+ createGroupsTemplateForService,
243
+ createAPIResourceTemplate,
244
+ createEventResourceTemplate,
354
245
  };
package/package.json CHANGED
@@ -1,27 +1,34 @@
1
1
  {
2
- "name": "@cap-js/ord",
3
- "version": "1.0.3",
4
- "description": "CAP Plugin for generating ORD document.",
5
- "repository": "cap-js/ord",
6
- "author": "SAP SE (https://www.sap.com)",
7
- "homepage": "https://cap.cloud.sap/",
8
- "license": "SEE LICENSE IN LICENSE",
9
- "main": "cds-plugin.js",
10
- "files": [
11
- "lib",
12
- "data",
13
- "LICENSES"
14
- ],
15
- "scripts": {
16
- "lint": "npx eslint ."
17
- },
18
- "devDependencies": {
19
- "eslint": "^8"
20
- },
21
- "peerDependencies": {
22
- "@sap/cds": "7.9.4",
23
- "@sap/cds-compiler" : "5.0.6",
24
- "@cap-js/asyncapi": "^1.0.0",
25
- "@cap-js/openapi": "^1.0.2"
26
- }
27
- }
2
+ "name": "@cap-js/ord",
3
+ "version": "1.2.0",
4
+ "description": "CAP Plugin for generating ORD document.",
5
+ "repository": "cap-js/ord",
6
+ "author": "SAP SE (https://www.sap.com)",
7
+ "homepage": "https://cap.cloud.sap/",
8
+ "license": "SEE LICENSE IN LICENSE",
9
+ "main": "cds-plugin.js",
10
+ "files": [
11
+ "lib",
12
+ "data",
13
+ "LICENSES"
14
+ ],
15
+ "scripts": {
16
+ "lint": "npx eslint .",
17
+ "test": "jest --ci --collectCoverage",
18
+ "update-snapshot": "jest --ci --updateSnapshot",
19
+ "cds:version": "cds v -i"
20
+ },
21
+ "devDependencies": {
22
+ "eslint": "^8",
23
+ "jest": "^29.7.0"
24
+ },
25
+ "peerDependencies": {
26
+ "@cap-js/asyncapi": "^1.0.0",
27
+ "@cap-js/openapi": "^1.0.2",
28
+ "@sap/cds": "^8.1.1",
29
+ "@sap/cds-compiler": "5.0.6"
30
+ },
31
+ "dependencies": {
32
+ "lodash": "^4.17.21"
33
+ }
34
+ }