@kapeta/local-cluster-service 0.44.0 → 0.45.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/CHANGELOG.md +7 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/src/codeGeneratorManager.d.ts +1 -0
- package/dist/cjs/src/codeGeneratorManager.js +12 -6
- package/dist/cjs/src/middleware/cors.d.ts +1 -0
- package/dist/cjs/src/middleware/kapeta.d.ts +1 -0
- package/dist/cjs/src/middleware/stringBody.d.ts +1 -0
- package/dist/cjs/src/storm/codegen.d.ts +36 -0
- package/dist/cjs/src/storm/codegen.js +160 -0
- package/dist/cjs/src/storm/event-parser.d.ts +70 -0
- package/dist/cjs/src/storm/event-parser.js +543 -0
- package/dist/cjs/src/storm/events.d.ts +127 -0
- package/dist/cjs/src/storm/events.js +6 -0
- package/dist/cjs/src/storm/routes.d.ts +7 -0
- package/dist/cjs/src/storm/routes.js +109 -0
- package/dist/cjs/src/storm/stormClient.d.ts +13 -0
- package/dist/cjs/src/storm/stormClient.js +87 -0
- package/dist/cjs/src/storm/stream.d.ts +38 -0
- package/dist/cjs/src/storm/stream.js +57 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/src/codeGeneratorManager.d.ts +1 -0
- package/dist/esm/src/codeGeneratorManager.js +12 -6
- package/dist/esm/src/middleware/cors.d.ts +1 -0
- package/dist/esm/src/middleware/kapeta.d.ts +1 -0
- package/dist/esm/src/middleware/stringBody.d.ts +1 -0
- package/dist/esm/src/storm/codegen.d.ts +36 -0
- package/dist/esm/src/storm/codegen.js +160 -0
- package/dist/esm/src/storm/event-parser.d.ts +70 -0
- package/dist/esm/src/storm/event-parser.js +543 -0
- package/dist/esm/src/storm/events.d.ts +127 -0
- package/dist/esm/src/storm/events.js +6 -0
- package/dist/esm/src/storm/routes.d.ts +7 -0
- package/dist/esm/src/storm/routes.js +109 -0
- package/dist/esm/src/storm/stormClient.d.ts +13 -0
- package/dist/esm/src/storm/stormClient.js +87 -0
- package/dist/esm/src/storm/stream.d.ts +38 -0
- package/dist/esm/src/storm/stream.js +57 -0
- package/index.ts +2 -0
- package/package.json +3 -3
- package/src/codeGeneratorManager.ts +17 -8
- package/src/storm/codegen.ts +210 -0
- package/src/storm/event-parser.ts +688 -0
- package/src/storm/events.ts +169 -0
- package/src/storm/routes.ts +143 -0
- package/src/storm/stormClient.ts +114 -0
- package/src/storm/stream.ts +88 -0
- package/src/utils/BlockInstanceRunner.ts +4 -2
@@ -0,0 +1,688 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright 2023 Kapeta Inc.
|
3
|
+
* SPDX-License-Identifier: BUSL-1.1
|
4
|
+
*/
|
5
|
+
|
6
|
+
import {
|
7
|
+
ScreenTemplate,
|
8
|
+
StormBlockInfoFilled,
|
9
|
+
StormBlockType,
|
10
|
+
StormConnection,
|
11
|
+
StormEvent,
|
12
|
+
StormResourceType,
|
13
|
+
} from './events';
|
14
|
+
import {
|
15
|
+
BlockDefinition,
|
16
|
+
BlockInstance,
|
17
|
+
Connection,
|
18
|
+
LanguageTargetReference,
|
19
|
+
Plan,
|
20
|
+
Resource,
|
21
|
+
SourceCode,
|
22
|
+
} from '@kapeta/schemas';
|
23
|
+
import { KapetaURI, normalizeKapetaUri, parseKapetaUri } from '@kapeta/nodejs-utils';
|
24
|
+
import { KAPLANG_ID, KAPLANG_VERSION, RESTMethod } from '@kapeta/kaplang-core';
|
25
|
+
import uuid from 'node-uuid';
|
26
|
+
import { definitionsManager } from '../definitionsManager';
|
27
|
+
|
28
|
+
export interface BlockDefinitionInfo {
|
29
|
+
uri: KapetaURI;
|
30
|
+
content: BlockDefinition;
|
31
|
+
screens: ScreenTemplate[];
|
32
|
+
}
|
33
|
+
|
34
|
+
export interface ParsedResult {
|
35
|
+
plan: Plan;
|
36
|
+
blocks: BlockDefinitionInfo[];
|
37
|
+
}
|
38
|
+
|
39
|
+
export interface StormOptions {
|
40
|
+
databaseKind: string;
|
41
|
+
apiKind: string;
|
42
|
+
clientKind: string;
|
43
|
+
webPageKind: string;
|
44
|
+
webFragmentKind: string;
|
45
|
+
mqKind: string;
|
46
|
+
serviceKind: string;
|
47
|
+
serviceLanguage: string;
|
48
|
+
frontendKind: string;
|
49
|
+
frontendLanguage: string;
|
50
|
+
exchangeKind: string;
|
51
|
+
queueKind: string;
|
52
|
+
publisherKind: string;
|
53
|
+
subscriberKind: string;
|
54
|
+
jwtProviderKind: string;
|
55
|
+
jwtConsumerKind: string;
|
56
|
+
smtpKind: string;
|
57
|
+
externalApiKind: string;
|
58
|
+
cliKind: string;
|
59
|
+
cliLanguage: string;
|
60
|
+
desktopKind: string;
|
61
|
+
desktopLanguage: string;
|
62
|
+
gatewayKind: string;
|
63
|
+
}
|
64
|
+
|
65
|
+
export async function resolveOptions(): Promise<StormOptions> {
|
66
|
+
// Predefined types for now - TODO: Allow user to select / change
|
67
|
+
|
68
|
+
const blockTypeService = await definitionsManager.getLatestDefinition('kapeta/block-type-service');
|
69
|
+
const blockTypeFrontend = await definitionsManager.getLatestDefinition('kapeta/block-type-frontend');
|
70
|
+
const blockTypeDesktop = await definitionsManager.getLatestDefinition('kapeta/block-type-desktop');
|
71
|
+
const blockTypeCli = await definitionsManager.getLatestDefinition('kapeta/block-type-cli');
|
72
|
+
const blockTypeGateway = await definitionsManager.getLatestDefinition('kapeta/block-type-gateway-http');
|
73
|
+
|
74
|
+
const postgresResource = await definitionsManager.getLatestDefinition('kapeta/resource-type-postgresql');
|
75
|
+
|
76
|
+
const webPageResource = await definitionsManager.getLatestDefinition('kapeta/resource-type-web-page');
|
77
|
+
const webFragmentResource = await definitionsManager.getLatestDefinition('kapeta/resource-type-web-fragment');
|
78
|
+
|
79
|
+
const restApiResource = await definitionsManager.getLatestDefinition('kapeta/resource-type-rest-api');
|
80
|
+
const restClientResource = await definitionsManager.getLatestDefinition('kapeta/resource-type-rest-client');
|
81
|
+
|
82
|
+
const javaLanguage = await definitionsManager.getLatestDefinition('kapeta/language-target-java-spring-boot');
|
83
|
+
const reactLanguage = await definitionsManager.getLatestDefinition('kapeta/language-target-react-ts');
|
84
|
+
const nodejsLanguage = await definitionsManager.getLatestDefinition('kapeta/language-target-nodejs');
|
85
|
+
|
86
|
+
const blockTypePubsub = await definitionsManager.getLatestDefinition('kapeta/block-type-pubsub');
|
87
|
+
const resourceTypePubsubSubscriber = await definitionsManager.getLatestDefinition(
|
88
|
+
'kapeta/resource-type-pubsub-subscriber'
|
89
|
+
);
|
90
|
+
const resourceTypePubsubSubscription = await definitionsManager.getLatestDefinition(
|
91
|
+
'kapeta/resource-type-pubsub-subscription'
|
92
|
+
);
|
93
|
+
const resourceTypePubsubTopic = await definitionsManager.getLatestDefinition('kapeta/resource-type-pubsub-topic');
|
94
|
+
const resourceTypePubsubPublisher = await definitionsManager.getLatestDefinition(
|
95
|
+
'kapeta/resource-type-pubsub-publisher'
|
96
|
+
);
|
97
|
+
|
98
|
+
const jwtProvider = await definitionsManager.getLatestDefinition('kapeta/resource-type-auth-jwt-provider');
|
99
|
+
const jwtConsumer = await definitionsManager.getLatestDefinition('kapeta/resource-type-auth-jwt-consumer');
|
100
|
+
|
101
|
+
const smtpClient = await definitionsManager.getLatestDefinition('kapeta/resource-type-smtp-client');
|
102
|
+
const externalService = await definitionsManager.getLatestDefinition('kapeta/resource-type-external-services');
|
103
|
+
|
104
|
+
if (
|
105
|
+
!blockTypeService ||
|
106
|
+
!blockTypeFrontend ||
|
107
|
+
!blockTypeDesktop ||
|
108
|
+
!blockTypeGateway ||
|
109
|
+
!postgresResource ||
|
110
|
+
!javaLanguage ||
|
111
|
+
!reactLanguage ||
|
112
|
+
!webPageResource ||
|
113
|
+
!restApiResource ||
|
114
|
+
!restClientResource ||
|
115
|
+
!webFragmentResource ||
|
116
|
+
!blockTypePubsub ||
|
117
|
+
!resourceTypePubsubSubscriber ||
|
118
|
+
!resourceTypePubsubSubscription ||
|
119
|
+
!resourceTypePubsubTopic ||
|
120
|
+
!resourceTypePubsubPublisher ||
|
121
|
+
!jwtProvider ||
|
122
|
+
!jwtConsumer ||
|
123
|
+
!smtpClient ||
|
124
|
+
!externalService ||
|
125
|
+
!blockTypeCli ||
|
126
|
+
!nodejsLanguage
|
127
|
+
) {
|
128
|
+
throw new Error('Missing definitions');
|
129
|
+
}
|
130
|
+
|
131
|
+
return {
|
132
|
+
serviceKind: normalizeKapetaUri(`${blockTypeService.definition.metadata.name}:${blockTypeService.version}`),
|
133
|
+
serviceLanguage: normalizeKapetaUri('kapeta/language-target-java-spring-boot:local'), //normalizeKapetaUri(`${javaLanguage.definition.metadata.name}:${javaLanguage.version}`),
|
134
|
+
|
135
|
+
frontendKind: normalizeKapetaUri(`${blockTypeFrontend.definition.metadata.name}:${blockTypeFrontend.version}`),
|
136
|
+
frontendLanguage: normalizeKapetaUri('kapeta/language-target-react-ts:local'), // normalizeKapetaUri(`${reactLanguage.definition.metadata.name}:${reactLanguage.version}`),
|
137
|
+
|
138
|
+
cliKind: normalizeKapetaUri(`${blockTypeCli.definition.metadata.name}:${blockTypeCli.version}`),
|
139
|
+
cliLanguage: normalizeKapetaUri(`${nodejsLanguage.definition.metadata.name}:${nodejsLanguage.version}`),
|
140
|
+
|
141
|
+
desktopKind: normalizeKapetaUri(`${blockTypeDesktop.definition.metadata.name}:${blockTypeDesktop.version}`),
|
142
|
+
desktopLanguage: normalizeKapetaUri(`${reactLanguage.definition.metadata.name}:${reactLanguage.version}`),
|
143
|
+
|
144
|
+
gatewayKind: normalizeKapetaUri(`${blockTypeGateway.definition.metadata.name}:${blockTypeGateway.version}`),
|
145
|
+
|
146
|
+
mqKind: normalizeKapetaUri(`${blockTypePubsub.definition.metadata.name}:${blockTypePubsub.version}`),
|
147
|
+
exchangeKind: normalizeKapetaUri(
|
148
|
+
`${resourceTypePubsubTopic.definition.metadata.name}:${resourceTypePubsubTopic.version}`
|
149
|
+
),
|
150
|
+
queueKind: normalizeKapetaUri(
|
151
|
+
`${resourceTypePubsubSubscription.definition.metadata.name}:${resourceTypePubsubSubscription.version}`
|
152
|
+
),
|
153
|
+
publisherKind: normalizeKapetaUri(
|
154
|
+
`${resourceTypePubsubPublisher.definition.metadata.name}:${resourceTypePubsubPublisher.version}`
|
155
|
+
),
|
156
|
+
subscriberKind: normalizeKapetaUri(
|
157
|
+
`${resourceTypePubsubSubscriber.definition.metadata.name}:${resourceTypePubsubSubscriber.version}`
|
158
|
+
),
|
159
|
+
|
160
|
+
databaseKind: normalizeKapetaUri(`${postgresResource.definition.metadata.name}:${postgresResource.version}`),
|
161
|
+
|
162
|
+
apiKind: normalizeKapetaUri(`${restApiResource.definition.metadata.name}:${restApiResource.version}`),
|
163
|
+
clientKind: normalizeKapetaUri(`${restClientResource.definition.metadata.name}:${restClientResource.version}`),
|
164
|
+
|
165
|
+
webPageKind: normalizeKapetaUri(`${webPageResource.definition.metadata.name}:${webPageResource.version}`),
|
166
|
+
webFragmentKind: normalizeKapetaUri(
|
167
|
+
`${webFragmentResource.definition.metadata.name}:${webFragmentResource.version}`
|
168
|
+
),
|
169
|
+
|
170
|
+
jwtProviderKind: normalizeKapetaUri(`${jwtProvider.definition.metadata.name}:${jwtProvider.version}`),
|
171
|
+
jwtConsumerKind: normalizeKapetaUri(`${jwtConsumer.definition.metadata.name}:${jwtConsumer.version}`),
|
172
|
+
|
173
|
+
smtpKind: normalizeKapetaUri(`${smtpClient.definition.metadata.name}:${smtpClient.version}`),
|
174
|
+
externalApiKind: normalizeKapetaUri(`${externalService.definition.metadata.name}:${externalService.version}`),
|
175
|
+
};
|
176
|
+
}
|
177
|
+
|
178
|
+
export class StormEventParser {
|
179
|
+
private events: StormEvent[] = [];
|
180
|
+
private planName: string = '';
|
181
|
+
private planDescription: string = '';
|
182
|
+
private blocks: { [key: string]: StormBlockInfoFilled } = {};
|
183
|
+
private connections: StormConnection[] = [];
|
184
|
+
private failed: boolean = false;
|
185
|
+
private error: string = '';
|
186
|
+
private options: StormOptions;
|
187
|
+
|
188
|
+
constructor(options: StormOptions) {
|
189
|
+
this.options = options;
|
190
|
+
}
|
191
|
+
|
192
|
+
private reset() {
|
193
|
+
this.planDescription = '';
|
194
|
+
this.planName = '';
|
195
|
+
this.blocks = {};
|
196
|
+
this.connections = [];
|
197
|
+
}
|
198
|
+
|
199
|
+
public addEvent(evt: StormEvent): void {
|
200
|
+
console.log('Processing storm event', evt);
|
201
|
+
this.events.push(evt);
|
202
|
+
switch (evt.type) {
|
203
|
+
case 'CREATE_PLAN_PROPERTIES':
|
204
|
+
this.planName = evt.payload.name;
|
205
|
+
this.planDescription = evt.payload.description;
|
206
|
+
break;
|
207
|
+
case 'CREATE_BLOCK':
|
208
|
+
this.blocks[evt.payload.name] = {
|
209
|
+
...evt.payload,
|
210
|
+
apis: [],
|
211
|
+
models: [],
|
212
|
+
types: [],
|
213
|
+
screens: [],
|
214
|
+
};
|
215
|
+
break;
|
216
|
+
case 'PLAN_RETRY':
|
217
|
+
this.reset();
|
218
|
+
break;
|
219
|
+
case 'PLAN_RETRY_FAILED':
|
220
|
+
this.failed = true;
|
221
|
+
this.error = evt.payload.error;
|
222
|
+
break;
|
223
|
+
case 'CREATE_API':
|
224
|
+
this.blocks[evt.payload.blockName].apis.push(evt.payload.content);
|
225
|
+
break;
|
226
|
+
case 'CREATE_TYPE':
|
227
|
+
this.blocks[evt.payload.blockName].types.push(evt.payload.content);
|
228
|
+
break;
|
229
|
+
case 'CREATE_MODEL':
|
230
|
+
this.blocks[evt.payload.blockName].models.push(evt.payload.content);
|
231
|
+
break;
|
232
|
+
case 'CREATE_CONNECTION':
|
233
|
+
this.connections.push(evt.payload);
|
234
|
+
break;
|
235
|
+
case 'SCREEN':
|
236
|
+
this.blocks[evt.payload.blockName].screens.push({
|
237
|
+
name: evt.payload.name,
|
238
|
+
description: evt.payload.description,
|
239
|
+
url: evt.payload.url,
|
240
|
+
template: evt.payload.template,
|
241
|
+
});
|
242
|
+
break;
|
243
|
+
|
244
|
+
default:
|
245
|
+
case 'SCREEN_CANDIDATE':
|
246
|
+
case 'FILE':
|
247
|
+
console.warn('Unhandled event: %s', evt.type, evt);
|
248
|
+
break;
|
249
|
+
}
|
250
|
+
}
|
251
|
+
|
252
|
+
public getEvents(): StormEvent[] {
|
253
|
+
return this.events;
|
254
|
+
}
|
255
|
+
|
256
|
+
public isValid(): boolean {
|
257
|
+
return !this.failed;
|
258
|
+
}
|
259
|
+
|
260
|
+
public getError(): string {
|
261
|
+
return this.error;
|
262
|
+
}
|
263
|
+
|
264
|
+
private applyLayoutToBlocks(result: ParsedResult): ParsedResult {
|
265
|
+
return result;
|
266
|
+
}
|
267
|
+
|
268
|
+
public toResult(handle: string): ParsedResult {
|
269
|
+
const planRef = this.toRef(handle, this.planName);
|
270
|
+
const blockDefinitions = this.toBlockDefinitions(handle);
|
271
|
+
const refIdMap: { [key: string]: string } = {};
|
272
|
+
const screens: { [key: string]: ScreenTemplate[] } = {};
|
273
|
+
const blocks = Object.entries(blockDefinitions).map(([ref, block]) => {
|
274
|
+
const id = uuid.v4();
|
275
|
+
refIdMap[ref] = id;
|
276
|
+
return {
|
277
|
+
id,
|
278
|
+
block: {
|
279
|
+
ref,
|
280
|
+
},
|
281
|
+
name: block.content.metadata.title ?? block.content.metadata.name,
|
282
|
+
dimensions: {
|
283
|
+
left: 0,
|
284
|
+
top: 0,
|
285
|
+
width: 200,
|
286
|
+
height: 200,
|
287
|
+
},
|
288
|
+
} satisfies BlockInstance;
|
289
|
+
});
|
290
|
+
|
291
|
+
Object.values(this.blocks).forEach((blockInfo) => {
|
292
|
+
const blockRef = this.toRef(handle, blockInfo.name);
|
293
|
+
const block = blockDefinitions[blockRef.toNormalizedString()];
|
294
|
+
if (!block) {
|
295
|
+
console.warn('Block not found: %s', blockInfo.name);
|
296
|
+
return;
|
297
|
+
}
|
298
|
+
|
299
|
+
screens[blockRef.fullName] = blockInfo.screens;
|
300
|
+
});
|
301
|
+
|
302
|
+
// Copy API methods from API provider to CLIENT consumer
|
303
|
+
this.connections
|
304
|
+
.filter((connection) => connection.fromResourceType === 'API' && connection.toResourceType === 'CLIENT')
|
305
|
+
.forEach((apiConnection) => {
|
306
|
+
const apiProviderRef = this.toRef(handle, apiConnection.fromComponent);
|
307
|
+
const clientConsumerRef = this.toRef(handle, apiConnection.toComponent);
|
308
|
+
const apiProviderBlock = blockDefinitions[apiProviderRef.toNormalizedString()];
|
309
|
+
if (!apiProviderBlock) {
|
310
|
+
console.warn('API provider not found: %s', apiConnection.fromComponent);
|
311
|
+
return;
|
312
|
+
}
|
313
|
+
const clientConsumerBlock = blockDefinitions[clientConsumerRef.toNormalizedString()];
|
314
|
+
if (!clientConsumerBlock) {
|
315
|
+
console.warn('Client consumer not found: %s', apiConnection.toComponent);
|
316
|
+
return;
|
317
|
+
}
|
318
|
+
|
319
|
+
const apiResource = apiProviderBlock.content.spec.providers?.find(
|
320
|
+
(p) => p.kind === this.options.apiKind && p.metadata.name === apiConnection.fromResource
|
321
|
+
);
|
322
|
+
|
323
|
+
if (!apiResource) {
|
324
|
+
console.warn(
|
325
|
+
'API resource not found: %s on %s',
|
326
|
+
apiConnection.fromResource,
|
327
|
+
apiProviderRef.toNormalizedString()
|
328
|
+
);
|
329
|
+
return;
|
330
|
+
}
|
331
|
+
|
332
|
+
const clientResource = clientConsumerBlock.content.spec.consumers?.find((clientResource) => {
|
333
|
+
if (clientResource.kind !== this.options.clientKind) {
|
334
|
+
return;
|
335
|
+
}
|
336
|
+
if (clientResource.metadata.name !== apiConnection.toResource) {
|
337
|
+
return;
|
338
|
+
}
|
339
|
+
});
|
340
|
+
|
341
|
+
if (!clientResource) {
|
342
|
+
console.warn(
|
343
|
+
'Client resource not found: %s on %s',
|
344
|
+
apiConnection.toResource,
|
345
|
+
clientConsumerRef.toNormalizedString()
|
346
|
+
);
|
347
|
+
return;
|
348
|
+
}
|
349
|
+
|
350
|
+
clientResource.spec.methods = apiResource.spec.methods;
|
351
|
+
clientResource.spec.source = apiResource.spec.source;
|
352
|
+
});
|
353
|
+
|
354
|
+
const connections = this.connections.map((connection) => {
|
355
|
+
const fromRef = this.toRef(handle, connection.fromComponent);
|
356
|
+
const toRef = this.toRef(handle, connection.toComponent);
|
357
|
+
return {
|
358
|
+
port: {
|
359
|
+
type: this.toPortType(connection.fromResourceType),
|
360
|
+
},
|
361
|
+
consumer: {
|
362
|
+
blockId: refIdMap[toRef.toNormalizedString()],
|
363
|
+
resourceName: connection.toResource,
|
364
|
+
},
|
365
|
+
provider: {
|
366
|
+
blockId: refIdMap[fromRef.toNormalizedString()],
|
367
|
+
resourceName: connection.fromResource,
|
368
|
+
},
|
369
|
+
mapping: {
|
370
|
+
//TODO: Add mapping
|
371
|
+
},
|
372
|
+
} satisfies Connection;
|
373
|
+
});
|
374
|
+
|
375
|
+
const plan: Plan = {
|
376
|
+
kind: 'core/plan',
|
377
|
+
metadata: {
|
378
|
+
name: planRef.fullName,
|
379
|
+
title: this.planName,
|
380
|
+
description: this.planDescription,
|
381
|
+
},
|
382
|
+
spec: {
|
383
|
+
blocks,
|
384
|
+
connections,
|
385
|
+
},
|
386
|
+
};
|
387
|
+
|
388
|
+
return this.applyLayoutToBlocks({
|
389
|
+
plan,
|
390
|
+
blocks: Object.values(blockDefinitions),
|
391
|
+
});
|
392
|
+
}
|
393
|
+
|
394
|
+
private toSafeName(name: string): string {
|
395
|
+
return name.toLowerCase().replace(/[^0-9a-z-]/gi, '');
|
396
|
+
}
|
397
|
+
|
398
|
+
private toRef(handle: string, name: string) {
|
399
|
+
return parseKapetaUri(handle + '/' + this.toSafeName(name) + ':local');
|
400
|
+
}
|
401
|
+
|
402
|
+
public toBlockDefinitions(handle: string): { [key: string]: BlockDefinitionInfo } {
|
403
|
+
const result: { [key: string]: BlockDefinitionInfo } = {};
|
404
|
+
|
405
|
+
Object.entries(this.blocks).forEach(([, blockInfo]) => {
|
406
|
+
const blockRef = this.toRef(handle, blockInfo.name);
|
407
|
+
|
408
|
+
const blockDefinitionInfo: BlockDefinitionInfo = {
|
409
|
+
uri: blockRef,
|
410
|
+
content: {
|
411
|
+
kind: this.toBlockKind(blockInfo.type),
|
412
|
+
metadata: {
|
413
|
+
title: blockInfo.name,
|
414
|
+
name: blockRef.fullName,
|
415
|
+
description: blockInfo.description,
|
416
|
+
},
|
417
|
+
spec: {
|
418
|
+
entities: {
|
419
|
+
types: [],
|
420
|
+
source: {
|
421
|
+
type: KAPLANG_ID,
|
422
|
+
version: KAPLANG_VERSION,
|
423
|
+
value: '',
|
424
|
+
},
|
425
|
+
},
|
426
|
+
target: this.toBlockTarget(handle, blockInfo.type),
|
427
|
+
providers: [],
|
428
|
+
consumers: [],
|
429
|
+
},
|
430
|
+
},
|
431
|
+
screens: blockInfo.screens,
|
432
|
+
};
|
433
|
+
|
434
|
+
const blockSpec = blockDefinitionInfo.content.spec;
|
435
|
+
|
436
|
+
let apiResource: Resource | undefined = undefined;
|
437
|
+
let dbResource: Resource | undefined = undefined;
|
438
|
+
|
439
|
+
blockInfo.resources.forEach((resource) => {
|
440
|
+
const port = {
|
441
|
+
type: this.toPortType(resource.type),
|
442
|
+
};
|
443
|
+
switch (resource.type) {
|
444
|
+
case 'API':
|
445
|
+
if (apiResource) {
|
446
|
+
break;
|
447
|
+
}
|
448
|
+
apiResource = {
|
449
|
+
kind: this.toResourceKind(resource.type),
|
450
|
+
metadata: {
|
451
|
+
name: resource.name,
|
452
|
+
description: resource.description,
|
453
|
+
},
|
454
|
+
spec: {
|
455
|
+
port,
|
456
|
+
methods: {},
|
457
|
+
source: {
|
458
|
+
type: KAPLANG_ID,
|
459
|
+
version: KAPLANG_VERSION,
|
460
|
+
value: '',
|
461
|
+
} satisfies SourceCode,
|
462
|
+
},
|
463
|
+
};
|
464
|
+
blockSpec.providers!.push(apiResource);
|
465
|
+
break;
|
466
|
+
case 'CLIENT':
|
467
|
+
blockSpec.consumers!.push({
|
468
|
+
kind: this.toResourceKind(resource.type),
|
469
|
+
metadata: {
|
470
|
+
name: resource.name,
|
471
|
+
description: resource.description,
|
472
|
+
},
|
473
|
+
spec: {
|
474
|
+
port,
|
475
|
+
methods: {},
|
476
|
+
source: {
|
477
|
+
type: KAPLANG_ID,
|
478
|
+
version: KAPLANG_VERSION,
|
479
|
+
value: '',
|
480
|
+
} satisfies SourceCode,
|
481
|
+
},
|
482
|
+
});
|
483
|
+
break;
|
484
|
+
case 'EXTERNAL_API':
|
485
|
+
break;
|
486
|
+
case 'EXCHANGE':
|
487
|
+
break;
|
488
|
+
case 'PUBLISHER':
|
489
|
+
break;
|
490
|
+
case 'QUEUE':
|
491
|
+
break;
|
492
|
+
case 'SUBSCRIBER':
|
493
|
+
break;
|
494
|
+
case 'JWTPROVIDER':
|
495
|
+
case 'WEBPAGE':
|
496
|
+
blockSpec.providers!.push({
|
497
|
+
kind: this.toResourceKind(resource.type),
|
498
|
+
metadata: {
|
499
|
+
name: resource.name,
|
500
|
+
description: resource.description,
|
501
|
+
},
|
502
|
+
spec: {
|
503
|
+
port,
|
504
|
+
},
|
505
|
+
});
|
506
|
+
break;
|
507
|
+
case 'DATABASE':
|
508
|
+
if (dbResource) {
|
509
|
+
break;
|
510
|
+
}
|
511
|
+
dbResource = {
|
512
|
+
kind: this.toResourceKind(resource.type),
|
513
|
+
metadata: {
|
514
|
+
name: resource.name,
|
515
|
+
description: resource.description,
|
516
|
+
},
|
517
|
+
spec: {
|
518
|
+
port,
|
519
|
+
models: [],
|
520
|
+
source: {
|
521
|
+
type: KAPLANG_ID,
|
522
|
+
version: KAPLANG_VERSION,
|
523
|
+
value: '',
|
524
|
+
} satisfies SourceCode,
|
525
|
+
},
|
526
|
+
};
|
527
|
+
blockSpec.providers!.push(dbResource);
|
528
|
+
break;
|
529
|
+
case 'JWTCONSUMER':
|
530
|
+
case 'WEBFRAGMENT':
|
531
|
+
case 'SMTPCLIENT':
|
532
|
+
blockSpec.consumers!.push({
|
533
|
+
kind: this.toResourceKind(resource.type),
|
534
|
+
metadata: {
|
535
|
+
name: resource.name,
|
536
|
+
description: resource.description,
|
537
|
+
},
|
538
|
+
spec: {
|
539
|
+
port,
|
540
|
+
},
|
541
|
+
});
|
542
|
+
}
|
543
|
+
});
|
544
|
+
|
545
|
+
if (apiResource) {
|
546
|
+
blockInfo.apis.forEach((api) => {
|
547
|
+
apiResource!.spec.source.value += api + '\n\n';
|
548
|
+
});
|
549
|
+
}
|
550
|
+
|
551
|
+
blockInfo.types.forEach((type) => {
|
552
|
+
blockSpec.entities!.source!.value += type + '\n';
|
553
|
+
});
|
554
|
+
|
555
|
+
if (dbResource) {
|
556
|
+
blockInfo.models.forEach((model) => {
|
557
|
+
dbResource!.spec.source.value += model + '\n';
|
558
|
+
});
|
559
|
+
}
|
560
|
+
|
561
|
+
result[blockRef.toNormalizedString()] = blockDefinitionInfo;
|
562
|
+
});
|
563
|
+
|
564
|
+
return result;
|
565
|
+
}
|
566
|
+
|
567
|
+
private toResourceKind(type: StormResourceType) {
|
568
|
+
//TODO: Handle support for multiple resource types and versions
|
569
|
+
switch (type) {
|
570
|
+
case 'API':
|
571
|
+
return this.options.apiKind;
|
572
|
+
case 'CLIENT':
|
573
|
+
return this.options.clientKind;
|
574
|
+
case 'DATABASE':
|
575
|
+
return this.options.databaseKind;
|
576
|
+
case 'JWTPROVIDER':
|
577
|
+
return this.options.jwtProviderKind;
|
578
|
+
case 'JWTCONSUMER':
|
579
|
+
return this.options.jwtConsumerKind;
|
580
|
+
case 'WEBFRAGMENT':
|
581
|
+
return this.options.webFragmentKind;
|
582
|
+
case 'WEBPAGE':
|
583
|
+
return this.options.webPageKind;
|
584
|
+
case 'SMTPCLIENT':
|
585
|
+
return this.options.smtpKind;
|
586
|
+
case 'EXTERNAL_API':
|
587
|
+
return this.options.externalApiKind;
|
588
|
+
case 'SUBSCRIBER':
|
589
|
+
return this.options.subscriberKind;
|
590
|
+
case 'PUBLISHER':
|
591
|
+
return this.options.publisherKind;
|
592
|
+
case 'QUEUE':
|
593
|
+
return this.options.queueKind;
|
594
|
+
case 'EXCHANGE':
|
595
|
+
return this.options.exchangeKind;
|
596
|
+
}
|
597
|
+
|
598
|
+
return '';
|
599
|
+
}
|
600
|
+
|
601
|
+
private toBlockKind(type: StormBlockType) {
|
602
|
+
switch (type) {
|
603
|
+
case 'BACKEND':
|
604
|
+
return this.options.serviceKind;
|
605
|
+
case 'FRONTEND':
|
606
|
+
return this.options.frontendKind;
|
607
|
+
case 'CLI':
|
608
|
+
return this.options.cliKind;
|
609
|
+
case 'DESKTOP':
|
610
|
+
return this.options.desktopKind;
|
611
|
+
case 'GATEWAY':
|
612
|
+
return this.options.gatewayKind;
|
613
|
+
case 'MQ':
|
614
|
+
return this.options.mqKind;
|
615
|
+
}
|
616
|
+
return '';
|
617
|
+
}
|
618
|
+
|
619
|
+
private toPortType(type: StormResourceType) {
|
620
|
+
switch (type) {
|
621
|
+
case 'API':
|
622
|
+
case 'CLIENT':
|
623
|
+
return 'rest';
|
624
|
+
|
625
|
+
case 'JWTPROVIDER':
|
626
|
+
case 'JWTCONSUMER':
|
627
|
+
return 'http';
|
628
|
+
|
629
|
+
case 'WEBFRAGMENT':
|
630
|
+
case 'WEBPAGE':
|
631
|
+
return 'web';
|
632
|
+
|
633
|
+
case 'SUBSCRIBER':
|
634
|
+
case 'PUBLISHER':
|
635
|
+
case 'QUEUE':
|
636
|
+
case 'EXCHANGE':
|
637
|
+
// PubSub uses http. TODO: Handle support for multiple MQ types
|
638
|
+
return 'http';
|
639
|
+
|
640
|
+
case 'SMTPCLIENT':
|
641
|
+
return 'smtp';
|
642
|
+
|
643
|
+
case 'DATABASE':
|
644
|
+
//TODO: Handle support for multiple DB types
|
645
|
+
return 'postgres';
|
646
|
+
}
|
647
|
+
|
648
|
+
return 'http';
|
649
|
+
}
|
650
|
+
|
651
|
+
private toBlockTarget(handle: string, type: StormBlockType): LanguageTargetReference | undefined {
|
652
|
+
const kind = this.toBlockTargetKind(type);
|
653
|
+
if (!kind) {
|
654
|
+
return undefined;
|
655
|
+
}
|
656
|
+
|
657
|
+
let options: { [key: string]: any } = {};
|
658
|
+
|
659
|
+
if (kind.includes('java')) {
|
660
|
+
const groupId = `ai.${this.toSafeName(handle)}`;
|
661
|
+
const artifactId = this.toSafeName(this.planName);
|
662
|
+
options = {
|
663
|
+
groupId,
|
664
|
+
artifactId,
|
665
|
+
basePackage: `${groupId}.${artifactId}`,
|
666
|
+
};
|
667
|
+
}
|
668
|
+
|
669
|
+
return {
|
670
|
+
kind,
|
671
|
+
options,
|
672
|
+
};
|
673
|
+
}
|
674
|
+
|
675
|
+
private toBlockTargetKind(type: StormBlockType): string | undefined {
|
676
|
+
switch (type) {
|
677
|
+
case 'BACKEND':
|
678
|
+
return this.options.serviceLanguage;
|
679
|
+
case 'CLI':
|
680
|
+
return this.options.cliLanguage;
|
681
|
+
case 'FRONTEND':
|
682
|
+
return this.options.frontendLanguage;
|
683
|
+
case 'DESKTOP':
|
684
|
+
return this.options.desktopLanguage;
|
685
|
+
}
|
686
|
+
return undefined;
|
687
|
+
}
|
688
|
+
}
|