@cap-js/ord 1.3.8 → 1.3.10

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/build.js CHANGED
@@ -10,7 +10,9 @@ module.exports = class OrdBuildPlugin extends cds_dk.build.Plugin {
10
10
  static taskDefaults = { src: cds.env.folders.srv };
11
11
 
12
12
  init() {
13
- this.task.dest = path.join(cds.root, BUILD_DEFAULT_PATH);
13
+ if (this.task.dest === undefined) {
14
+ this.task.dest = path.join(cds.root, BUILD_DEFAULT_PATH);
15
+ }
14
16
  }
15
17
 
16
18
  async _writeResourcesFiles(resObj, model, promises) {
package/lib/constants.js CHANGED
@@ -44,6 +44,8 @@ const CONTENT_MERGE_KEY = "ordId";
44
44
 
45
45
  const DATA_PRODUCT_ANNOTATION = "@DataIntegration.dataProduct.type";
46
46
 
47
+ const DATA_PRODUCT_SIMPLE_ANNOTATION = "@data.product";
48
+
47
49
  const DATA_PRODUCT_TYPE = Object.freeze({
48
50
  primary: "primary",
49
51
  });
@@ -106,6 +108,7 @@ module.exports = {
106
108
  COMPILER_TYPES,
107
109
  CONTENT_MERGE_KEY,
108
110
  DATA_PRODUCT_ANNOTATION,
111
+ DATA_PRODUCT_SIMPLE_ANNOTATION,
109
112
  DATA_PRODUCT_TYPE,
110
113
  DESCRIPTION_PREFIX,
111
114
  ENTITY_RELATIONSHIP_ANNOTATION,
package/lib/defaults.js CHANGED
@@ -12,6 +12,26 @@ const packageTypes = [
12
12
  { tag: "-dataProduct", type: "Data Products" },
13
13
  ];
14
14
 
15
+ const stringTypeCheck = (value) => typeof value === "string";
16
+ const arrayTypeCheck = (value) => Array.isArray(value);
17
+
18
+ // see ref: https://pages.github.tools.sap/CentralEngineering/open-resource-discovery-specification/spec-v1/interfaces/document#package
19
+ const packageTypeChecks = {
20
+ policyLevels: arrayTypeCheck,
21
+ packageLinks: arrayTypeCheck,
22
+ links: arrayTypeCheck,
23
+ licenseType: stringTypeCheck,
24
+ supportInfo: stringTypeCheck,
25
+ vendor: stringTypeCheck,
26
+ countries: arrayTypeCheck,
27
+ lineOfBusiness: arrayTypeCheck,
28
+ industry: arrayTypeCheck,
29
+ runtimeRestriction: stringTypeCheck,
30
+ tags: arrayTypeCheck,
31
+ labels: arrayTypeCheck,
32
+ documentationLabels: arrayTypeCheck,
33
+ };
34
+
15
35
  const regexWithRemoval = (name) => {
16
36
  return name?.replace(/[^a-zA-Z0-9]/g, "");
17
37
  };
@@ -36,6 +56,22 @@ const generateUniquePackageOrdId = (ordNamespace, name, tag, visibility) => {
36
56
  return `${ordNamespace}:package:${regexWithRemoval(name)}${tag}${visibilitySuffix}:v1`;
37
57
  };
38
58
 
59
+ const mapEnvPackageInfo = (packageConfig) => {
60
+ if (!packageConfig) {
61
+ return { vendor: undefined };
62
+ }
63
+
64
+ const filteredEnv = {};
65
+ for (const key in packageConfig) {
66
+ const value = packageConfig[key];
67
+ const checkFunction = packageTypeChecks[key];
68
+ if (value && checkFunction && checkFunction(value)) {
69
+ filteredEnv[key] = value;
70
+ }
71
+ }
72
+ return filteredEnv;
73
+ };
74
+
39
75
  /**
40
76
  * Module containing default configuration for ORD Document.
41
77
  * @module defaults
@@ -58,7 +94,7 @@ module.exports = {
58
94
  const name = appConfig.appName;
59
95
  const ordNamespace = appConfig.ordNamespace;
60
96
  const productsOrdId = appConfig.existingProductORDId || appConfig.products?.[0]?.ordId;
61
- const vendor = appConfig.env?.packages?.[0]?.vendor;
97
+ const { vendor, ...envValues } = mapEnvPackageInfo(appConfig?.env?.packages?.[0]);
62
98
  if (hasSAPPolicyLevel(appConfig.policyLevels)) {
63
99
  return _.uniqBy(
64
100
  packageTypes.flatMap(({ tag, type }) =>
@@ -69,6 +105,7 @@ module.exports = {
69
105
  version: "1.0.0",
70
106
  ...(productsOrdId && { partOfProducts: [productsOrdId || defaultProductOrdId(name)] }),
71
107
  vendor: vendor || "customer:vendor:Customer:",
108
+ ...envValues,
72
109
  })),
73
110
  ),
74
111
  "ordId",
@@ -82,6 +119,7 @@ module.exports = {
82
119
  version: "1.0.0",
83
120
  ...(productsOrdId && { partOfProducts: [productsOrdId || defaultProductOrdId(name)] }),
84
121
  vendor: vendor || "customer:vendor:Customer:",
122
+ ...envValues,
85
123
  },
86
124
  ];
87
125
  }
package/lib/templates.js CHANGED
@@ -5,6 +5,7 @@ const _ = require("lodash");
5
5
  const {
6
6
  AUTHENTICATION_TYPE,
7
7
  DATA_PRODUCT_ANNOTATION,
8
+ DATA_PRODUCT_SIMPLE_ANNOTATION,
8
9
  DATA_PRODUCT_TYPE,
9
10
  DESCRIPTION_PREFIX,
10
11
  ENTITY_RELATIONSHIP_ANNOTATION,
@@ -189,6 +190,13 @@ const createGroupsTemplateForService = (serviceName, serviceDefinition, appConfi
189
190
  return undefined;
190
191
  }
191
192
 
193
+ const visibility = _handleVisibility(ordExtensions, serviceDefinition, appConfig.env?.defaultVisibility);
194
+ if (visibility === RESOURCE_VISIBILITY.private) {
195
+ // If the visibility of the service is private, do not create a group
196
+ Logger.debug("Skipping group creation for private service:", serviceName);
197
+ return undefined;
198
+ }
199
+
192
200
  const groupId = _getGroupID(serviceDefinition, defaults.groupTypeId, appConfig);
193
201
  return {
194
202
  groupId: groupId,
@@ -257,7 +265,13 @@ function _handleVisibility(ordExtensions, definition, defaultVisibility = RESOUR
257
265
  let visibility;
258
266
  //check for supported custom visibility value in defaultVisibility variable
259
267
  if (!ALLOWED_VISIBILITY.includes(defaultVisibility)) {
260
- Logger.warn("Default visibility", defaultVisibility, "is not supported. Using", RESOURCE_VISIBILITY.public, "as fallback.");
268
+ Logger.warn(
269
+ "Default visibility",
270
+ defaultVisibility,
271
+ "is not supported. Using",
272
+ RESOURCE_VISIBILITY.public,
273
+ "as fallback.",
274
+ );
261
275
  defaultVisibility = RESOURCE_VISIBILITY.public;
262
276
  }
263
277
  // Determine visibility
@@ -295,7 +309,34 @@ const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, pa
295
309
 
296
310
  const paths = _generatePaths(serviceName, serviceDefinition);
297
311
  const apiResources = [];
298
- const ordId = `${appConfig.ordNamespace}:apiResource:${_getGroupNameWithNestedNamespace(serviceDefinition, appConfig)}:v1`;
312
+
313
+ // Handle version suffix extraction for primary data product services
314
+ let cleanServiceName,
315
+ version,
316
+ semanticVersion,
317
+ extracted = null;
318
+ if (isPrimaryDataProductService(serviceDefinition)) {
319
+ extracted = _extractVersionFromServiceName(serviceDefinition.name);
320
+ if (extracted) {
321
+ // Create a temporary service definition with the clean name for namespace processing
322
+ const cleanServiceDefinition = { ...serviceDefinition, name: extracted.cleanName };
323
+ cleanServiceName = _getGroupNameWithNestedNamespace(cleanServiceDefinition, appConfig);
324
+ version = extracted.version;
325
+ semanticVersion = extracted.semanticVersion;
326
+ } else {
327
+ // Invalid pattern - use current behavior
328
+ cleanServiceName = _getGroupNameWithNestedNamespace(serviceDefinition, appConfig);
329
+ version = "v1";
330
+ semanticVersion = "1.0.0";
331
+ }
332
+ } else {
333
+ // Non-data product - use current behavior
334
+ cleanServiceName = _getGroupNameWithNestedNamespace(serviceDefinition, appConfig);
335
+ version = "v1";
336
+ semanticVersion = "1.0.0";
337
+ }
338
+
339
+ const ordId = `${appConfig.ordNamespace}:apiResource:${cleanServiceName}:${version}`;
299
340
 
300
341
  paths.forEach((generatedPath) => {
301
342
  let resourceDefinitions = [
@@ -317,7 +358,7 @@ const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, pa
317
358
  title: serviceDefinition["@title"] ?? serviceDefinition["@Common.Label"] ?? serviceName,
318
359
  shortDescription: SHORT_DESCRIPTION_PREFIX + serviceName,
319
360
  description: serviceDefinition["@Core.Description"] ?? DESCRIPTION_PREFIX + serviceName,
320
- version: "1.0.0",
361
+ version: semanticVersion,
321
362
  lastUpdate: appConfig.lastUpdate,
322
363
  visibility,
323
364
  partOfPackage: packageId,
@@ -339,6 +380,10 @@ const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, pa
339
380
  obj.direction = "outbound";
340
381
  obj.implementationStandard = "sap.dp:data-subscription-api:v1";
341
382
  obj.entryPoints = [];
383
+ if (extracted) {
384
+ // Overwrite partOfGroups
385
+ obj.partOfGroups = [`${defaults.groupTypeId}:${appConfig.ordNamespace}:${cleanServiceName}`];
386
+ }
342
387
  obj.resourceDefinitions = [
343
388
  _getResourceDefinition(
344
389
  "sap-csn-interop-effective-v1",
@@ -412,7 +457,10 @@ const createEventResourceTemplate = (serviceName, serviceDefinition, appConfig,
412
457
  };
413
458
 
414
459
  function isPrimaryDataProductService(serviceDefinition) {
415
- return serviceDefinition[DATA_PRODUCT_ANNOTATION] === DATA_PRODUCT_TYPE.primary;
460
+ return (
461
+ serviceDefinition[DATA_PRODUCT_ANNOTATION] === DATA_PRODUCT_TYPE.primary ||
462
+ !!serviceDefinition[DATA_PRODUCT_SIMPLE_ANNOTATION]
463
+ );
416
464
  }
417
465
 
418
466
  function _getEntityTypeMappings(definitionObj) {
@@ -483,6 +531,32 @@ function _flattenEntityGraph(currentEntity, processedEntities = []) {
483
531
  return [currentEntity, ...assertionsTodo.flatMap((entity) => _flattenEntityGraph(entity, processedEntities))];
484
532
  }
485
533
 
534
+ /**
535
+ * Extracts version suffix from service name for data product services.
536
+ * Only accepts pattern: .v<number> (e.g., .v0, .v1, .v2, .v10)
537
+ * Rejects patterns like: .v1.1, .v1.0, .version1, .beta
538
+ *
539
+ * @param {string} serviceName The full service name
540
+ * @returns {Object|null} Object with cleanName, version, and semanticVersion, or null if invalid pattern
541
+ */
542
+ function _extractVersionFromServiceName(serviceName) {
543
+ // Only match pattern: .v<number> (where number is 1 or more digits)
544
+ const versionPattern = /\.v(\d+)$/;
545
+ const match = serviceName.match(versionPattern);
546
+
547
+ if (!match) {
548
+ return null; // No valid version suffix found
549
+ }
550
+
551
+ const versionNumber = parseInt(match[1], 10);
552
+
553
+ return {
554
+ cleanName: serviceName.replace(versionPattern, ""),
555
+ version: `v${versionNumber}`,
556
+ semanticVersion: `${versionNumber}.0.0`,
557
+ };
558
+ }
559
+
486
560
  function _getPackageID(namespace, packageIds, resourceType, visibility = RESOURCE_VISIBILITY.public) {
487
561
  if (!packageIds) return;
488
562
 
@@ -531,4 +605,5 @@ module.exports = {
531
605
  _getExposedEntityTypes,
532
606
  _propagateORDVisibility,
533
607
  _handleVisibility,
608
+ isPrimaryDataProductService,
534
609
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cap-js/ord",
3
- "version": "1.3.8",
3
+ "version": "1.3.10",
4
4
  "description": "CAP Plugin for generating ORD document.",
5
5
  "repository": "cap-js/ord",
6
6
  "author": "SAP SE (https://www.sap.com)",
@@ -25,8 +25,8 @@
25
25
  },
26
26
  "devDependencies": {
27
27
  "eslint": "^9.2.0",
28
- "jest": "^29.7.0",
29
- "prettier": "3.5.3"
28
+ "jest": "^30.0.0",
29
+ "prettier": "3.6.2"
30
30
  },
31
31
  "peerDependencies": {
32
32
  "@sap/cds": ">=8.9.4",