@kapeta/local-cluster-service 0.60.1 → 0.60.3
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/CHANGELOG.md +14 -0
- package/dist/cjs/src/storm/event-parser.js +69 -6
- package/dist/cjs/test/storm/duplicate-entities-events.json +143 -0
- package/dist/cjs/test/storm/event-parser.test.js +31 -0
- package/dist/esm/src/storm/event-parser.js +69 -6
- package/dist/esm/test/storm/duplicate-entities-events.json +143 -0
- package/dist/esm/test/storm/event-parser.test.js +31 -0
- package/package.json +1 -1
- package/src/storm/event-parser.ts +102 -20
- package/test/storm/duplicate-entities-events.json +143 -0
- package/test/storm/event-parser.test.ts +39 -0
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## [0.60.3](https://github.com/kapetacom/local-cluster-service/compare/v0.60.2...v0.60.3) (2024-08-07)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* rename conflicting entities when creating connections ([a5125cf](https://github.com/kapetacom/local-cluster-service/commit/a5125cf652b808cd94cf3ebe0df853f0c7256566))
|
7
|
+
|
8
|
+
## [0.60.2](https://github.com/kapetacom/local-cluster-service/compare/v0.60.1...v0.60.2) (2024-08-06)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* actually use the new toSafeArtifactName() function ([41f5033](https://github.com/kapetacom/local-cluster-service/commit/41f5033d0a2b2cd21ff6954d2ef3468644ee56c7))
|
14
|
+
|
1
15
|
## [0.60.1](https://github.com/kapetacom/local-cluster-service/compare/v0.60.0...v0.60.1) (2024-08-06)
|
2
16
|
|
3
17
|
|
@@ -313,6 +313,7 @@ class StormEventParser {
|
|
313
313
|
}
|
314
314
|
return;
|
315
315
|
}
|
316
|
+
const renamedEntities = {};
|
316
317
|
if (apiProviderBlock.content.spec.entities?.source?.value) {
|
317
318
|
if (!clientConsumerBlock.content.spec.entities) {
|
318
319
|
clientConsumerBlock.content.spec.entities = {
|
@@ -328,17 +329,79 @@ class StormEventParser {
|
|
328
329
|
const apiTypes = kaplang_core_1.DSLDataTypeParser.parse(apiProviderBlock.content.spec.entities?.source?.value, {
|
329
330
|
ignoreSemantics: true,
|
330
331
|
});
|
332
|
+
const newTypes = [];
|
333
|
+
const clientTypeExists = function (apiType) {
|
334
|
+
const clientType = clientTypes.find((t) => t.name === apiType.name);
|
335
|
+
return clientType != undefined;
|
336
|
+
};
|
337
|
+
const clientTypeIsCompatible = function (apiType) {
|
338
|
+
const clientType = clientTypes.find((t) => t.name === apiType.name);
|
339
|
+
return (clientType != undefined &&
|
340
|
+
kaplang_core_1.DSLCompatibilityHelper.isDataCompatible(apiType, clientType, apiTypes, clientTypes));
|
341
|
+
};
|
331
342
|
apiTypes.forEach((apiType) => {
|
332
|
-
if (
|
333
|
-
|
343
|
+
if (!clientTypeExists(apiType)) {
|
344
|
+
newTypes.push(apiType);
|
345
|
+
return;
|
346
|
+
}
|
347
|
+
if (clientTypeIsCompatible(apiType)) {
|
334
348
|
return;
|
335
349
|
}
|
336
|
-
|
350
|
+
const originalName = apiType.name;
|
351
|
+
const toEntity = lodash_1.default.cloneDeep(apiType);
|
352
|
+
let conflictCount = 1;
|
353
|
+
while (clientTypeExists(toEntity) && !clientTypeIsCompatible(toEntity)) {
|
354
|
+
toEntity.name = `${originalName}_${conflictCount}`;
|
355
|
+
conflictCount++;
|
356
|
+
}
|
357
|
+
newTypes.push(toEntity);
|
358
|
+
renamedEntities[originalName] = toEntity.name;
|
359
|
+
});
|
360
|
+
Object.entries(renamedEntities).forEach(([from, to]) => {
|
361
|
+
newTypes.forEach((newType) => {
|
362
|
+
if (newType.type !== kaplang_core_1.DSLEntityType.DATATYPE) {
|
363
|
+
return;
|
364
|
+
}
|
365
|
+
if (!newType.properties) {
|
366
|
+
return;
|
367
|
+
}
|
368
|
+
newType.properties.forEach((property) => {
|
369
|
+
const type = kaplang_core_1.DSLTypeHelper.asType(property.type);
|
370
|
+
if (from !== type.name) {
|
371
|
+
return;
|
372
|
+
}
|
373
|
+
type.name = to;
|
374
|
+
property.type = type;
|
375
|
+
});
|
376
|
+
});
|
337
377
|
});
|
338
|
-
clientConsumerBlock.content.spec.entities.source.value = kaplang_core_1.KaplangWriter.write(
|
378
|
+
clientConsumerBlock.content.spec.entities.source.value = kaplang_core_1.KaplangWriter.write([
|
379
|
+
...clientTypes,
|
380
|
+
...newTypes,
|
381
|
+
]);
|
339
382
|
}
|
340
383
|
clientResource.spec.methods = apiResource.spec.methods;
|
341
|
-
|
384
|
+
if (Object.keys(renamedEntities).length == 0) {
|
385
|
+
clientResource.spec.source = apiResource.spec.source;
|
386
|
+
}
|
387
|
+
else {
|
388
|
+
// entities were renamed - rename references as well
|
389
|
+
const targetSource = lodash_1.default.cloneDeep(apiResource.spec.source);
|
390
|
+
const methods = kaplang_core_1.DSLAPIParser.parse(targetSource.value, {
|
391
|
+
ignoreSemantics: true,
|
392
|
+
});
|
393
|
+
const resolver = new kaplang_core_1.DSLReferenceResolver();
|
394
|
+
resolver.visitReferences(methods, (name) => {
|
395
|
+
const type = kaplang_core_1.DSLTypeHelper.asType(name);
|
396
|
+
if (renamedEntities[type.name]) {
|
397
|
+
type.name = renamedEntities[type.name];
|
398
|
+
return type;
|
399
|
+
}
|
400
|
+
return name;
|
401
|
+
});
|
402
|
+
targetSource.value = kaplang_core_1.KaplangWriter.write(methods);
|
403
|
+
clientResource.spec.source = targetSource;
|
404
|
+
}
|
342
405
|
});
|
343
406
|
const connections = this.connections.map((connection) => {
|
344
407
|
const fromRef = StormEventParser.toRef(handle, connection.fromComponent);
|
@@ -677,7 +740,7 @@ class StormEventParser {
|
|
677
740
|
let options = {};
|
678
741
|
if (kind.includes('java')) {
|
679
742
|
const groupId = `ai.${StormEventParser.toSafeName(handle)}`;
|
680
|
-
const artifactId = StormEventParser.
|
743
|
+
const artifactId = StormEventParser.toSafeArtifactName(this.planName);
|
681
744
|
options = {
|
682
745
|
groupId,
|
683
746
|
artifactId,
|
@@ -0,0 +1,143 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"type": "CREATE_BLOCK",
|
4
|
+
"reason": "Block updated",
|
5
|
+
"payload": {
|
6
|
+
"archetype": "",
|
7
|
+
"description": "Handles traffic from the backend services.",
|
8
|
+
"name": "api-gateway",
|
9
|
+
"resources": [
|
10
|
+
{
|
11
|
+
"description": "",
|
12
|
+
"name": "posts",
|
13
|
+
"to": "post-service",
|
14
|
+
"type": "CLIENT"
|
15
|
+
},
|
16
|
+
{
|
17
|
+
"description": "",
|
18
|
+
"name": "comments",
|
19
|
+
"to": "comment-service",
|
20
|
+
"type": "CLIENT"
|
21
|
+
}
|
22
|
+
],
|
23
|
+
"type": "GATEWAY",
|
24
|
+
"blockRef": "kapeta://kapeta/api-gateway:local",
|
25
|
+
"instanceId": "6b247f30-dec4-5960-a8a0-f300caa95226"
|
26
|
+
},
|
27
|
+
"created": 1720784242064
|
28
|
+
},
|
29
|
+
{
|
30
|
+
"type": "CREATE_BLOCK",
|
31
|
+
"reason": "Block updated",
|
32
|
+
"payload": {
|
33
|
+
"archetype": "",
|
34
|
+
"description": "Manages the creation, editing, and deletion of blog posts.",
|
35
|
+
"name": "post-service",
|
36
|
+
"resources": [
|
37
|
+
{
|
38
|
+
"description": "The posts API provides endpoints for managing blog posts. It includes functionality for creating, editing, and deleting posts, as well as retrieving and searching for posts. The API is designed to be secure and follows best practices for authentication and authorization.",
|
39
|
+
"name": "posts",
|
40
|
+
"type": "API"
|
41
|
+
}
|
42
|
+
],
|
43
|
+
"type": "BACKEND",
|
44
|
+
"blockRef": "kapeta://kapeta/post-service:local",
|
45
|
+
"instanceId": "4e002962-ca24-5b8b-bcea-395b9bbf7c26"
|
46
|
+
},
|
47
|
+
"created": 1720784243137
|
48
|
+
},
|
49
|
+
{
|
50
|
+
"type": "CREATE_BLOCK",
|
51
|
+
"reason": "Block updated",
|
52
|
+
"payload": {
|
53
|
+
"archetype": "",
|
54
|
+
"description": "Manages the creation, editing, and deletion of comments on blog posts.",
|
55
|
+
"name": "comment-service",
|
56
|
+
"resources": [
|
57
|
+
{
|
58
|
+
"description": "The comments API provides endpoints for managing comments on blog posts. It includes functionality for creating, editing, and deleting comments, as well as retrieving and searching for comments. The API is designed to be secure and follows best practices for authentication and authorization.",
|
59
|
+
"name": "comments",
|
60
|
+
"type": "API"
|
61
|
+
}
|
62
|
+
],
|
63
|
+
"type": "BACKEND",
|
64
|
+
"blockRef": "kapeta://kapeta/comment-service:local",
|
65
|
+
"instanceId": "d4215220-f552-5a6d-9429-bef1c40c4d7c"
|
66
|
+
},
|
67
|
+
"created": 1720784243141
|
68
|
+
},
|
69
|
+
{
|
70
|
+
"type": "CREATE_TYPE",
|
71
|
+
"reason": "Create type for post-service",
|
72
|
+
"payload": {
|
73
|
+
"blockName": "post-service",
|
74
|
+
"content": "enum Status {\n NEW,\n ARCHIVED\n}\n\ntype Result {\n status: Status\n}\n\ntype User {\n id: string\n}",
|
75
|
+
"blockRef": "kapeta://kapeta/post-service:local",
|
76
|
+
"instanceId": "4e002962-ca24-5b8b-bcea-395b9bbf7c26"
|
77
|
+
},
|
78
|
+
"created": 1720784233286
|
79
|
+
},
|
80
|
+
{
|
81
|
+
"type": "CREATE_API",
|
82
|
+
"reason": "Create API for post-service",
|
83
|
+
"payload": {
|
84
|
+
"blockName": "post-service",
|
85
|
+
"content": "@GET(\"/status\")\ngetStatus(): Result",
|
86
|
+
"blockRef": "kapeta://kapeta/post-service:local",
|
87
|
+
"instanceId": "4e002962-ca24-5b8b-bcea-395b9bbf7c26"
|
88
|
+
},
|
89
|
+
"created": 1720784233290
|
90
|
+
},
|
91
|
+
{
|
92
|
+
"type": "CREATE_TYPE",
|
93
|
+
"reason": "Create type for comment-service",
|
94
|
+
"payload": {
|
95
|
+
"blockName": "comment-service",
|
96
|
+
"content": "enum Status {\n NEW,\n APPROVED\n}\n\ntype Result {\n status: Status\n}\n\ntype User {\n id: string\n}",
|
97
|
+
"blockRef": "kapeta://kapeta/comment-service:local",
|
98
|
+
"instanceId": "d4215220-f552-5a6d-9429-bef1c40c4d7c"
|
99
|
+
},
|
100
|
+
"created": 1720784241000
|
101
|
+
},
|
102
|
+
{
|
103
|
+
"type": "CREATE_API",
|
104
|
+
"reason": "Create API for comment-service",
|
105
|
+
"payload": {
|
106
|
+
"blockName": "comment-service",
|
107
|
+
"content": "@GET(\"/status\")\ngetStatus(): Result",
|
108
|
+
"blockRef": "kapeta://kapeta/comment-service:local",
|
109
|
+
"instanceId": "d4215220-f552-5a6d-9429-bef1c40c4d7c"
|
110
|
+
},
|
111
|
+
"created": 1720784241002
|
112
|
+
},
|
113
|
+
{
|
114
|
+
"type": "CREATE_CONNECTION",
|
115
|
+
"reason": "api-gateway needs to be able to serve the posts API from the post-service",
|
116
|
+
"payload": {
|
117
|
+
"fromComponent": "post-service",
|
118
|
+
"fromResource": "posts",
|
119
|
+
"fromResourceType": "API",
|
120
|
+
"toComponent": "api-gateway",
|
121
|
+
"toResource": "posts",
|
122
|
+
"toResourceType": "CLIENT",
|
123
|
+
"fromBlockId": "4e002962-ca24-5b8b-bcea-395b9bbf7c26",
|
124
|
+
"toBlockId": "6b247f30-dec4-5960-a8a0-f300caa95226"
|
125
|
+
},
|
126
|
+
"created": 1720784243173
|
127
|
+
},
|
128
|
+
{
|
129
|
+
"type": "CREATE_CONNECTION",
|
130
|
+
"reason": "api-gateway needs to be able to serve the comments API from the comment-service",
|
131
|
+
"payload": {
|
132
|
+
"fromComponent": "comment-service",
|
133
|
+
"fromResource": "comments",
|
134
|
+
"fromResourceType": "API",
|
135
|
+
"toComponent": "api-gateway",
|
136
|
+
"toResource": "comments",
|
137
|
+
"toResourceType": "CLIENT",
|
138
|
+
"fromBlockId": "d4215220-f552-5a6d-9429-bef1c40c4d7c",
|
139
|
+
"toBlockId": "6b247f30-dec4-5960-a8a0-f300caa95226"
|
140
|
+
},
|
141
|
+
"created": 1720784243174
|
142
|
+
}
|
143
|
+
]
|
@@ -12,6 +12,8 @@ const event_parser_1 = require("../../src/storm/event-parser");
|
|
12
12
|
const simple_blog_events_json_1 = __importDefault(require("./simple-blog-events.json"));
|
13
13
|
const predefined_user_events_json_1 = __importDefault(require("./predefined-user-events.json"));
|
14
14
|
const blog_events_json_1 = __importDefault(require("./blog-events.json"));
|
15
|
+
const duplicate_entities_events_json_1 = __importDefault(require("./duplicate-entities-events.json"));
|
16
|
+
const kaplang_core_1 = require("@kapeta/kaplang-core");
|
15
17
|
exports.parserOptions = {
|
16
18
|
serviceKind: 'kapeta/block-service:local',
|
17
19
|
serviceLanguage: 'kapeta/language-target-java-spring-boot:local',
|
@@ -217,4 +219,33 @@ describe('event-parser', () => {
|
|
217
219
|
const safeName = event_parser_1.StormEventParser.toSafeArtifactName('Browser-based CRM Application');
|
218
220
|
expect(safeName).toBe('browserbasedcrmapplication');
|
219
221
|
});
|
222
|
+
it('rename duplicate entity names', async () => {
|
223
|
+
const events = duplicate_entities_events_json_1.default;
|
224
|
+
const parser = new event_parser_1.StormEventParser(exports.parserOptions);
|
225
|
+
for (const event of events) {
|
226
|
+
await parser.processEvent('kapeta', event);
|
227
|
+
}
|
228
|
+
const result = await parser.toResult('kapeta');
|
229
|
+
const apiGateway = result.blocks.find((block) => block.aiName === 'api-gateway');
|
230
|
+
expect(apiGateway).toBeDefined();
|
231
|
+
const dataTypes = kaplang_core_1.DSLDataTypeParser.parse(apiGateway.content.spec.entities.source.value, {
|
232
|
+
ignoreSemantics: true,
|
233
|
+
});
|
234
|
+
expect(dataTypes.map((type) => type.name)).toStrictEqual(['Status', 'Result', 'User', 'Status_1', 'Result_1']);
|
235
|
+
const conflictingType = dataTypes.find((type) => type.name === 'Result_1');
|
236
|
+
expect(conflictingType).toBeDefined();
|
237
|
+
const dataType = conflictingType;
|
238
|
+
expect(dataType.properties?.length).toBe(1);
|
239
|
+
const dslDataTypeProperty = dataType.properties[0];
|
240
|
+
expect(dslDataTypeProperty.type).toBe('Status_1');
|
241
|
+
const commentsClient = apiGateway?.content.spec.consumers?.find((resource) => resource.metadata.name === 'comments');
|
242
|
+
expect(commentsClient).toBeDefined();
|
243
|
+
const methods = kaplang_core_1.DSLAPIParser.parse(commentsClient.spec.source.value, {
|
244
|
+
ignoreSemantics: true,
|
245
|
+
});
|
246
|
+
expect(methods).toBeDefined();
|
247
|
+
expect(methods.length).toBe(1);
|
248
|
+
const method = methods[0];
|
249
|
+
expect(method.returnType).toBe('Result_1');
|
250
|
+
});
|
220
251
|
});
|
@@ -313,6 +313,7 @@ class StormEventParser {
|
|
313
313
|
}
|
314
314
|
return;
|
315
315
|
}
|
316
|
+
const renamedEntities = {};
|
316
317
|
if (apiProviderBlock.content.spec.entities?.source?.value) {
|
317
318
|
if (!clientConsumerBlock.content.spec.entities) {
|
318
319
|
clientConsumerBlock.content.spec.entities = {
|
@@ -328,17 +329,79 @@ class StormEventParser {
|
|
328
329
|
const apiTypes = kaplang_core_1.DSLDataTypeParser.parse(apiProviderBlock.content.spec.entities?.source?.value, {
|
329
330
|
ignoreSemantics: true,
|
330
331
|
});
|
332
|
+
const newTypes = [];
|
333
|
+
const clientTypeExists = function (apiType) {
|
334
|
+
const clientType = clientTypes.find((t) => t.name === apiType.name);
|
335
|
+
return clientType != undefined;
|
336
|
+
};
|
337
|
+
const clientTypeIsCompatible = function (apiType) {
|
338
|
+
const clientType = clientTypes.find((t) => t.name === apiType.name);
|
339
|
+
return (clientType != undefined &&
|
340
|
+
kaplang_core_1.DSLCompatibilityHelper.isDataCompatible(apiType, clientType, apiTypes, clientTypes));
|
341
|
+
};
|
331
342
|
apiTypes.forEach((apiType) => {
|
332
|
-
if (
|
333
|
-
|
343
|
+
if (!clientTypeExists(apiType)) {
|
344
|
+
newTypes.push(apiType);
|
345
|
+
return;
|
346
|
+
}
|
347
|
+
if (clientTypeIsCompatible(apiType)) {
|
334
348
|
return;
|
335
349
|
}
|
336
|
-
|
350
|
+
const originalName = apiType.name;
|
351
|
+
const toEntity = lodash_1.default.cloneDeep(apiType);
|
352
|
+
let conflictCount = 1;
|
353
|
+
while (clientTypeExists(toEntity) && !clientTypeIsCompatible(toEntity)) {
|
354
|
+
toEntity.name = `${originalName}_${conflictCount}`;
|
355
|
+
conflictCount++;
|
356
|
+
}
|
357
|
+
newTypes.push(toEntity);
|
358
|
+
renamedEntities[originalName] = toEntity.name;
|
359
|
+
});
|
360
|
+
Object.entries(renamedEntities).forEach(([from, to]) => {
|
361
|
+
newTypes.forEach((newType) => {
|
362
|
+
if (newType.type !== kaplang_core_1.DSLEntityType.DATATYPE) {
|
363
|
+
return;
|
364
|
+
}
|
365
|
+
if (!newType.properties) {
|
366
|
+
return;
|
367
|
+
}
|
368
|
+
newType.properties.forEach((property) => {
|
369
|
+
const type = kaplang_core_1.DSLTypeHelper.asType(property.type);
|
370
|
+
if (from !== type.name) {
|
371
|
+
return;
|
372
|
+
}
|
373
|
+
type.name = to;
|
374
|
+
property.type = type;
|
375
|
+
});
|
376
|
+
});
|
337
377
|
});
|
338
|
-
clientConsumerBlock.content.spec.entities.source.value = kaplang_core_1.KaplangWriter.write(
|
378
|
+
clientConsumerBlock.content.spec.entities.source.value = kaplang_core_1.KaplangWriter.write([
|
379
|
+
...clientTypes,
|
380
|
+
...newTypes,
|
381
|
+
]);
|
339
382
|
}
|
340
383
|
clientResource.spec.methods = apiResource.spec.methods;
|
341
|
-
|
384
|
+
if (Object.keys(renamedEntities).length == 0) {
|
385
|
+
clientResource.spec.source = apiResource.spec.source;
|
386
|
+
}
|
387
|
+
else {
|
388
|
+
// entities were renamed - rename references as well
|
389
|
+
const targetSource = lodash_1.default.cloneDeep(apiResource.spec.source);
|
390
|
+
const methods = kaplang_core_1.DSLAPIParser.parse(targetSource.value, {
|
391
|
+
ignoreSemantics: true,
|
392
|
+
});
|
393
|
+
const resolver = new kaplang_core_1.DSLReferenceResolver();
|
394
|
+
resolver.visitReferences(methods, (name) => {
|
395
|
+
const type = kaplang_core_1.DSLTypeHelper.asType(name);
|
396
|
+
if (renamedEntities[type.name]) {
|
397
|
+
type.name = renamedEntities[type.name];
|
398
|
+
return type;
|
399
|
+
}
|
400
|
+
return name;
|
401
|
+
});
|
402
|
+
targetSource.value = kaplang_core_1.KaplangWriter.write(methods);
|
403
|
+
clientResource.spec.source = targetSource;
|
404
|
+
}
|
342
405
|
});
|
343
406
|
const connections = this.connections.map((connection) => {
|
344
407
|
const fromRef = StormEventParser.toRef(handle, connection.fromComponent);
|
@@ -677,7 +740,7 @@ class StormEventParser {
|
|
677
740
|
let options = {};
|
678
741
|
if (kind.includes('java')) {
|
679
742
|
const groupId = `ai.${StormEventParser.toSafeName(handle)}`;
|
680
|
-
const artifactId = StormEventParser.
|
743
|
+
const artifactId = StormEventParser.toSafeArtifactName(this.planName);
|
681
744
|
options = {
|
682
745
|
groupId,
|
683
746
|
artifactId,
|
@@ -0,0 +1,143 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"type": "CREATE_BLOCK",
|
4
|
+
"reason": "Block updated",
|
5
|
+
"payload": {
|
6
|
+
"archetype": "",
|
7
|
+
"description": "Handles traffic from the backend services.",
|
8
|
+
"name": "api-gateway",
|
9
|
+
"resources": [
|
10
|
+
{
|
11
|
+
"description": "",
|
12
|
+
"name": "posts",
|
13
|
+
"to": "post-service",
|
14
|
+
"type": "CLIENT"
|
15
|
+
},
|
16
|
+
{
|
17
|
+
"description": "",
|
18
|
+
"name": "comments",
|
19
|
+
"to": "comment-service",
|
20
|
+
"type": "CLIENT"
|
21
|
+
}
|
22
|
+
],
|
23
|
+
"type": "GATEWAY",
|
24
|
+
"blockRef": "kapeta://kapeta/api-gateway:local",
|
25
|
+
"instanceId": "6b247f30-dec4-5960-a8a0-f300caa95226"
|
26
|
+
},
|
27
|
+
"created": 1720784242064
|
28
|
+
},
|
29
|
+
{
|
30
|
+
"type": "CREATE_BLOCK",
|
31
|
+
"reason": "Block updated",
|
32
|
+
"payload": {
|
33
|
+
"archetype": "",
|
34
|
+
"description": "Manages the creation, editing, and deletion of blog posts.",
|
35
|
+
"name": "post-service",
|
36
|
+
"resources": [
|
37
|
+
{
|
38
|
+
"description": "The posts API provides endpoints for managing blog posts. It includes functionality for creating, editing, and deleting posts, as well as retrieving and searching for posts. The API is designed to be secure and follows best practices for authentication and authorization.",
|
39
|
+
"name": "posts",
|
40
|
+
"type": "API"
|
41
|
+
}
|
42
|
+
],
|
43
|
+
"type": "BACKEND",
|
44
|
+
"blockRef": "kapeta://kapeta/post-service:local",
|
45
|
+
"instanceId": "4e002962-ca24-5b8b-bcea-395b9bbf7c26"
|
46
|
+
},
|
47
|
+
"created": 1720784243137
|
48
|
+
},
|
49
|
+
{
|
50
|
+
"type": "CREATE_BLOCK",
|
51
|
+
"reason": "Block updated",
|
52
|
+
"payload": {
|
53
|
+
"archetype": "",
|
54
|
+
"description": "Manages the creation, editing, and deletion of comments on blog posts.",
|
55
|
+
"name": "comment-service",
|
56
|
+
"resources": [
|
57
|
+
{
|
58
|
+
"description": "The comments API provides endpoints for managing comments on blog posts. It includes functionality for creating, editing, and deleting comments, as well as retrieving and searching for comments. The API is designed to be secure and follows best practices for authentication and authorization.",
|
59
|
+
"name": "comments",
|
60
|
+
"type": "API"
|
61
|
+
}
|
62
|
+
],
|
63
|
+
"type": "BACKEND",
|
64
|
+
"blockRef": "kapeta://kapeta/comment-service:local",
|
65
|
+
"instanceId": "d4215220-f552-5a6d-9429-bef1c40c4d7c"
|
66
|
+
},
|
67
|
+
"created": 1720784243141
|
68
|
+
},
|
69
|
+
{
|
70
|
+
"type": "CREATE_TYPE",
|
71
|
+
"reason": "Create type for post-service",
|
72
|
+
"payload": {
|
73
|
+
"blockName": "post-service",
|
74
|
+
"content": "enum Status {\n NEW,\n ARCHIVED\n}\n\ntype Result {\n status: Status\n}\n\ntype User {\n id: string\n}",
|
75
|
+
"blockRef": "kapeta://kapeta/post-service:local",
|
76
|
+
"instanceId": "4e002962-ca24-5b8b-bcea-395b9bbf7c26"
|
77
|
+
},
|
78
|
+
"created": 1720784233286
|
79
|
+
},
|
80
|
+
{
|
81
|
+
"type": "CREATE_API",
|
82
|
+
"reason": "Create API for post-service",
|
83
|
+
"payload": {
|
84
|
+
"blockName": "post-service",
|
85
|
+
"content": "@GET(\"/status\")\ngetStatus(): Result",
|
86
|
+
"blockRef": "kapeta://kapeta/post-service:local",
|
87
|
+
"instanceId": "4e002962-ca24-5b8b-bcea-395b9bbf7c26"
|
88
|
+
},
|
89
|
+
"created": 1720784233290
|
90
|
+
},
|
91
|
+
{
|
92
|
+
"type": "CREATE_TYPE",
|
93
|
+
"reason": "Create type for comment-service",
|
94
|
+
"payload": {
|
95
|
+
"blockName": "comment-service",
|
96
|
+
"content": "enum Status {\n NEW,\n APPROVED\n}\n\ntype Result {\n status: Status\n}\n\ntype User {\n id: string\n}",
|
97
|
+
"blockRef": "kapeta://kapeta/comment-service:local",
|
98
|
+
"instanceId": "d4215220-f552-5a6d-9429-bef1c40c4d7c"
|
99
|
+
},
|
100
|
+
"created": 1720784241000
|
101
|
+
},
|
102
|
+
{
|
103
|
+
"type": "CREATE_API",
|
104
|
+
"reason": "Create API for comment-service",
|
105
|
+
"payload": {
|
106
|
+
"blockName": "comment-service",
|
107
|
+
"content": "@GET(\"/status\")\ngetStatus(): Result",
|
108
|
+
"blockRef": "kapeta://kapeta/comment-service:local",
|
109
|
+
"instanceId": "d4215220-f552-5a6d-9429-bef1c40c4d7c"
|
110
|
+
},
|
111
|
+
"created": 1720784241002
|
112
|
+
},
|
113
|
+
{
|
114
|
+
"type": "CREATE_CONNECTION",
|
115
|
+
"reason": "api-gateway needs to be able to serve the posts API from the post-service",
|
116
|
+
"payload": {
|
117
|
+
"fromComponent": "post-service",
|
118
|
+
"fromResource": "posts",
|
119
|
+
"fromResourceType": "API",
|
120
|
+
"toComponent": "api-gateway",
|
121
|
+
"toResource": "posts",
|
122
|
+
"toResourceType": "CLIENT",
|
123
|
+
"fromBlockId": "4e002962-ca24-5b8b-bcea-395b9bbf7c26",
|
124
|
+
"toBlockId": "6b247f30-dec4-5960-a8a0-f300caa95226"
|
125
|
+
},
|
126
|
+
"created": 1720784243173
|
127
|
+
},
|
128
|
+
{
|
129
|
+
"type": "CREATE_CONNECTION",
|
130
|
+
"reason": "api-gateway needs to be able to serve the comments API from the comment-service",
|
131
|
+
"payload": {
|
132
|
+
"fromComponent": "comment-service",
|
133
|
+
"fromResource": "comments",
|
134
|
+
"fromResourceType": "API",
|
135
|
+
"toComponent": "api-gateway",
|
136
|
+
"toResource": "comments",
|
137
|
+
"toResourceType": "CLIENT",
|
138
|
+
"fromBlockId": "d4215220-f552-5a6d-9429-bef1c40c4d7c",
|
139
|
+
"toBlockId": "6b247f30-dec4-5960-a8a0-f300caa95226"
|
140
|
+
},
|
141
|
+
"created": 1720784243174
|
142
|
+
}
|
143
|
+
]
|
@@ -12,6 +12,8 @@ const event_parser_1 = require("../../src/storm/event-parser");
|
|
12
12
|
const simple_blog_events_json_1 = __importDefault(require("./simple-blog-events.json"));
|
13
13
|
const predefined_user_events_json_1 = __importDefault(require("./predefined-user-events.json"));
|
14
14
|
const blog_events_json_1 = __importDefault(require("./blog-events.json"));
|
15
|
+
const duplicate_entities_events_json_1 = __importDefault(require("./duplicate-entities-events.json"));
|
16
|
+
const kaplang_core_1 = require("@kapeta/kaplang-core");
|
15
17
|
exports.parserOptions = {
|
16
18
|
serviceKind: 'kapeta/block-service:local',
|
17
19
|
serviceLanguage: 'kapeta/language-target-java-spring-boot:local',
|
@@ -217,4 +219,33 @@ describe('event-parser', () => {
|
|
217
219
|
const safeName = event_parser_1.StormEventParser.toSafeArtifactName('Browser-based CRM Application');
|
218
220
|
expect(safeName).toBe('browserbasedcrmapplication');
|
219
221
|
});
|
222
|
+
it('rename duplicate entity names', async () => {
|
223
|
+
const events = duplicate_entities_events_json_1.default;
|
224
|
+
const parser = new event_parser_1.StormEventParser(exports.parserOptions);
|
225
|
+
for (const event of events) {
|
226
|
+
await parser.processEvent('kapeta', event);
|
227
|
+
}
|
228
|
+
const result = await parser.toResult('kapeta');
|
229
|
+
const apiGateway = result.blocks.find((block) => block.aiName === 'api-gateway');
|
230
|
+
expect(apiGateway).toBeDefined();
|
231
|
+
const dataTypes = kaplang_core_1.DSLDataTypeParser.parse(apiGateway.content.spec.entities.source.value, {
|
232
|
+
ignoreSemantics: true,
|
233
|
+
});
|
234
|
+
expect(dataTypes.map((type) => type.name)).toStrictEqual(['Status', 'Result', 'User', 'Status_1', 'Result_1']);
|
235
|
+
const conflictingType = dataTypes.find((type) => type.name === 'Result_1');
|
236
|
+
expect(conflictingType).toBeDefined();
|
237
|
+
const dataType = conflictingType;
|
238
|
+
expect(dataType.properties?.length).toBe(1);
|
239
|
+
const dslDataTypeProperty = dataType.properties[0];
|
240
|
+
expect(dslDataTypeProperty.type).toBe('Status_1');
|
241
|
+
const commentsClient = apiGateway?.content.spec.consumers?.find((resource) => resource.metadata.name === 'comments');
|
242
|
+
expect(commentsClient).toBeDefined();
|
243
|
+
const methods = kaplang_core_1.DSLAPIParser.parse(commentsClient.spec.source.value, {
|
244
|
+
ignoreSemantics: true,
|
245
|
+
});
|
246
|
+
expect(methods).toBeDefined();
|
247
|
+
expect(methods.length).toBe(1);
|
248
|
+
const method = methods[0];
|
249
|
+
expect(method.returnType).toBe('Result_1');
|
250
|
+
});
|
220
251
|
});
|
package/package.json
CHANGED
@@ -24,12 +24,16 @@ import {
|
|
24
24
|
import { KapetaURI, normalizeKapetaUri, parseKapetaUri } from '@kapeta/nodejs-utils';
|
25
25
|
import {
|
26
26
|
DSLAPIParser,
|
27
|
+
DSLCompatibilityHelper,
|
27
28
|
DSLController,
|
28
29
|
DSLConverters,
|
30
|
+
DSLData,
|
29
31
|
DSLDataTypeParser,
|
30
32
|
DSLEntityType,
|
31
33
|
DSLMethod,
|
32
34
|
DSLParser,
|
35
|
+
DSLReferenceResolver,
|
36
|
+
DSLTypeHelper,
|
33
37
|
KAPLANG_ID,
|
34
38
|
KAPLANG_VERSION,
|
35
39
|
KaplangWriter,
|
@@ -413,13 +417,11 @@ export class StormEventParser {
|
|
413
417
|
return;
|
414
418
|
}
|
415
419
|
|
416
|
-
const apiResource = apiProviderBlock.content.spec.providers?.find(
|
417
|
-
(p)
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
}
|
422
|
-
);
|
420
|
+
const apiResource = apiProviderBlock.content.spec.providers?.find((p) => {
|
421
|
+
const pKind = normalizeKapetaUri(p.kind);
|
422
|
+
const apiKind = normalizeKapetaUri(this.options.apiKind);
|
423
|
+
return pKind === apiKind && p.metadata.name === apiConnection.fromResource;
|
424
|
+
});
|
423
425
|
|
424
426
|
if (!apiResource) {
|
425
427
|
if (warn) {
|
@@ -454,6 +456,8 @@ export class StormEventParser {
|
|
454
456
|
return;
|
455
457
|
}
|
456
458
|
|
459
|
+
const renamedEntities: { [from: string]: string } = {};
|
460
|
+
|
457
461
|
if (apiProviderBlock.content.spec.entities?.source?.value) {
|
458
462
|
if (!clientConsumerBlock.content.spec.entities) {
|
459
463
|
clientConsumerBlock.content.spec.entities = {
|
@@ -473,19 +477,99 @@ export class StormEventParser {
|
|
473
477
|
const apiTypes = DSLDataTypeParser.parse(apiProviderBlock.content.spec.entities?.source?.value, {
|
474
478
|
ignoreSemantics: true,
|
475
479
|
});
|
480
|
+
const newTypes: DSLData[] = [];
|
481
|
+
|
482
|
+
const clientTypeExists = function (apiType: DSLData): boolean {
|
483
|
+
const clientType = clientTypes.find((t) => t.name === apiType.name);
|
484
|
+
return clientType != undefined;
|
485
|
+
};
|
486
|
+
|
487
|
+
const clientTypeIsCompatible = function (apiType: DSLData): boolean {
|
488
|
+
const clientType = clientTypes.find((t) => t.name === apiType.name);
|
489
|
+
return (
|
490
|
+
clientType != undefined &&
|
491
|
+
DSLCompatibilityHelper.isDataCompatible(apiType, clientType, apiTypes, clientTypes)
|
492
|
+
);
|
493
|
+
};
|
476
494
|
|
477
495
|
apiTypes.forEach((apiType) => {
|
478
|
-
if (
|
479
|
-
|
496
|
+
if (!clientTypeExists(apiType)) {
|
497
|
+
newTypes.push(apiType);
|
480
498
|
return;
|
481
499
|
}
|
482
|
-
|
500
|
+
|
501
|
+
if (clientTypeIsCompatible(apiType)) {
|
502
|
+
return;
|
503
|
+
}
|
504
|
+
|
505
|
+
const originalName = apiType.name;
|
506
|
+
const toEntity = _.cloneDeep(apiType);
|
507
|
+
let conflictCount = 1;
|
508
|
+
|
509
|
+
while (clientTypeExists(toEntity) && !clientTypeIsCompatible(toEntity)) {
|
510
|
+
toEntity.name = `${originalName}_${conflictCount}`;
|
511
|
+
conflictCount++;
|
512
|
+
}
|
513
|
+
|
514
|
+
newTypes.push(toEntity);
|
515
|
+
renamedEntities[originalName] = toEntity.name;
|
516
|
+
});
|
517
|
+
|
518
|
+
Object.entries(renamedEntities).forEach(([from, to]) => {
|
519
|
+
newTypes.forEach((newType) => {
|
520
|
+
if (newType.type !== DSLEntityType.DATATYPE) {
|
521
|
+
return;
|
522
|
+
}
|
523
|
+
|
524
|
+
if (!newType.properties) {
|
525
|
+
return;
|
526
|
+
}
|
527
|
+
|
528
|
+
newType.properties.forEach((property) => {
|
529
|
+
const type = DSLTypeHelper.asType(property.type);
|
530
|
+
|
531
|
+
if (from !== type.name) {
|
532
|
+
return;
|
533
|
+
}
|
534
|
+
|
535
|
+
type.name = to;
|
536
|
+
property.type = type;
|
537
|
+
});
|
538
|
+
});
|
483
539
|
});
|
484
540
|
|
485
|
-
clientConsumerBlock.content.spec.entities.source!.value = KaplangWriter.write(
|
541
|
+
clientConsumerBlock.content.spec.entities.source!.value = KaplangWriter.write([
|
542
|
+
...clientTypes,
|
543
|
+
...newTypes,
|
544
|
+
]);
|
486
545
|
}
|
546
|
+
|
487
547
|
clientResource.spec.methods = apiResource.spec.methods;
|
488
|
-
|
548
|
+
|
549
|
+
if (Object.keys(renamedEntities).length == 0) {
|
550
|
+
clientResource.spec.source = apiResource.spec.source;
|
551
|
+
} else {
|
552
|
+
// entities were renamed - rename references as well
|
553
|
+
const targetSource = _.cloneDeep(apiResource.spec.source);
|
554
|
+
const methods = DSLAPIParser.parse(targetSource.value, {
|
555
|
+
ignoreSemantics: true,
|
556
|
+
});
|
557
|
+
|
558
|
+
const resolver = new DSLReferenceResolver();
|
559
|
+
resolver.visitReferences(methods, (name) => {
|
560
|
+
const type = DSLTypeHelper.asType(name);
|
561
|
+
|
562
|
+
if (renamedEntities[type.name]) {
|
563
|
+
type.name = renamedEntities[type.name];
|
564
|
+
return type;
|
565
|
+
}
|
566
|
+
|
567
|
+
return name;
|
568
|
+
});
|
569
|
+
|
570
|
+
targetSource.value = KaplangWriter.write(methods);
|
571
|
+
clientResource.spec.source = targetSource;
|
572
|
+
}
|
489
573
|
});
|
490
574
|
|
491
575
|
const connections: Connection[] = this.connections.map((connection) => {
|
@@ -802,13 +886,11 @@ export class StormEventParser {
|
|
802
886
|
return;
|
803
887
|
}
|
804
888
|
|
805
|
-
const apiResource = apiProviderBlock.content.spec.providers?.find(
|
806
|
-
(p)
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
}
|
811
|
-
);
|
889
|
+
const apiResource = apiProviderBlock.content.spec.providers?.find((p) => {
|
890
|
+
const pKind = normalizeKapetaUri(p.kind);
|
891
|
+
const apiKind = normalizeKapetaUri(this.options.apiKind);
|
892
|
+
return pKind === apiKind && p.metadata.name === connection.fromResource;
|
893
|
+
});
|
812
894
|
|
813
895
|
if (!apiResource) {
|
814
896
|
if (warn) {
|
@@ -882,7 +964,7 @@ export class StormEventParser {
|
|
882
964
|
|
883
965
|
if (kind.includes('java')) {
|
884
966
|
const groupId = `ai.${StormEventParser.toSafeName(handle)}`;
|
885
|
-
const artifactId = StormEventParser.
|
967
|
+
const artifactId = StormEventParser.toSafeArtifactName(this.planName);
|
886
968
|
options = {
|
887
969
|
groupId,
|
888
970
|
artifactId,
|
@@ -0,0 +1,143 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"type": "CREATE_BLOCK",
|
4
|
+
"reason": "Block updated",
|
5
|
+
"payload": {
|
6
|
+
"archetype": "",
|
7
|
+
"description": "Handles traffic from the backend services.",
|
8
|
+
"name": "api-gateway",
|
9
|
+
"resources": [
|
10
|
+
{
|
11
|
+
"description": "",
|
12
|
+
"name": "posts",
|
13
|
+
"to": "post-service",
|
14
|
+
"type": "CLIENT"
|
15
|
+
},
|
16
|
+
{
|
17
|
+
"description": "",
|
18
|
+
"name": "comments",
|
19
|
+
"to": "comment-service",
|
20
|
+
"type": "CLIENT"
|
21
|
+
}
|
22
|
+
],
|
23
|
+
"type": "GATEWAY",
|
24
|
+
"blockRef": "kapeta://kapeta/api-gateway:local",
|
25
|
+
"instanceId": "6b247f30-dec4-5960-a8a0-f300caa95226"
|
26
|
+
},
|
27
|
+
"created": 1720784242064
|
28
|
+
},
|
29
|
+
{
|
30
|
+
"type": "CREATE_BLOCK",
|
31
|
+
"reason": "Block updated",
|
32
|
+
"payload": {
|
33
|
+
"archetype": "",
|
34
|
+
"description": "Manages the creation, editing, and deletion of blog posts.",
|
35
|
+
"name": "post-service",
|
36
|
+
"resources": [
|
37
|
+
{
|
38
|
+
"description": "The posts API provides endpoints for managing blog posts. It includes functionality for creating, editing, and deleting posts, as well as retrieving and searching for posts. The API is designed to be secure and follows best practices for authentication and authorization.",
|
39
|
+
"name": "posts",
|
40
|
+
"type": "API"
|
41
|
+
}
|
42
|
+
],
|
43
|
+
"type": "BACKEND",
|
44
|
+
"blockRef": "kapeta://kapeta/post-service:local",
|
45
|
+
"instanceId": "4e002962-ca24-5b8b-bcea-395b9bbf7c26"
|
46
|
+
},
|
47
|
+
"created": 1720784243137
|
48
|
+
},
|
49
|
+
{
|
50
|
+
"type": "CREATE_BLOCK",
|
51
|
+
"reason": "Block updated",
|
52
|
+
"payload": {
|
53
|
+
"archetype": "",
|
54
|
+
"description": "Manages the creation, editing, and deletion of comments on blog posts.",
|
55
|
+
"name": "comment-service",
|
56
|
+
"resources": [
|
57
|
+
{
|
58
|
+
"description": "The comments API provides endpoints for managing comments on blog posts. It includes functionality for creating, editing, and deleting comments, as well as retrieving and searching for comments. The API is designed to be secure and follows best practices for authentication and authorization.",
|
59
|
+
"name": "comments",
|
60
|
+
"type": "API"
|
61
|
+
}
|
62
|
+
],
|
63
|
+
"type": "BACKEND",
|
64
|
+
"blockRef": "kapeta://kapeta/comment-service:local",
|
65
|
+
"instanceId": "d4215220-f552-5a6d-9429-bef1c40c4d7c"
|
66
|
+
},
|
67
|
+
"created": 1720784243141
|
68
|
+
},
|
69
|
+
{
|
70
|
+
"type": "CREATE_TYPE",
|
71
|
+
"reason": "Create type for post-service",
|
72
|
+
"payload": {
|
73
|
+
"blockName": "post-service",
|
74
|
+
"content": "enum Status {\n NEW,\n ARCHIVED\n}\n\ntype Result {\n status: Status\n}\n\ntype User {\n id: string\n}",
|
75
|
+
"blockRef": "kapeta://kapeta/post-service:local",
|
76
|
+
"instanceId": "4e002962-ca24-5b8b-bcea-395b9bbf7c26"
|
77
|
+
},
|
78
|
+
"created": 1720784233286
|
79
|
+
},
|
80
|
+
{
|
81
|
+
"type": "CREATE_API",
|
82
|
+
"reason": "Create API for post-service",
|
83
|
+
"payload": {
|
84
|
+
"blockName": "post-service",
|
85
|
+
"content": "@GET(\"/status\")\ngetStatus(): Result",
|
86
|
+
"blockRef": "kapeta://kapeta/post-service:local",
|
87
|
+
"instanceId": "4e002962-ca24-5b8b-bcea-395b9bbf7c26"
|
88
|
+
},
|
89
|
+
"created": 1720784233290
|
90
|
+
},
|
91
|
+
{
|
92
|
+
"type": "CREATE_TYPE",
|
93
|
+
"reason": "Create type for comment-service",
|
94
|
+
"payload": {
|
95
|
+
"blockName": "comment-service",
|
96
|
+
"content": "enum Status {\n NEW,\n APPROVED\n}\n\ntype Result {\n status: Status\n}\n\ntype User {\n id: string\n}",
|
97
|
+
"blockRef": "kapeta://kapeta/comment-service:local",
|
98
|
+
"instanceId": "d4215220-f552-5a6d-9429-bef1c40c4d7c"
|
99
|
+
},
|
100
|
+
"created": 1720784241000
|
101
|
+
},
|
102
|
+
{
|
103
|
+
"type": "CREATE_API",
|
104
|
+
"reason": "Create API for comment-service",
|
105
|
+
"payload": {
|
106
|
+
"blockName": "comment-service",
|
107
|
+
"content": "@GET(\"/status\")\ngetStatus(): Result",
|
108
|
+
"blockRef": "kapeta://kapeta/comment-service:local",
|
109
|
+
"instanceId": "d4215220-f552-5a6d-9429-bef1c40c4d7c"
|
110
|
+
},
|
111
|
+
"created": 1720784241002
|
112
|
+
},
|
113
|
+
{
|
114
|
+
"type": "CREATE_CONNECTION",
|
115
|
+
"reason": "api-gateway needs to be able to serve the posts API from the post-service",
|
116
|
+
"payload": {
|
117
|
+
"fromComponent": "post-service",
|
118
|
+
"fromResource": "posts",
|
119
|
+
"fromResourceType": "API",
|
120
|
+
"toComponent": "api-gateway",
|
121
|
+
"toResource": "posts",
|
122
|
+
"toResourceType": "CLIENT",
|
123
|
+
"fromBlockId": "4e002962-ca24-5b8b-bcea-395b9bbf7c26",
|
124
|
+
"toBlockId": "6b247f30-dec4-5960-a8a0-f300caa95226"
|
125
|
+
},
|
126
|
+
"created": 1720784243173
|
127
|
+
},
|
128
|
+
{
|
129
|
+
"type": "CREATE_CONNECTION",
|
130
|
+
"reason": "api-gateway needs to be able to serve the comments API from the comment-service",
|
131
|
+
"payload": {
|
132
|
+
"fromComponent": "comment-service",
|
133
|
+
"fromResource": "comments",
|
134
|
+
"fromResourceType": "API",
|
135
|
+
"toComponent": "api-gateway",
|
136
|
+
"toResource": "comments",
|
137
|
+
"toResourceType": "CLIENT",
|
138
|
+
"fromBlockId": "d4215220-f552-5a6d-9429-bef1c40c4d7c",
|
139
|
+
"toBlockId": "6b247f30-dec4-5960-a8a0-f300caa95226"
|
140
|
+
},
|
141
|
+
"created": 1720784243174
|
142
|
+
}
|
143
|
+
]
|
@@ -8,6 +8,8 @@ import { StormEvent } from '../../src/storm/events';
|
|
8
8
|
import simpleBlogEvents from './simple-blog-events.json';
|
9
9
|
import predefinedUserEvents from './predefined-user-events.json';
|
10
10
|
import testEvents from './blog-events.json';
|
11
|
+
import duplicateEntitiesEvents from './duplicate-entities-events.json';
|
12
|
+
import { DSLAPIParser, DSLDataType, DSLDataTypeParser, DSLMethod } from '@kapeta/kaplang-core';
|
11
13
|
|
12
14
|
export const parserOptions = {
|
13
15
|
serviceKind: 'kapeta/block-service:local',
|
@@ -245,4 +247,41 @@ describe('event-parser', () => {
|
|
245
247
|
const safeName = StormEventParser.toSafeArtifactName('Browser-based CRM Application');
|
246
248
|
expect(safeName).toBe('browserbasedcrmapplication');
|
247
249
|
});
|
250
|
+
|
251
|
+
it('rename duplicate entity names', async () => {
|
252
|
+
const events = duplicateEntitiesEvents as StormEvent[];
|
253
|
+
const parser = new StormEventParser(parserOptions);
|
254
|
+
for (const event of events) {
|
255
|
+
await parser.processEvent('kapeta', event);
|
256
|
+
}
|
257
|
+
|
258
|
+
const result = await parser.toResult('kapeta');
|
259
|
+
const apiGateway = result.blocks.find((block) => block.aiName === 'api-gateway');
|
260
|
+
expect(apiGateway).toBeDefined();
|
261
|
+
|
262
|
+
const dataTypes = DSLDataTypeParser.parse(apiGateway!.content!.spec!.entities!.source!.value, {
|
263
|
+
ignoreSemantics: true,
|
264
|
+
});
|
265
|
+
expect(dataTypes.map((type) => type.name)).toStrictEqual(['Status', 'Result', 'User', 'Status_1', 'Result_1']);
|
266
|
+
|
267
|
+
const conflictingType = dataTypes.find((type) => type.name === 'Result_1');
|
268
|
+
expect(conflictingType).toBeDefined();
|
269
|
+
const dataType = conflictingType as DSLDataType;
|
270
|
+
expect(dataType.properties?.length).toBe(1);
|
271
|
+
const dslDataTypeProperty = dataType.properties![0];
|
272
|
+
expect(dslDataTypeProperty.type).toBe('Status_1');
|
273
|
+
|
274
|
+
const commentsClient = apiGateway?.content!.spec!.consumers?.find(
|
275
|
+
(resource) => resource.metadata.name === 'comments'
|
276
|
+
);
|
277
|
+
expect(commentsClient).toBeDefined();
|
278
|
+
|
279
|
+
const methods = DSLAPIParser.parse(commentsClient!.spec!.source!.value, {
|
280
|
+
ignoreSemantics: true,
|
281
|
+
});
|
282
|
+
expect(methods).toBeDefined();
|
283
|
+
expect(methods.length).toBe(1);
|
284
|
+
const method = methods[0] as DSLMethod;
|
285
|
+
expect(method.returnType).toBe('Result_1');
|
286
|
+
});
|
248
287
|
});
|