@cap-js/ord 1.7.0 → 1.8.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/defaults.js CHANGED
@@ -122,17 +122,6 @@ module.exports = {
122
122
  CONTENT_MERGE_KEY,
123
123
  );
124
124
  },
125
- consumptionBundles: (appConfig) => [
126
- {
127
- ordId: `${regexWithRemoval(appConfig.appName)}:consumptionBundle:noAuth:v1`,
128
- version: "1.0.0",
129
- lastUpdate: appConfig.lastUpdate,
130
- title: "Unprotected resources",
131
- shortDescription: "If we have another protected API then it will be another object",
132
- description:
133
- "This Consumption Bundle contains all resources of the reference app which are unprotected and do not require authentication",
134
- },
135
- ],
136
125
  baseTemplate: (authConfig, tenant) => {
137
126
  // Get access strategies from the provided authConfig
138
127
  // If auth config is not available, fall back to empty array
@@ -89,11 +89,12 @@ function createIntegrationDependency(externalServices, appConfig, packageIds) {
89
89
 
90
90
  // Read IntegrationDependency level config from cdsrc
91
91
  const integrationDepConfig = appConfig.env?.integrationDependency || {};
92
+ const version = integrationDepConfig.version || "1.0.0";
92
93
 
93
94
  return {
94
- ordId: `${appConfig.ordNamespace}:${ORD_RESOURCE_TYPE.integrationDependency}:${INTEGRATION_DEPENDENCY_RESOURCE_NAME}:v1`,
95
+ ordId: `${appConfig.ordNamespace}:${ORD_RESOURCE_TYPE.integrationDependency}:${INTEGRATION_DEPENDENCY_RESOURCE_NAME}:v${version.split(".")[0]}`,
95
96
  title: "External Dependencies",
96
- version: "1.0.0",
97
+ version: version,
97
98
  releaseStatus: "active",
98
99
  visibility: RESOURCE_VISIBILITY.public,
99
100
  mandatory: false,
package/lib/ord.js CHANGED
@@ -20,26 +20,21 @@ const {
20
20
 
21
21
  const _getGroups = (csn, appConfig) => {
22
22
  return appConfig.serviceNames
23
- .flatMap((serviceName) => createGroupsTemplateForService(serviceName, csn.definitions[serviceName], appConfig))
23
+ .map((name) => csn.definitions[name])
24
+ .flatMap((srvDefinition) => createGroupsTemplateForService(srvDefinition, appConfig))
24
25
  .filter((resource) => !!resource);
25
26
  };
26
27
 
27
28
  const _getAPIResources = (csn, appConfig, packageIds, accessStrategies) => {
28
- return appConfig.apiResourceNames.flatMap((apiResourceName) =>
29
- createAPIResourceTemplate(
30
- apiResourceName,
31
- csn.definitions[apiResourceName],
32
- appConfig,
33
- packageIds,
34
- accessStrategies,
35
- ),
36
- );
29
+ return appConfig.apiResourceNames
30
+ .map((name) => csn.definitions[name])
31
+ .flatMap((srvDefinition) => createAPIResourceTemplate(srvDefinition, appConfig, packageIds, accessStrategies));
37
32
  };
38
33
 
39
34
  const _getEventResources = (csn, appConfig, packageIds, accessStrategies) => {
40
- return appConfig.eventServiceNames.flatMap((serviceName) =>
41
- createEventResourceTemplate(serviceName, csn.definitions[serviceName], appConfig, packageIds, accessStrategies),
42
- );
35
+ return appConfig.eventServiceNames
36
+ .map((name) => csn.definitions[name])
37
+ .flatMap((srvDefinition) => createEventResourceTemplate(srvDefinition, appConfig, packageIds, accessStrategies));
43
38
  };
44
39
 
45
40
  const _getProducts = (appConfig) => {
@@ -75,7 +70,6 @@ const _createDefaultORDDocument = (linkedCsn, appConfig, authConfig) => {
75
70
  packages: packages,
76
71
  description: appConfig.env?.description || defaults.description,
77
72
  openResourceDiscovery: appConfig.env?.openResourceDiscovery || defaults.openResourceDiscovery,
78
- consumptionBundles: appConfig.env?.consumptionBundles || defaults.consumptionBundles(appConfig),
79
73
 
80
74
  // Conditionally added top-level properties
81
75
  ...(!entityTypes.length ? {} : { entityTypes: entityTypes }),
@@ -84,6 +78,7 @@ const _createDefaultORDDocument = (linkedCsn, appConfig, authConfig) => {
84
78
  ...(appConfig.existingProductORDId ? {} : { products: [products[0]] }),
85
79
  ...(!appConfig.serviceNames.length ? {} : { groups: _getGroups(linkedCsn, appConfig) }),
86
80
  ...(!integrationDependencies.length ? {} : { integrationDependencies: integrationDependencies }),
81
+ ...(!appConfig.env?.consumptionBundles?.length ? {} : { consumptionBundles: appConfig.env.consumptionBundles }),
87
82
  };
88
83
  };
89
84
 
@@ -7,18 +7,6 @@ const {
7
7
  } = require("./constants");
8
8
  const Logger = require("./logger");
9
9
 
10
- /**
11
- * Gets CAP endpoints for a service using CDS endpoints4().
12
- *
13
- * @param {string} serviceName The service name.
14
- * @param {Object} srvDefinition The service definition object.
15
- * @returns {Array} Raw endpoints from CDS.
16
- */
17
- function _getCapEndpoints(serviceName, srvDefinition) {
18
- const srvObj = { name: serviceName, definition: srvDefinition };
19
- return cds.service.protocols.endpoints4(srvObj);
20
- }
21
-
22
10
  /**
23
11
  * Reads the explicit @protocol annotation from service definition.
24
12
  *
@@ -42,13 +30,12 @@ function _getExplicitProtocol(srvDefinition) {
42
30
  * - Rule B: Only fallback to OData when no explicit protocol
43
31
  * - Rule C: Never produce [null] in entryPoints
44
32
  *
45
- * @param {string} serviceName The service name.
46
33
  * @param {Object} srvDefinition The service definition object.
47
34
  * @param {Object} options Configuration options.
48
35
  * @param {Function} options.isPrimaryDataProduct Strategy function to check if service is primary data product.
49
36
  * @returns {Array} Array with single {apiProtocol, entryPoints, hasResourceDefinitions} object, or empty array.
50
37
  */
51
- function resolveApiResourceProtocol(serviceName, srvDefinition, options = {}) {
38
+ function resolveApiResourceProtocol(srvDefinition, options = {}) {
52
39
  const { isPrimaryDataProduct = () => false } = options;
53
40
 
54
41
  // 1. Primary Data Product - early return
@@ -62,7 +49,7 @@ function resolveApiResourceProtocol(serviceName, srvDefinition, options = {}) {
62
49
  ];
63
50
  }
64
51
 
65
- const capEndpoints = _getCapEndpoints(serviceName, srvDefinition);
52
+ const capEndpoints = cds.service.protocols.endpoints4({ name: srvDefinition.name, definition: srvDefinition });
66
53
  const ordProtocols = [];
67
54
  for (const endpoint of capEndpoints) {
68
55
  if (PLUGIN_UNSUPPORTED_PROTOCOLS.includes(endpoint.kind)) {
@@ -107,7 +94,7 @@ function resolveApiResourceProtocol(serviceName, srvDefinition, options = {}) {
107
94
 
108
95
  // 4. Handle explicit protocol with no CAP endpoint (Rule A)
109
96
  if (!ordProtocols.some((p) => p.apiProtocol === protocol) && !CAP_TO_ORD_PROTOCOL_MAP[protocol]) {
110
- Logger.warn(`Unknown protocol '${protocol}' is not supported, and skipped for service '${serviceName}'.`);
97
+ Logger.warn(`Unknown protocol '${protocol}' is not supported, and skipped for service '${srvDefinition.name}'.`);
111
98
  }
112
99
  }
113
100
 
package/lib/templates.js CHANGED
@@ -32,11 +32,11 @@ function unflatten(flattedObject) {
32
32
  return result;
33
33
  }
34
34
 
35
- function readORDExtensions(model) {
35
+ function readORDExtensions(model, prefix = ORD_EXTENSIONS_PREFIX) {
36
36
  const ordExtensions = {};
37
37
  for (const key in model) {
38
- if (key.startsWith(ORD_EXTENSIONS_PREFIX)) {
39
- const ordKey = key.replace(ORD_EXTENSIONS_PREFIX, "");
38
+ if (key.startsWith(prefix)) {
39
+ const ordKey = key.replace(prefix, "");
40
40
  ordExtensions[ordKey] = model[key];
41
41
  }
42
42
  }
@@ -63,9 +63,9 @@ const createEntityTypeMappingsItemTemplate = (entity) => {
63
63
  const ordIdParts = entity[ENTITY_RELATIONSHIP_ANNOTATION].split(":");
64
64
  const namespace = ordIdParts[0];
65
65
  const entityName = ordIdParts[1];
66
- const version = ordIdParts[2] || "v1";
66
+ const version = entity[`${ORD_EXTENSIONS_PREFIX}version`] || ordIdParts[2]?.substring(1) || "1";
67
67
  results.push({
68
- ordId: `${namespace}:entityType:${entityName}:${version}`,
68
+ ordId: `${namespace}:entityType:${entityName}:v${version.split(".")[0]}`,
69
69
  entityName,
70
70
  ...entity,
71
71
  });
@@ -74,8 +74,8 @@ const createEntityTypeMappingsItemTemplate = (entity) => {
74
74
  return results;
75
75
  };
76
76
 
77
- function _getGroupID(serviceDefinition, groupTypeId = defaults.groupTypeId, appConfig) {
78
- return `${groupTypeId}:${appConfig.ordNamespace}:${_getCleanServiceName(serviceDefinition, appConfig)}`;
77
+ function _getGroupID(appConfig, srvDefinition) {
78
+ return `${defaults.groupTypeId}:${appConfig.ordNamespace}:${_getCleanServiceName(srvDefinition.name, appConfig)}`;
79
79
  }
80
80
 
81
81
  function _startsWithNamespace(name, namespace) {
@@ -84,7 +84,7 @@ function _startsWithNamespace(name, namespace) {
84
84
  return rest === "" || rest.startsWith(".");
85
85
  }
86
86
 
87
- function _getCleanServiceName({ name }, appConfig) {
87
+ function _getCleanServiceName(name, appConfig) {
88
88
  let sortedName = name;
89
89
  if (appConfig.internalNamespace && _startsWithNamespace(name, appConfig.internalNamespace)) {
90
90
  sortedName = name.substring(appConfig.internalNamespace.length);
@@ -122,7 +122,7 @@ function _getTitleFromServiceName(srv) {
122
122
  */
123
123
  function _getEntityVersion(entity) {
124
124
  const entityVersion = entity.ordId.split(":").pop();
125
- const version = entityVersion.replace("v", "") + ".0.0"; // TODO: version can be stated/overwritten by annotation
125
+ const version = entityVersion.replace("v", "") + ".0.0";
126
126
  if (!SEM_VERSION_REGEX.test(version)) {
127
127
  Logger.warn("Entity version", version, "is not a valid semantic version.");
128
128
  }
@@ -162,31 +162,24 @@ function _getResourceDefinition(resourceType, mediaType, ordId, serviceName, fil
162
162
  /**
163
163
  * This is a template function to create group object of a service for groups array in ORD doc.
164
164
  *
165
- * @param {string} serviceName The name of the service.
166
- * @param {object} serviceDefinition The definition of the service
165
+ * @param {object} srvDefinition The definition of the service
167
166
  * @param {object} appConfig - The application configuration.
168
167
  * @returns {Object} A group object.
169
168
  */
170
- const createGroupsTemplateForService = (serviceName, serviceDefinition, appConfig) => {
171
- const ordExtensions = readORDExtensions(serviceDefinition);
172
-
173
- if (!serviceDefinition) {
174
- Logger.warn("Unable to find service definition:", serviceName);
175
- return undefined;
176
- }
169
+ const createGroupsTemplateForService = (srvDefinition, appConfig) => {
170
+ const ordExtensions = readORDExtensions(srvDefinition);
171
+ const visibility = _handleVisibility(ordExtensions, srvDefinition, appConfig.env?.defaultVisibility);
177
172
 
178
- const visibility = _handleVisibility(ordExtensions, serviceDefinition, appConfig.env?.defaultVisibility);
179
173
  if (visibility === RESOURCE_VISIBILITY.private) {
180
174
  // If the visibility of the service is private, do not create a group
181
- Logger.info("Skipping group creation for private service:", serviceName);
175
+ Logger.info("Skipping group creation for private service:", srvDefinition.name);
182
176
  return undefined;
183
177
  }
184
178
 
185
- const groupId = _getGroupID(serviceDefinition, defaults.groupTypeId, appConfig);
186
179
  return {
187
- groupId: groupId,
180
+ groupId: _getGroupID(appConfig, srvDefinition),
188
181
  groupTypeId: defaults.groupTypeId,
189
- title: ordExtensions.title ?? _getTitleFromServiceName(serviceName),
182
+ title: ordExtensions.title ?? _getTitleFromServiceName(srvDefinition.name),
190
183
  };
191
184
  };
192
185
 
@@ -221,7 +214,7 @@ const createEntityTypeTemplate = (appConfig, packageIds, entity) => {
221
214
  return {
222
215
  ordId: entity.ordId,
223
216
  localId: entity.entityName,
224
- title: entity["@title"] ?? entity["@Common.Label"] ?? entity.entityName,
217
+ title: entity["@title"] ?? entity["@Common.Label"] ?? entity["@EndUserText.label"] ?? entity.entityName,
225
218
  shortDescription: SHORT_DESCRIPTION_PREFIX + entity.entityName,
226
219
  description: DESCRIPTION_PREFIX + entity.entityName,
227
220
  version: _getEntityVersion(entity),
@@ -280,26 +273,24 @@ function _handleVisibility(ordExtensions, definition, defaultVisibility = RESOUR
280
273
  * This is a template function to create API Resource object for API Resource Array.
281
274
  * Properties of an API resource can be overwritten by the ORD extensions. Example: visibility.
282
275
  * Ensures proper visibility compliance by checking associated EntityTypes.
283
- * @param {string} serviceName The name of the service.
284
- * @param {object} serviceDefinition The definition of the service
276
+ * @param {object} srvDefinition The definition of the service
285
277
  * @param {object} appConfig - The application configuration.
286
278
  * @param {Array} packageIds - The available package identifiers.
287
279
  * @param {Array} accessStrategies The array of accessStrategies objects
288
280
  * @returns {Array} An array of objects for the API Resources.
289
281
  */
290
- const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, packageIds, accessStrategies) => {
291
- const ordExtensions = readORDExtensions(serviceDefinition);
292
- const visibility = _handleVisibility(ordExtensions, serviceDefinition, appConfig.env?.defaultVisibility);
282
+ const createAPIResourceTemplate = (srvDefinition, appConfig, packageIds, accessStrategies) => {
283
+ const ordExtensions = readORDExtensions(srvDefinition);
284
+ const visibility = _handleVisibility(ordExtensions, srvDefinition, appConfig.env?.defaultVisibility);
293
285
  const packageId = _getPackageID(appConfig.ordNamespace, packageIds, ORD_RESOURCE_TYPE.api, visibility);
294
-
295
- const protocolResults = resolveApiResourceProtocol(serviceName, serviceDefinition, {
286
+ const protocolResults = resolveApiResourceProtocol(srvDefinition, {
296
287
  isPrimaryDataProduct: isPrimaryDataProductService,
297
288
  });
298
289
  const apiResources = [];
299
290
 
300
291
  // If no protocols were generated, skip this service
301
292
  if (protocolResults.length === 0) {
302
- Logger.info(`No supported protocols for service '${serviceName}', skipping API resource generation.`);
293
+ Logger.info(`No supported protocols for service '${srvDefinition.name}', skipping API resource generation.`);
303
294
  return apiResources;
304
295
  }
305
296
 
@@ -308,31 +299,26 @@ const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, pa
308
299
  version,
309
300
  semanticVersion,
310
301
  extracted = null;
311
- if (isPrimaryDataProductService(serviceDefinition)) {
312
- extracted = _extractVersionFromServiceName(serviceDefinition.name);
313
- if (extracted) {
314
- // Create a temporary service definition with the clean name for namespace processing
315
- const versionExtractedServiceDefinition = { ...serviceDefinition, name: extracted.cleanName };
316
- cleanServiceName = _getCleanServiceName(versionExtractedServiceDefinition, appConfig);
317
- version = extracted.version;
318
- semanticVersion = extracted.semanticVersion;
319
- } else {
320
- // Invalid pattern - use current behavior
321
- cleanServiceName = _getCleanServiceName(serviceDefinition, appConfig);
322
- version = "v1";
323
- semanticVersion = "1.0.0";
324
- }
302
+ if (isPrimaryDataProductService(srvDefinition)) {
303
+ extracted = _extractVersionFromServiceName(srvDefinition.name);
304
+
305
+ cleanServiceName = _getCleanServiceName(extracted?.cleanName || srvDefinition.name, appConfig);
306
+ semanticVersion = ordExtensions.version || extracted?.semanticVersion || "1.0.0";
307
+ version = `v${semanticVersion.split(".")[0]}`;
325
308
  } else {
326
309
  // Non-data product - use current behavior
327
- cleanServiceName = _getCleanServiceName(serviceDefinition, appConfig);
328
- version = "v1";
329
- semanticVersion = "1.0.0";
310
+ cleanServiceName = _getCleanServiceName(srvDefinition.name, appConfig);
311
+ semanticVersion = ordExtensions.version || "1.0.0";
312
+ version = `v${semanticVersion.split(".")[0]}`;
330
313
  }
331
314
 
332
- const ordId = `${appConfig.ordNamespace}:apiResource:${cleanServiceName}:${version}`;
333
-
334
- protocolResults.forEach((protocolResult) => {
315
+ protocolResults.forEach((protocolResult, index) => {
335
316
  const { apiProtocol, entryPoints, hasResourceDefinitions } = protocolResult;
317
+ const protocolExtensions = readORDExtensions(srvDefinition, `@protocol('${apiProtocol}').ORD.Extensions.`);
318
+ const ordId =
319
+ protocolExtensions.ordId ||
320
+ ordExtensions.ordId ||
321
+ `${appConfig.ordNamespace}:apiResource:${cleanServiceName}${index === 0 ? "" : `-${apiProtocol}`}:${version}`;
336
322
 
337
323
  // Build resource definitions based on protocol
338
324
  let resourceDefinitions = [];
@@ -344,7 +330,7 @@ const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, pa
344
330
  "sap-csn-interop-effective-v1",
345
331
  "json",
346
332
  ordId,
347
- serviceName,
333
+ srvDefinition.name,
348
334
  "csn.json",
349
335
  accessStrategies,
350
336
  ),
@@ -352,7 +338,14 @@ const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, pa
352
338
  } else if (apiProtocol === ORD_API_PROTOCOL.REST) {
353
339
  // REST only has OpenAPI, no EDMX
354
340
  resourceDefinitions = [
355
- _getResourceDefinition("openapi-v3", "json", ordId, serviceName, "oas3.json", accessStrategies),
341
+ _getResourceDefinition(
342
+ "openapi-v3",
343
+ "json",
344
+ ordId,
345
+ srvDefinition.name,
346
+ "oas3.json",
347
+ accessStrategies,
348
+ ),
356
349
  ];
357
350
  } else if (apiProtocol === ORD_API_PROTOCOL.MCP) {
358
351
  resourceDefinitions = [
@@ -360,7 +353,7 @@ const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, pa
360
353
  MCP_RESOURCE_DEFINITION_TYPE,
361
354
  "json",
362
355
  ordId,
363
- serviceName,
356
+ srvDefinition.name,
364
357
  "mcp.json",
365
358
  accessStrategies,
366
359
  ),
@@ -371,38 +364,49 @@ const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, pa
371
364
  {
372
365
  type: "graphql-sdl",
373
366
  mediaType: "text/plain",
374
- url: `/ord/v1/${ordId}/${serviceName}.graphql`,
367
+ url: `/ord/v1/${ordId}/${srvDefinition.name}.graphql`,
375
368
  accessStrategies: ensureAccessStrategies(accessStrategies, {
376
- resourceName: `${serviceName} (graphql-sdl)`,
369
+ resourceName: `${srvDefinition.name} (graphql-sdl)`,
377
370
  }),
378
371
  },
379
372
  ];
380
373
  } else if (apiProtocol === ORD_API_PROTOCOL.ODATA_V2) {
381
374
  // openapi-v3 is not supported for OData V2, only EDMX
382
375
  resourceDefinitions = [
383
- _getResourceDefinition("edmx", "xml", ordId, serviceName, "edmx", accessStrategies),
376
+ _getResourceDefinition("edmx", "xml", ordId, srvDefinition.name, "edmx", accessStrategies),
384
377
  ];
385
378
  } else {
386
379
  // odata-v4 and others have both OpenAPI and EDMX
387
380
  resourceDefinitions = [
388
- _getResourceDefinition("openapi-v3", "json", ordId, serviceName, "oas3.json", accessStrategies),
389
- _getResourceDefinition("edmx", "xml", ordId, serviceName, "edmx", accessStrategies),
381
+ _getResourceDefinition(
382
+ "openapi-v3",
383
+ "json",
384
+ ordId,
385
+ srvDefinition.name,
386
+ "oas3.json",
387
+ accessStrategies,
388
+ ),
389
+ _getResourceDefinition("edmx", "xml", ordId, srvDefinition.name, "edmx", accessStrategies),
390
390
  ];
391
391
  }
392
392
  }
393
393
 
394
- const exposedEntityTypes = _getExposedEntityTypes(serviceDefinition);
394
+ const exposedEntityTypes = _getExposedEntityTypes(srvDefinition);
395
395
 
396
396
  let obj = {
397
397
  ordId,
398
- title: serviceDefinition["@title"] ?? serviceDefinition["@Common.Label"] ?? serviceName,
399
- shortDescription: SHORT_DESCRIPTION_PREFIX + serviceName,
400
- description: serviceDefinition["@Core.Description"] ?? DESCRIPTION_PREFIX + serviceName,
398
+ title:
399
+ srvDefinition["@title"] ??
400
+ srvDefinition["@Common.Label"] ??
401
+ srvDefinition["@EndUserText.label"] ??
402
+ srvDefinition.name,
403
+ shortDescription: SHORT_DESCRIPTION_PREFIX + srvDefinition.name,
404
+ description: srvDefinition["@Core.Description"] ?? DESCRIPTION_PREFIX + srvDefinition.name,
401
405
  version: semanticVersion,
402
406
  lastUpdate: appConfig.lastUpdate,
403
407
  visibility,
404
408
  partOfPackage: packageId,
405
- partOfGroups: [_getGroupID(serviceDefinition, defaults.groupTypeId, appConfig)],
409
+ partOfGroups: [_getGroupID(appConfig, srvDefinition)],
406
410
  releaseStatus: "active",
407
411
  apiProtocol,
408
412
  resourceDefinitions,
@@ -412,10 +416,11 @@ const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, pa
412
416
  },
413
417
  ...(exposedEntityTypes ? { exposedEntityTypes } : []),
414
418
  ...ordExtensions,
419
+ ...protocolExtensions,
415
420
  };
416
421
 
417
422
  // Special handling for data product services
418
- if (isPrimaryDataProductService(serviceDefinition)) {
423
+ if (isPrimaryDataProductService(srvDefinition)) {
419
424
  obj.direction = "outbound";
420
425
  if (extracted) {
421
426
  // Overwrite partOfGroups
@@ -437,39 +442,47 @@ const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, pa
437
442
  * Properties of an event resource can be overwritten by the ORD extensions. Example: visibility.
438
443
  * Ensures proper visibility compliance by checking associated EntityTypes.
439
444
  *
440
- * @param {string} serviceName The name of the service.
441
- * @param {object} serviceDefinition The definition of the service
445
+ * @param {object} srvDefinition The definition of the service
442
446
  * @param {object} appConfig - The application configuration.
443
447
  * @param {Array} packageIds - The available package identifiers.
444
448
  * @param {Array} accessStrategies The array of accessStrategies objects
445
449
  * @returns {Array} An single-item array of objects for the Event Resources.
446
450
  */
447
- const createEventResourceTemplate = (serviceName, serviceDefinition, appConfig, packageIds, accessStrategies) => {
448
- const ordExtensions = readORDExtensions(serviceDefinition);
449
- const visibility = _handleVisibility(ordExtensions, serviceDefinition, appConfig.env?.defaultVisibility);
451
+ const createEventResourceTemplate = (srvDefinition, appConfig, packageIds, accessStrategies) => {
452
+ const ordExtensions = readORDExtensions(srvDefinition);
453
+ const visibility = _handleVisibility(ordExtensions, srvDefinition, appConfig.env?.defaultVisibility);
454
+ const version = ordExtensions.version || "1.0.0";
450
455
  const packageId = _getPackageID(appConfig.ordNamespace, packageIds, ORD_RESOURCE_TYPE.event, visibility);
451
- const ordId = `${appConfig.ordNamespace}:eventResource:${_getCleanServiceName(serviceDefinition, appConfig)}:v1`;
452
- const exposedEntityTypes = _getExposedEntityTypes(serviceDefinition);
456
+ const ordId = `${appConfig.ordNamespace}:eventResource:${_getCleanServiceName(srvDefinition.name, appConfig)}:v${version.split(".")[0]}`;
457
+ const exposedEntityTypes = _getExposedEntityTypes(srvDefinition);
453
458
 
454
459
  let obj = {
455
460
  ordId,
456
461
  title:
457
- serviceDefinition["@title"] ??
458
- serviceDefinition["@Common.Label"] ??
462
+ srvDefinition["@title"] ??
463
+ srvDefinition["@Common.Label"] ??
464
+ srvDefinition["@EndUserText.label"] ??
459
465
  `ODM ${appConfig.appName.replace(/[^a-zA-Z0-9]/g, "")} Events`,
460
- shortDescription: `${serviceName} event resource`,
466
+ shortDescription: `${srvDefinition.name} event resource`,
461
467
  description:
462
- serviceDefinition["@description"] ??
463
- serviceDefinition["@Core.Description"] ??
468
+ srvDefinition["@description"] ??
469
+ srvDefinition["@Core.Description"] ??
464
470
  "CAP Event resource describing events / messages.",
465
- version: "1.0.0",
471
+ version: version,
466
472
  lastUpdate: appConfig.lastUpdate,
467
473
  releaseStatus: "active",
468
474
  partOfPackage: packageId,
469
- partOfGroups: [_getGroupID(serviceDefinition, defaults.groupTypeId, appConfig)],
475
+ partOfGroups: [_getGroupID(appConfig, srvDefinition)],
470
476
  visibility,
471
477
  resourceDefinitions: [
472
- _getResourceDefinition("asyncapi-v2", "json", ordId, serviceName, "asyncapi2.json", accessStrategies),
478
+ _getResourceDefinition(
479
+ "asyncapi-v2",
480
+ "json",
481
+ ordId,
482
+ srvDefinition.name,
483
+ "asyncapi2.json",
484
+ accessStrategies,
485
+ ),
473
486
  ],
474
487
  extensible: { supported: "no" },
475
488
  ...(exposedEntityTypes ? { exposedEntityTypes } : []),
@@ -497,9 +510,9 @@ function _getExposedEntityTypes(definitionObj) {
497
510
  return _.uniqBy(entityData, CONTENT_MERGE_KEY);
498
511
  });
499
512
  const exposedEntityTypes = _.uniqBy(entities, CONTENT_MERGE_KEY)
500
- .filter((entity) => entity !== undefined)
501
- .map(({ ordId }) => ({
502
- ordId,
513
+ .filter((entity) => !!entity)
514
+ .map((entity) => ({
515
+ ordId: entity.isODMMapping ? entity.ordId : entity[`${ORD_EXTENSIONS_PREFIX}ordId`] || entity.ordId,
503
516
  }));
504
517
 
505
518
  if (exposedEntityTypes.length > 0) {
@@ -556,7 +569,6 @@ function _extractVersionFromServiceName(serviceName) {
556
569
 
557
570
  return {
558
571
  cleanName: serviceName.replace(versionPattern, ""),
559
- version: `v${versionNumber}`,
560
572
  semanticVersion: `${versionNumber}.0.0`,
561
573
  };
562
574
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cap-js/ord",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "CAP Plugin for generating ORD document.",
5
5
  "repository": "cap-js/ord",
6
6
  "author": "SAP SE (https://www.sap.com)",
@@ -33,7 +33,7 @@
33
33
  "@cap-js/sqlite": "^2",
34
34
  "@sap/cds-dk": ">=8.9.5",
35
35
  "eslint": "^10.0.0",
36
- "express": "^4",
36
+ "express": "^5.0.0",
37
37
  "jest": "^30.0.0",
38
38
  "prettier": "3.8.3",
39
39
  "supertest": "^7.0.0"