@cap-js/ord 1.3.2 → 1.3.4
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 +4 -12
- package/lib/ord.js +24 -15
- package/lib/templates.js +50 -17
- package/lib/utils.js +12 -0
- package/package.json +1 -1
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:
|
|
53
|
+
vendor: "customer:vendor:Customer:",
|
|
62
54
|
},
|
|
63
55
|
],
|
|
64
56
|
groupTypeId: "sap.cds:service",
|
|
65
|
-
packages: function getPackageData(appConfig
|
|
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
|
@@ -34,14 +34,15 @@ const initializeAppConfig = (csn) => {
|
|
|
34
34
|
|
|
35
35
|
_validateNamespaces(ordNamespace, eventApplicationNamespace);
|
|
36
36
|
|
|
37
|
-
const { serviceNames, apiResourceNames, apiEndpoints,
|
|
37
|
+
const { serviceNames, apiResourceNames, apiEndpoints, eventServiceNames, entityTypeTargets } =
|
|
38
|
+
_triageCsnDefinitions(csn);
|
|
38
39
|
|
|
39
40
|
return {
|
|
40
41
|
env: cds.env["ord"],
|
|
41
42
|
lastUpdate,
|
|
42
43
|
appName,
|
|
43
44
|
apiEndpoints: Array.from(apiEndpoints),
|
|
44
|
-
|
|
45
|
+
eventServiceNames,
|
|
45
46
|
serviceNames,
|
|
46
47
|
apiResourceNames,
|
|
47
48
|
entityTypeTargets: _.uniqBy(entityTypeTargets, CONTENT_MERGE_KEY),
|
|
@@ -77,9 +78,12 @@ function _validateNamespaces(ordNamespace, eventApplicationNamespace) {
|
|
|
77
78
|
function _triageCsnDefinitions(csn) {
|
|
78
79
|
const pendingApiResourceNames = [];
|
|
79
80
|
const apiEndpoints = new Set();
|
|
80
|
-
const
|
|
81
|
+
const pendingEventServiceNames = new Set();
|
|
81
82
|
const entityTypeTargets = [];
|
|
82
83
|
const pendingServiceNames = [];
|
|
84
|
+
const serviceNames = Object.keys(csn.definitions).filter(
|
|
85
|
+
(key) => csn.definitions[key].kind === CDS_ELEMENT_KIND.service,
|
|
86
|
+
);
|
|
83
87
|
|
|
84
88
|
for (const definitionKey of Object.keys(csn.definitions)) {
|
|
85
89
|
const definitionObj = csn.definitions[definitionKey];
|
|
@@ -103,8 +107,8 @@ function _triageCsnDefinitions(csn) {
|
|
|
103
107
|
break;
|
|
104
108
|
}
|
|
105
109
|
case CDS_ELEMENT_KIND.event: {
|
|
106
|
-
const event = _handleEvent(definitionKey);
|
|
107
|
-
if (event)
|
|
110
|
+
const event = _handleEvent(serviceNames, definitionKey);
|
|
111
|
+
if (event) pendingEventServiceNames.add(event);
|
|
108
112
|
break;
|
|
109
113
|
}
|
|
110
114
|
case CDS_ELEMENT_KIND.action:
|
|
@@ -120,7 +124,7 @@ function _triageCsnDefinitions(csn) {
|
|
|
120
124
|
serviceNames: pendingServiceNames,
|
|
121
125
|
apiResourceNames: pendingApiResourceNames,
|
|
122
126
|
apiEndpoints: Array.from(apiEndpoints),
|
|
123
|
-
|
|
127
|
+
eventServiceNames: [...pendingEventServiceNames],
|
|
124
128
|
entityTypeTargets,
|
|
125
129
|
};
|
|
126
130
|
}
|
|
@@ -156,8 +160,12 @@ function _handleEntity(key, keyDefinition) {
|
|
|
156
160
|
return null;
|
|
157
161
|
}
|
|
158
162
|
|
|
159
|
-
function _handleEvent(key) {
|
|
160
|
-
|
|
163
|
+
function _handleEvent(serviceNames, key) {
|
|
164
|
+
for (const serviceName of serviceNames) {
|
|
165
|
+
if (key.startsWith(serviceName + ".")) {
|
|
166
|
+
return serviceName;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
161
169
|
}
|
|
162
170
|
|
|
163
171
|
function _handleActionOrFunction(key) {
|
|
@@ -177,14 +185,14 @@ const _getGroups = (csn, appConfig) => {
|
|
|
177
185
|
.filter((resource) => !!resource);
|
|
178
186
|
};
|
|
179
187
|
|
|
180
|
-
const _getPackages = (
|
|
181
|
-
return defaults.packages(appConfig
|
|
188
|
+
const _getPackages = (appConfig) => {
|
|
189
|
+
return defaults.packages(appConfig);
|
|
182
190
|
};
|
|
183
191
|
|
|
184
192
|
const _getEntityTypes = (appConfig, packageIds) => {
|
|
185
193
|
if (!appConfig.entityTypeTargets?.length) return [];
|
|
186
194
|
|
|
187
|
-
return appConfig.entityTypeTargets.
|
|
195
|
+
return appConfig.entityTypeTargets.flatMap((entity) => createEntityTypeTemplate(appConfig, packageIds, entity));
|
|
188
196
|
};
|
|
189
197
|
|
|
190
198
|
const _getAPIResources = (csn, appConfig, packageIds, accessStrategies) => {
|
|
@@ -200,7 +208,7 @@ const _getAPIResources = (csn, appConfig, packageIds, accessStrategies) => {
|
|
|
200
208
|
};
|
|
201
209
|
|
|
202
210
|
const _getEventResources = (csn, appConfig, packageIds, accessStrategies) => {
|
|
203
|
-
return appConfig.
|
|
211
|
+
return appConfig.eventServiceNames.flatMap((serviceName) =>
|
|
204
212
|
createEventResourceTemplate(serviceName, csn.definitions[serviceName], appConfig, packageIds, accessStrategies),
|
|
205
213
|
);
|
|
206
214
|
};
|
|
@@ -230,10 +238,11 @@ const _getProducts = (appConfig) => {
|
|
|
230
238
|
};
|
|
231
239
|
|
|
232
240
|
function createDefaultORDDocument(linkedCsn, appConfig) {
|
|
241
|
+
appConfig.policyLevels = _getPolicyLevels(appConfig);
|
|
233
242
|
let ordDocument = {
|
|
234
243
|
$schema: "https://open-resource-discovery.github.io/specification/spec-v1/interfaces/Document.schema.json",
|
|
235
244
|
openResourceDiscovery: _getOpenResourceDiscovery(appConfig),
|
|
236
|
-
policyLevels:
|
|
245
|
+
policyLevels: appConfig.policyLevels,
|
|
237
246
|
description: _getDescription(appConfig),
|
|
238
247
|
consumptionBundles: _getConsumptionBundles(appConfig),
|
|
239
248
|
};
|
|
@@ -248,7 +257,7 @@ function createDefaultORDDocument(linkedCsn, appConfig) {
|
|
|
248
257
|
ordDocument.products = [_getProducts(appConfig)[0]];
|
|
249
258
|
}
|
|
250
259
|
|
|
251
|
-
ordDocument.packages = _getPackages(
|
|
260
|
+
ordDocument.packages = _getPackages(appConfig);
|
|
252
261
|
|
|
253
262
|
return ordDocument;
|
|
254
263
|
}
|
|
@@ -295,7 +304,7 @@ module.exports = (csn) => {
|
|
|
295
304
|
ordDocument.apiResources = apiResources;
|
|
296
305
|
}
|
|
297
306
|
}
|
|
298
|
-
if (appConfig.
|
|
307
|
+
if (appConfig.eventServiceNames.length) {
|
|
299
308
|
const eventResources = _getEventResources(linkedCsn, appConfig, packageIds, accessStrategies);
|
|
300
309
|
if (eventResources.length) {
|
|
301
310
|
ordDocument.eventResources = eventResources;
|
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(
|
|
99
|
-
return `${groupTypeId}:${appConfig.ordNamespace}:${
|
|
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(
|
|
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
|
|
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 (
|
|
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:${
|
|
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(
|
|
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
|
|
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 = [];
|
|
@@ -301,8 +324,6 @@ const createAPIResourceTemplate = (serviceName, serviceDefinition, appConfig, pa
|
|
|
301
324
|
accessStrategies,
|
|
302
325
|
),
|
|
303
326
|
];
|
|
304
|
-
|
|
305
|
-
apiResources.push(obj);
|
|
306
327
|
}
|
|
307
328
|
|
|
308
329
|
if (obj.visibility !== RESOURCE_VISIBILITY.private) {
|
|
@@ -330,7 +351,7 @@ const createEventResourceTemplate = (serviceName, serviceDefinition, appConfig,
|
|
|
330
351
|
const ordExtensions = readORDExtensions(serviceDefinition);
|
|
331
352
|
const visibility = _handleVisibility(ordExtensions, serviceDefinition);
|
|
332
353
|
const packageId = _getPackageID(appConfig.ordNamespace, packageIds, ORD_RESOURCE_TYPE.event, visibility);
|
|
333
|
-
const ordId = `${appConfig.ordNamespace}:eventResource:${
|
|
354
|
+
const ordId = `${appConfig.ordNamespace}:eventResource:${_getGroupNameWithNestedNamespace(serviceDefinition, appConfig)}:v1`;
|
|
334
355
|
const entityTypeMappings = _getEntityTypeMappings(serviceDefinition);
|
|
335
356
|
|
|
336
357
|
let obj = {
|
|
@@ -348,7 +369,7 @@ const createEventResourceTemplate = (serviceName, serviceDefinition, appConfig,
|
|
|
348
369
|
lastUpdate: appConfig.lastUpdate,
|
|
349
370
|
releaseStatus: "active",
|
|
350
371
|
partOfPackage: packageId,
|
|
351
|
-
partOfGroups: [_getGroupID(
|
|
372
|
+
partOfGroups: [_getGroupID(serviceDefinition, defaults.groupTypeId, appConfig)],
|
|
352
373
|
visibility,
|
|
353
374
|
resourceDefinitions: [
|
|
354
375
|
_getResourceDefinition("asyncapi-v2", "json", ordId, serviceName, "asyncapi2.json", accessStrategies),
|
|
@@ -363,13 +384,18 @@ const createEventResourceTemplate = (serviceName, serviceDefinition, appConfig,
|
|
|
363
384
|
: [];
|
|
364
385
|
};
|
|
365
386
|
|
|
387
|
+
function isPrimaryDataProductService(serviceDefinition) {
|
|
388
|
+
return serviceDefinition[DATA_PRODUCT_ANNOTATION] === DATA_PRODUCT_TYPE.primary;
|
|
389
|
+
}
|
|
390
|
+
|
|
366
391
|
function _getEntityTypeMappings(definitionObj) {
|
|
367
392
|
if (!definitionObj.entities) {
|
|
368
393
|
return;
|
|
369
394
|
}
|
|
370
|
-
const entities = Object.values(definitionObj.entities)
|
|
371
|
-
|
|
372
|
-
.
|
|
395
|
+
const entities = Object.values(definitionObj.entities).flatMap((entity) => {
|
|
396
|
+
const entityData = _flattenEntityGraph(entity).map(createEntityTypeMappingsItemTemplate);
|
|
397
|
+
return _.uniqBy(entityData, CONTENT_MERGE_KEY);
|
|
398
|
+
});
|
|
373
399
|
const entityTypeTargets = _.uniqBy(entities, CONTENT_MERGE_KEY)
|
|
374
400
|
.filter((entity) => entity !== undefined)
|
|
375
401
|
.map(({ ordId }) => ({
|
|
@@ -396,8 +422,15 @@ function _flattenEntityGraph(currentEntity, processedEntities = []) {
|
|
|
396
422
|
if (processedEntities.includes(target)) {
|
|
397
423
|
return;
|
|
398
424
|
}
|
|
399
|
-
processedEntities = [...processedEntities, target];
|
|
400
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);
|
|
401
434
|
});
|
|
402
435
|
|
|
403
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
|
+
};
|