@cap-js/ord 1.3.3 → 1.3.5

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/constants.js CHANGED
@@ -9,6 +9,7 @@ const BUILD_DEFAULT_PATH = "gen/ord";
9
9
 
10
10
  const BLOCKED_SERVICE_NAME = Object.freeze({
11
11
  MTXServices: "cds.xt.MTXServices",
12
+ OpenResourceDiscoveryService: "OpenResourceDiscoveryService",
12
13
  });
13
14
 
14
15
  const ORD_ACCESS_STRATEGY = Object.freeze({
package/lib/defaults.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const { OPEN_RESOURCE_DISCOVERY_VERSION, SHORT_DESCRIPTION_PREFIX, RESOURCE_VISIBILITY } = require("./constants");
2
+ const { hasSAPPolicyLevel } = require("./utils");
2
3
  const { getAuthConfig } = require("./authentication");
3
4
  const _ = require("lodash");
4
5
 
@@ -35,15 +36,6 @@ const generateUniquePackageOrdId = (ordNamespace, name, tag, visibility) => {
35
36
  return `${ordNamespace}:package:${regexWithRemoval(name)}${tag}${visibilitySuffix}:v1`;
36
37
  };
37
38
 
38
- /**
39
- * Checks if at least one policy level in the array is SAP.
40
- *
41
- * @param {string[]} policyLevels - Array of policy levels.
42
- */
43
- function hasSAPPolicyLevel(policyLevels) {
44
- return policyLevels.some((policyLevel) => policyLevel.split(":")[0].toLowerCase() === "sap");
45
- }
46
-
47
39
  /**
48
40
  * Module containing default configuration for ORD Document.
49
41
  * @module defaults
@@ -58,16 +50,16 @@ module.exports = {
58
50
  ordId: defaultProductOrdId(name),
59
51
  title: nameWithSpaces(name),
60
52
  shortDescription: SHORT_DESCRIPTION_PREFIX + nameWithSpaces(name),
61
- vendor: "customer:vendor:customer:",
53
+ vendor: "customer:vendor:Customer:",
62
54
  },
63
55
  ],
64
56
  groupTypeId: "sap.cds:service",
65
- packages: function getPackageData(appConfig, policyLevels) {
57
+ packages: function getPackageData(appConfig) {
66
58
  const name = appConfig.appName;
67
59
  const ordNamespace = appConfig.ordNamespace;
68
60
  const productsOrdId = appConfig.existingProductORDId || appConfig.products?.[0]?.ordId;
69
61
  const vendor = appConfig.env?.packages?.[0]?.vendor;
70
- if (hasSAPPolicyLevel(policyLevels)) {
62
+ if (hasSAPPolicyLevel(appConfig.policyLevels)) {
71
63
  return _.uniqBy(
72
64
  packageTypes.flatMap(({ tag, type }) =>
73
65
  Object.values(RESOURCE_VISIBILITY).map((visibility) => ({
package/lib/ord.js CHANGED
@@ -87,7 +87,10 @@ function _triageCsnDefinitions(csn) {
87
87
 
88
88
  for (const definitionKey of Object.keys(csn.definitions)) {
89
89
  const definitionObj = csn.definitions[definitionKey];
90
- if (definitionKey.includes(BLOCKED_SERVICE_NAME.MTXServices)) {
90
+ if (
91
+ definitionKey.includes(BLOCKED_SERVICE_NAME.MTXServices) ||
92
+ definitionKey.includes(BLOCKED_SERVICE_NAME.OpenResourceDiscoveryService)
93
+ ) {
91
94
  Logger.warn(`ORD service name "${definitionKey}" is blocked.`);
92
95
  continue;
93
96
  }
@@ -185,14 +188,14 @@ const _getGroups = (csn, appConfig) => {
185
188
  .filter((resource) => !!resource);
186
189
  };
187
190
 
188
- const _getPackages = (policyLevels, appConfig) => {
189
- return defaults.packages(appConfig, policyLevels);
191
+ const _getPackages = (appConfig) => {
192
+ return defaults.packages(appConfig);
190
193
  };
191
194
 
192
195
  const _getEntityTypes = (appConfig, packageIds) => {
193
196
  if (!appConfig.entityTypeTargets?.length) return [];
194
197
 
195
- return appConfig.entityTypeTargets.map((entity) => createEntityTypeTemplate(appConfig, packageIds, entity));
198
+ return appConfig.entityTypeTargets.flatMap((entity) => createEntityTypeTemplate(appConfig, packageIds, entity));
196
199
  };
197
200
 
198
201
  const _getAPIResources = (csn, appConfig, packageIds, accessStrategies) => {
@@ -238,10 +241,11 @@ const _getProducts = (appConfig) => {
238
241
  };
239
242
 
240
243
  function createDefaultORDDocument(linkedCsn, appConfig) {
244
+ appConfig.policyLevels = _getPolicyLevels(appConfig);
241
245
  let ordDocument = {
242
246
  $schema: "https://open-resource-discovery.github.io/specification/spec-v1/interfaces/Document.schema.json",
243
247
  openResourceDiscovery: _getOpenResourceDiscovery(appConfig),
244
- policyLevels: _getPolicyLevels(appConfig),
248
+ policyLevels: appConfig.policyLevels,
245
249
  description: _getDescription(appConfig),
246
250
  consumptionBundles: _getConsumptionBundles(appConfig),
247
251
  };
@@ -256,7 +260,7 @@ function createDefaultORDDocument(linkedCsn, appConfig) {
256
260
  ordDocument.products = [_getProducts(appConfig)[0]];
257
261
  }
258
262
 
259
- ordDocument.packages = _getPackages(ordDocument.policyLevels, appConfig);
263
+ ordDocument.packages = _getPackages(appConfig);
260
264
 
261
265
  return ordDocument;
262
266
  }
package/lib/templates.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const cds = require("@sap/cds");
2
+ const { hasSAPPolicyLevel } = require("./utils");
2
3
  const defaults = require("./defaults");
3
4
  const _ = require("lodash");
4
5
  const {
@@ -80,6 +81,7 @@ const createEntityTypeMappingsItemTemplate = (entity) => {
80
81
  return {
81
82
  ordId: `sap.odm:entityType:${entity[ORD_ODM_ENTITY_NAME_ANNOTATION]}:v1`,
82
83
  entityName: entity[ORD_ODM_ENTITY_NAME_ANNOTATION],
84
+ isODMMapping: true,
83
85
  ...entity,
84
86
  };
85
87
  } else if (entity[ENTITY_RELATIONSHIP_ANNOTATION]) {
@@ -95,8 +97,19 @@ const createEntityTypeMappingsItemTemplate = (entity) => {
95
97
  }
96
98
  };
97
99
 
98
- function _getGroupID(fullyQualifiedName, groupTypeId = defaults.groupTypeId, appConfig) {
99
- return `${groupTypeId}:${appConfig.ordNamespace}:${fullyQualifiedName}`;
100
+ function _getGroupID(serviceDefinition, groupTypeId = defaults.groupTypeId, appConfig) {
101
+ return `${groupTypeId}:${appConfig.ordNamespace}:${_getGroupNameWithNestedNamespace(serviceDefinition, appConfig)}`;
102
+ }
103
+
104
+ function _getGroupNameWithNestedNamespace({ name }, appConfig) {
105
+ if (!name.startsWith(appConfig.ordNamespace)) {
106
+ return name;
107
+ }
108
+ let sortedName = name.substring(appConfig.ordNamespace.length);
109
+ if (sortedName.startsWith(".")) {
110
+ sortedName = sortedName.substring(1);
111
+ }
112
+ return sortedName;
100
113
  }
101
114
 
102
115
  /**
@@ -174,7 +187,7 @@ const createGroupsTemplateForService = (serviceName, serviceDefinition, appConfi
174
187
  return undefined;
175
188
  }
176
189
 
177
- const groupId = _getGroupID(serviceName, defaults.groupTypeId, appConfig);
190
+ const groupId = _getGroupID(serviceDefinition, defaults.groupTypeId, appConfig);
178
191
  return {
179
192
  groupId: groupId,
180
193
  groupTypeId: defaults.groupTypeId,
@@ -192,11 +205,20 @@ const createGroupsTemplateForService = (serviceName, serviceDefinition, appConfi
192
205
  * @returns { object } An object for the EntityType.
193
206
  */
194
207
  const createEntityTypeTemplate = (appConfig, packageIds, entity) => {
208
+ if (entity.isODMMapping) {
209
+ // ODM mappings are not created as entity types, they are only used in entityTypeMappings
210
+ return [];
211
+ }
212
+ if (hasSAPPolicyLevel(appConfig.policyLevels)) {
213
+ // If SAP policy level is present, don't create entity type, they must be in the central repository
214
+ return [];
215
+ }
216
+
195
217
  const ordExtensions = readORDExtensions(entity);
196
218
  const visibility = ordExtensions.visibility || RESOURCE_VISIBILITY.public;
197
219
 
198
220
  if (visibility === RESOURCE_VISIBILITY.private) {
199
- return null;
221
+ return [];
200
222
  }
201
223
 
202
224
  const packageId = _getPackageID(appConfig.ordNamespace, packageIds, ORD_RESOURCE_TYPE.entityType, visibility);
@@ -220,7 +242,9 @@ const createEntityTypeTemplate = (appConfig, packageIds, entity) => {
220
242
 
221
243
  function _handleVisibility(ordExtensions, definition) {
222
244
  let visibility;
223
- if (ordExtensions.visibility) {
245
+ if (isPrimaryDataProductService(definition)) {
246
+ visibility = RESOURCE_VISIBILITY.internal;
247
+ } else if (ordExtensions.visibility) {
224
248
  visibility = ordExtensions.visibility;
225
249
  } else if (definition[ORD_EXTENSIONS_PREFIX + "visibility"]) {
226
250
  visibility = definition[ORD_EXTENSIONS_PREFIX + "visibility"];
@@ -248,7 +272,7 @@ const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, pa
248
272
 
249
273
  const paths = _generatePaths(serviceName, serviceDefinition);
250
274
  const apiResources = [];
251
- const ordId = `${appConfig.ordNamespace}:apiResource:${serviceName}:v1`;
275
+ const ordId = `${appConfig.ordNamespace}:apiResource:${_getGroupNameWithNestedNamespace(serviceDefinition, appConfig)}:v1`;
252
276
 
253
277
  paths.forEach((generatedPath) => {
254
278
  let resourceDefinitions = [
@@ -273,7 +297,7 @@ const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, pa
273
297
  lastUpdate: appConfig.lastUpdate,
274
298
  visibility,
275
299
  partOfPackage: packageId,
276
- partOfGroups: [_getGroupID(serviceName, defaults.groupTypeId, appConfig)],
300
+ partOfGroups: [_getGroupID(serviceDefinition, defaults.groupTypeId, appConfig)],
277
301
  releaseStatus: "active",
278
302
  apiProtocol: generatedPath.kind === "odata" ? "odata-v4" : generatedPath.kind,
279
303
  resourceDefinitions: resourceDefinitions,
@@ -285,9 +309,8 @@ const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, pa
285
309
  ...ordExtensions,
286
310
  };
287
311
 
288
- if (serviceDefinition[DATA_PRODUCT_ANNOTATION] === DATA_PRODUCT_TYPE.primary) {
312
+ if (isPrimaryDataProductService(serviceDefinition)) {
289
313
  obj.apiProtocol = "rest";
290
- obj.visibility = RESOURCE_VISIBILITY.internal;
291
314
  obj.direction = "outbound";
292
315
  obj.implementationStandard = "sap.dp:data-subscription-api:v1";
293
316
  obj.entryPoints = [];
@@ -328,7 +351,7 @@ const createEventResourceTemplate = (serviceName, serviceDefinition, appConfig,
328
351
  const ordExtensions = readORDExtensions(serviceDefinition);
329
352
  const visibility = _handleVisibility(ordExtensions, serviceDefinition);
330
353
  const packageId = _getPackageID(appConfig.ordNamespace, packageIds, ORD_RESOURCE_TYPE.event, visibility);
331
- const ordId = `${appConfig.ordNamespace}:eventResource:${serviceName}:v1`;
354
+ const ordId = `${appConfig.ordNamespace}:eventResource:${_getGroupNameWithNestedNamespace(serviceDefinition, appConfig)}:v1`;
332
355
  const entityTypeMappings = _getEntityTypeMappings(serviceDefinition);
333
356
 
334
357
  let obj = {
@@ -346,7 +369,7 @@ const createEventResourceTemplate = (serviceName, serviceDefinition, appConfig,
346
369
  lastUpdate: appConfig.lastUpdate,
347
370
  releaseStatus: "active",
348
371
  partOfPackage: packageId,
349
- partOfGroups: [_getGroupID(serviceName, defaults.groupTypeId, appConfig)],
372
+ partOfGroups: [_getGroupID(serviceDefinition, defaults.groupTypeId, appConfig)],
350
373
  visibility,
351
374
  resourceDefinitions: [
352
375
  _getResourceDefinition("asyncapi-v2", "json", ordId, serviceName, "asyncapi2.json", accessStrategies),
@@ -361,13 +384,18 @@ const createEventResourceTemplate = (serviceName, serviceDefinition, appConfig,
361
384
  : [];
362
385
  };
363
386
 
387
+ function isPrimaryDataProductService(serviceDefinition) {
388
+ return serviceDefinition[DATA_PRODUCT_ANNOTATION] === DATA_PRODUCT_TYPE.primary;
389
+ }
390
+
364
391
  function _getEntityTypeMappings(definitionObj) {
365
392
  if (!definitionObj.entities) {
366
393
  return;
367
394
  }
368
- const entities = Object.values(definitionObj.entities)
369
- .flatMap((entity) => _flattenEntityGraph(entity))
370
- .map(createEntityTypeMappingsItemTemplate);
395
+ const entities = Object.values(definitionObj.entities).flatMap((entity) => {
396
+ const entityData = _flattenEntityGraph(entity).map(createEntityTypeMappingsItemTemplate);
397
+ return _.uniqBy(entityData, CONTENT_MERGE_KEY);
398
+ });
371
399
  const entityTypeTargets = _.uniqBy(entities, CONTENT_MERGE_KEY)
372
400
  .filter((entity) => entity !== undefined)
373
401
  .map(({ ordId }) => ({
@@ -394,8 +422,15 @@ function _flattenEntityGraph(currentEntity, processedEntities = []) {
394
422
  if (processedEntities.includes(target)) {
395
423
  return;
396
424
  }
397
- processedEntities = [...processedEntities, target];
398
425
  assertionsTodo.push(entity);
426
+
427
+ /*
428
+ the next line operates on heap memory so that the same entity is not processed again
429
+ heap memory is used so that the check is the same in:
430
+ a > b > c > b scenario (runs first)
431
+ a > d > c > ... scenario (runs later and does not process c again)
432
+ */
433
+ processedEntities.push(target);
399
434
  });
400
435
 
401
436
  return [currentEntity, ...assertionsTodo.flatMap((entity) => _flattenEntityGraph(entity, processedEntities))];
package/lib/utils.js ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Checks if at least one policy level in the array is SAP.
3
+ *
4
+ * @param {string[]} policyLevels - Array of policy levels.
5
+ */
6
+ function hasSAPPolicyLevel(policyLevels) {
7
+ return policyLevels.some((policyLevel) => policyLevel.split(":")[0].toLowerCase() === "sap");
8
+ }
9
+
10
+ module.exports = {
11
+ hasSAPPolicyLevel,
12
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cap-js/ord",
3
- "version": "1.3.3",
3
+ "version": "1.3.5",
4
4
  "description": "CAP Plugin for generating ORD document.",
5
5
  "repository": "cap-js/ord",
6
6
  "author": "SAP SE (https://www.sap.com)",