@polytric/openws-sdkgen 0.0.3 → 0.0.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/dist/main.cjs +22 -205
- package/dist/main.d.cts +1 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +403 -0
- package/dist/plans/dotnet.cjs +229 -0
- package/dist/plans/dotnet.d.cts +147 -0
- package/dist/plans/dotnet.d.ts +147 -0
- package/dist/plans/dotnet.js +192 -0
- package/package.json +2 -4
- /package/{src/dotnet/template → dist/templates/dotnet}/HostRole.cs.ejs +0 -0
- /package/{src/dotnet/template → dist/templates/dotnet}/Model.cs.ejs +0 -0
- /package/{src/dotnet/template → dist/templates/dotnet}/Network.cs.ejs +0 -0
- /package/{src/dotnet/template → dist/templates/dotnet}/RemoteRole.cs.ejs +0 -0
- /package/{src/dotnet/template → dist/templates/dotnet}/Service.asmdef.ejs +0 -0
- /package/{src/dotnet/template → dist/templates/dotnet}/UserHostRole.cs.ejs +0 -0
- /package/{src/dotnet/template → dist/templates/dotnet}/UserService.asmref.ejs +0 -0
package/dist/main.cjs
CHANGED
|
@@ -23,10 +23,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
mod
|
|
24
24
|
));
|
|
25
25
|
|
|
26
|
-
// ../../node_modules/.pnpm/tsup@8.5.1_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js
|
|
27
|
-
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
28
|
-
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
29
|
-
|
|
30
26
|
// src/build-ir.ts
|
|
31
27
|
var import_schema = __toESM(require("@pocketgems/schema"), 1);
|
|
32
28
|
var validateIr = import_schema.default.obj({
|
|
@@ -238,215 +234,27 @@ function buildIr(ctx) {
|
|
|
238
234
|
};
|
|
239
235
|
}
|
|
240
236
|
|
|
241
|
-
// src/dotnet/build-plan.ts
|
|
242
|
-
var import_node_path = __toESM(require("path"), 1);
|
|
243
|
-
var import_node_url = require("url");
|
|
244
|
-
var __dirname = import_node_path.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
245
|
-
function pascalCase(str) {
|
|
246
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
247
|
-
}
|
|
248
|
-
function camelCase(str) {
|
|
249
|
-
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
250
|
-
}
|
|
251
|
-
function createPlan(ctx) {
|
|
252
|
-
const { ir, request } = ctx;
|
|
253
|
-
if (!ir) throw new Error("ir is required");
|
|
254
|
-
if (!request) throw new Error("request is required");
|
|
255
|
-
const assemblyName = `${pascalCase(ir.package.project)}.${pascalCase(ir.package.service)}.Sdk`;
|
|
256
|
-
ir.assemblyName = assemblyName;
|
|
257
|
-
const plan = [
|
|
258
|
-
{
|
|
259
|
-
name: "assembly definition",
|
|
260
|
-
command: "render",
|
|
261
|
-
getData: () => ir,
|
|
262
|
-
template: import_node_path.default.join(__dirname, "template", "Service.asmdef.ejs"),
|
|
263
|
-
output: import_node_path.default.join(request.outputPath, assemblyName, `${assemblyName}.asmdef`)
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
name: "user assembly reference",
|
|
267
|
-
command: "render",
|
|
268
|
-
getData: () => ir,
|
|
269
|
-
template: import_node_path.default.join(__dirname, "template", "UserService.asmref.ejs"),
|
|
270
|
-
output: import_node_path.default.join(
|
|
271
|
-
request.outputPath,
|
|
272
|
-
`${assemblyName}.User`,
|
|
273
|
-
`${assemblyName}.User.asmref`
|
|
274
|
-
)
|
|
275
|
-
}
|
|
276
|
-
];
|
|
277
|
-
for (const networkIr of ir.networks) {
|
|
278
|
-
const networkNamespace = `${pascalCase(ir.package.project)}.${pascalCase(ir.package.service)}.${pascalCase(networkIr.name)}`;
|
|
279
|
-
const networkClassName = `${pascalCase(networkIr.name)}Network`;
|
|
280
|
-
const networkOutputPath = import_node_path.default.join(
|
|
281
|
-
request.outputPath,
|
|
282
|
-
assemblyName,
|
|
283
|
-
pascalCase(networkIr.name)
|
|
284
|
-
);
|
|
285
|
-
const userNetworkOutputPath = import_node_path.default.join(
|
|
286
|
-
request.outputPath,
|
|
287
|
-
`${assemblyName}.User`,
|
|
288
|
-
pascalCase(networkIr.name)
|
|
289
|
-
);
|
|
290
|
-
const hostRoles = [];
|
|
291
|
-
const remoteRoles = [];
|
|
292
|
-
for (const role of networkIr.roles) {
|
|
293
|
-
const roleInfo = {
|
|
294
|
-
roleName: role.name,
|
|
295
|
-
className: pascalCase(role.name),
|
|
296
|
-
varName: camelCase(role.name),
|
|
297
|
-
description: role.description || "",
|
|
298
|
-
baseClassName: role.isHost ? "HostRole" : "RemoteRole",
|
|
299
|
-
endpoints: role.endpoints || []
|
|
300
|
-
};
|
|
301
|
-
if (role.isHost) {
|
|
302
|
-
hostRoles.push(roleInfo);
|
|
303
|
-
} else {
|
|
304
|
-
remoteRoles.push(roleInfo);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
const allRoles = [...hostRoles, ...remoteRoles];
|
|
308
|
-
const allModelImports = allRoles.map((role) => `${networkNamespace}.Models.${role.className}`);
|
|
309
|
-
plan.push({
|
|
310
|
-
name: `network ${networkIr.name}`,
|
|
311
|
-
command: "render",
|
|
312
|
-
getData: () => ({
|
|
313
|
-
namespace: networkNamespace,
|
|
314
|
-
networkClassName,
|
|
315
|
-
networkName: networkIr.name,
|
|
316
|
-
description: networkIr.description,
|
|
317
|
-
version: networkIr.version,
|
|
318
|
-
allRoles
|
|
319
|
-
}),
|
|
320
|
-
template: import_node_path.default.join(__dirname, "template", "Network.cs.ejs"),
|
|
321
|
-
output: import_node_path.default.join(networkOutputPath, `${networkClassName}.cs`)
|
|
322
|
-
});
|
|
323
|
-
for (const modelIr of networkIr.models) {
|
|
324
|
-
modelIr.namespace = `${networkNamespace}.Models.${pascalCase(modelIr.scopeName)}`;
|
|
325
|
-
modelIr.className = pascalCase(modelIr.modelName);
|
|
326
|
-
if (modelIr.properties) {
|
|
327
|
-
for (const propertyIr of modelIr.properties) {
|
|
328
|
-
propertyIr.propertyName = pascalCase(propertyIr.modelName);
|
|
329
|
-
propertyIr.typeName = mapType(propertyIr);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
for (const handlerIr of networkIr.handlers) {
|
|
334
|
-
handlerIr.modelClassName = pascalCase(handlerIr.handlerName);
|
|
335
|
-
handlerIr.messageName = handlerIr.handlerName;
|
|
336
|
-
handlerIr.methodName = pascalCase(handlerIr.handlerName);
|
|
337
|
-
}
|
|
338
|
-
for (const messageIr of networkIr.messages) {
|
|
339
|
-
messageIr.modelClassName = pascalCase(messageIr.handlerName);
|
|
340
|
-
messageIr.messageName = messageIr.handlerName;
|
|
341
|
-
messageIr.methodName = pascalCase(messageIr.handlerName);
|
|
342
|
-
}
|
|
343
|
-
for (const hostRole of hostRoles) {
|
|
344
|
-
const roleHandlers = networkIr.handlers.filter((h) => h.roleName === hostRole.roleName);
|
|
345
|
-
const modelImports = [`${networkNamespace}.Models.${hostRole.className}`];
|
|
346
|
-
plan.push({
|
|
347
|
-
name: `host role ${hostRole.className}`,
|
|
348
|
-
command: "render",
|
|
349
|
-
getData: () => ({
|
|
350
|
-
namespace: `${networkNamespace}.Roles`,
|
|
351
|
-
handlers: roleHandlers,
|
|
352
|
-
remoteRoles,
|
|
353
|
-
modelImports,
|
|
354
|
-
...hostRole
|
|
355
|
-
}),
|
|
356
|
-
template: import_node_path.default.join(__dirname, "template", "HostRole.cs.ejs"),
|
|
357
|
-
output: import_node_path.default.join(networkOutputPath, "Roles", `${hostRole.className}.cs`)
|
|
358
|
-
});
|
|
359
|
-
plan.push({
|
|
360
|
-
name: `user host role ${hostRole.className}`,
|
|
361
|
-
command: "render",
|
|
362
|
-
getData: () => ({
|
|
363
|
-
namespace: `${networkNamespace}.Roles`,
|
|
364
|
-
handlers: roleHandlers,
|
|
365
|
-
remoteRoles,
|
|
366
|
-
modelImports: allModelImports,
|
|
367
|
-
...hostRole
|
|
368
|
-
}),
|
|
369
|
-
template: import_node_path.default.join(__dirname, "template", "UserHostRole.cs.ejs"),
|
|
370
|
-
output: import_node_path.default.join(userNetworkOutputPath, "Roles", `${hostRole.className}.cs`)
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
for (const remoteRole of remoteRoles) {
|
|
374
|
-
const roleMessages = networkIr.messages.filter((m) => m.roleName === remoteRole.roleName);
|
|
375
|
-
const modelImports = [`${networkNamespace}.Models.${remoteRole.className}`];
|
|
376
|
-
plan.push({
|
|
377
|
-
name: `remote role ${remoteRole.className}`,
|
|
378
|
-
command: "render",
|
|
379
|
-
getData: () => ({
|
|
380
|
-
namespace: `${networkNamespace}.Roles`,
|
|
381
|
-
messages: roleMessages,
|
|
382
|
-
modelImports,
|
|
383
|
-
...remoteRole
|
|
384
|
-
}),
|
|
385
|
-
template: import_node_path.default.join(__dirname, "template", "RemoteRole.cs.ejs"),
|
|
386
|
-
output: import_node_path.default.join(networkOutputPath, "Roles", `${remoteRole.className}.cs`)
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
|
-
for (const modelIr of networkIr.models) {
|
|
390
|
-
if (modelIr.type !== "object") continue;
|
|
391
|
-
plan.push({
|
|
392
|
-
name: `model ${modelIr.className}`,
|
|
393
|
-
command: "render",
|
|
394
|
-
getData: () => modelIr,
|
|
395
|
-
template: import_node_path.default.join(__dirname, "template", "Model.cs.ejs"),
|
|
396
|
-
output: import_node_path.default.join(
|
|
397
|
-
networkOutputPath,
|
|
398
|
-
"Models",
|
|
399
|
-
pascalCase(modelIr.scopeName),
|
|
400
|
-
`${modelIr.className}.cs`
|
|
401
|
-
)
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
return {
|
|
406
|
-
...ctx,
|
|
407
|
-
plan
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
function mapType(property) {
|
|
411
|
-
switch (property.type) {
|
|
412
|
-
case "string":
|
|
413
|
-
return "string";
|
|
414
|
-
case "number":
|
|
415
|
-
return "double";
|
|
416
|
-
case "integer":
|
|
417
|
-
return "int";
|
|
418
|
-
case "boolean":
|
|
419
|
-
return "bool";
|
|
420
|
-
case "array":
|
|
421
|
-
if (!property.items) return "List<object>";
|
|
422
|
-
return `List<${mapType(property.items)}>`;
|
|
423
|
-
case "object":
|
|
424
|
-
return pascalCase(property.modelName);
|
|
425
|
-
default:
|
|
426
|
-
return "object";
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
237
|
// src/build-plan.ts
|
|
431
238
|
var planIndex = {
|
|
432
239
|
csharp: {
|
|
433
|
-
unity:
|
|
240
|
+
unity: "./plans/dotnet.js"
|
|
434
241
|
}
|
|
435
242
|
};
|
|
436
|
-
function dispatchBuildPlan(ctx) {
|
|
243
|
+
async function dispatchBuildPlan(ctx) {
|
|
437
244
|
const { request } = ctx;
|
|
438
245
|
if (!request) throw new Error("request is required");
|
|
439
246
|
const language = Object.keys(request.target)[0];
|
|
440
247
|
const targetConfig = request.target[language];
|
|
441
248
|
if (!targetConfig) throw new Error(`No target config for language: ${language}`);
|
|
442
249
|
const environment = targetConfig.environment;
|
|
443
|
-
const
|
|
444
|
-
if (!
|
|
250
|
+
const planPath = planIndex[language]?.[environment];
|
|
251
|
+
if (!planPath) throw new Error(`No plan for ${language}/${environment}`);
|
|
252
|
+
const { default: plan } = await import(planPath);
|
|
445
253
|
return plan(ctx);
|
|
446
254
|
}
|
|
447
255
|
|
|
448
256
|
// src/build-request.ts
|
|
449
|
-
var
|
|
257
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
450
258
|
var import_node_process = __toESM(require("process"), 1);
|
|
451
259
|
var import_schema2 = __toESM(require("@pocketgems/schema"), 1);
|
|
452
260
|
var validateBuildRequest = import_schema2.default.obj({
|
|
@@ -470,8 +278,8 @@ function buildRequest(ctx) {
|
|
|
470
278
|
if (!rawInput) throw new Error("rawInput is required");
|
|
471
279
|
console.log("Host roles:", rawInput.hostRole);
|
|
472
280
|
const request = {
|
|
473
|
-
specPath:
|
|
474
|
-
outputPath:
|
|
281
|
+
specPath: import_node_path.default.join(import_node_process.default.cwd(), rawInput.spec),
|
|
282
|
+
outputPath: import_node_path.default.join(import_node_process.default.cwd(), rawInput.out),
|
|
475
283
|
project: rawInput.project,
|
|
476
284
|
hostRoles: rawInput.hostRole,
|
|
477
285
|
target: {
|
|
@@ -490,7 +298,7 @@ function buildRequest(ctx) {
|
|
|
490
298
|
|
|
491
299
|
// src/execute-plan.ts
|
|
492
300
|
var import_node_fs = __toESM(require("fs"), 1);
|
|
493
|
-
var
|
|
301
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
494
302
|
var import_ejs = __toESM(require("ejs"), 1);
|
|
495
303
|
var rendererCache = {};
|
|
496
304
|
function renderTemplate(templatePath, data) {
|
|
@@ -517,7 +325,7 @@ function executePlan(ctx) {
|
|
|
517
325
|
if (!getData || !template) continue;
|
|
518
326
|
const data = getData();
|
|
519
327
|
console.log(data);
|
|
520
|
-
import_node_fs.default.mkdirSync(
|
|
328
|
+
import_node_fs.default.mkdirSync(import_node_path2.default.dirname(output), { recursive: true });
|
|
521
329
|
import_node_fs.default.writeFileSync(output, renderTemplate(template, { ctx: data }));
|
|
522
330
|
break;
|
|
523
331
|
}
|
|
@@ -603,7 +411,16 @@ var Pipeline = [
|
|
|
603
411
|
dispatchBuildPlan,
|
|
604
412
|
executePlan
|
|
605
413
|
];
|
|
606
|
-
function main() {
|
|
607
|
-
|
|
414
|
+
async function main() {
|
|
415
|
+
let ctx = { argv: process.argv };
|
|
416
|
+
for (const step of Pipeline) {
|
|
417
|
+
ctx = await step(ctx);
|
|
418
|
+
}
|
|
419
|
+
return ctx;
|
|
608
420
|
}
|
|
609
|
-
|
|
421
|
+
main().then((result) => {
|
|
422
|
+
console.log(JSON.stringify(result, null, 2));
|
|
423
|
+
}).catch((err) => {
|
|
424
|
+
console.error(err);
|
|
425
|
+
process.exit(1);
|
|
426
|
+
});
|
package/dist/main.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/main.js
ADDED
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/build-ir.ts
|
|
4
|
+
import S from "@pocketgems/schema";
|
|
5
|
+
var validateIr = S.obj({
|
|
6
|
+
package: S.obj({
|
|
7
|
+
project: S.str,
|
|
8
|
+
service: S.str,
|
|
9
|
+
description: S.str.optional(),
|
|
10
|
+
version: S.str.optional()
|
|
11
|
+
}),
|
|
12
|
+
networks: S.arr(
|
|
13
|
+
S.obj({
|
|
14
|
+
name: S.str,
|
|
15
|
+
description: S.str.optional(),
|
|
16
|
+
version: S.str.optional(),
|
|
17
|
+
roles: S.arr(
|
|
18
|
+
S.obj({
|
|
19
|
+
name: S.str,
|
|
20
|
+
description: S.str.optional(),
|
|
21
|
+
isHost: S.bool,
|
|
22
|
+
endpoints: S.arr(
|
|
23
|
+
S.obj({
|
|
24
|
+
scheme: S.str.enum("ws", "wss"),
|
|
25
|
+
host: S.str,
|
|
26
|
+
port: S.int.min(0).max(65535),
|
|
27
|
+
path: S.str
|
|
28
|
+
})
|
|
29
|
+
)
|
|
30
|
+
})
|
|
31
|
+
),
|
|
32
|
+
handlers: S.arr(
|
|
33
|
+
S.obj({
|
|
34
|
+
roleName: S.str,
|
|
35
|
+
handlerName: S.str,
|
|
36
|
+
description: S.str.optional()
|
|
37
|
+
})
|
|
38
|
+
),
|
|
39
|
+
messages: S.arr(
|
|
40
|
+
S.obj({
|
|
41
|
+
roleName: S.str,
|
|
42
|
+
handlerName: S.str,
|
|
43
|
+
description: S.str.optional()
|
|
44
|
+
})
|
|
45
|
+
),
|
|
46
|
+
models: S.arr(
|
|
47
|
+
S.obj({
|
|
48
|
+
scopeName: S.str,
|
|
49
|
+
modelName: S.str,
|
|
50
|
+
type: S.str,
|
|
51
|
+
description: S.str.optional(),
|
|
52
|
+
properties: S.arr(
|
|
53
|
+
S.obj({
|
|
54
|
+
type: S.str,
|
|
55
|
+
scopeName: S.str,
|
|
56
|
+
modelName: S.str,
|
|
57
|
+
description: S.str.optional(),
|
|
58
|
+
required: S.bool.optional(),
|
|
59
|
+
items: S.obj({
|
|
60
|
+
type: S.str,
|
|
61
|
+
scopeName: S.str,
|
|
62
|
+
modelName: S.str,
|
|
63
|
+
description: S.str.optional()
|
|
64
|
+
}).optional()
|
|
65
|
+
})
|
|
66
|
+
).optional()
|
|
67
|
+
})
|
|
68
|
+
)
|
|
69
|
+
})
|
|
70
|
+
).desc("An array of network definitions")
|
|
71
|
+
}).compile("IrValidator");
|
|
72
|
+
function buildIrModels(scopeName, modelName, schema) {
|
|
73
|
+
const type = schema.type;
|
|
74
|
+
const model = {
|
|
75
|
+
type,
|
|
76
|
+
scopeName,
|
|
77
|
+
modelName,
|
|
78
|
+
description: schema.description
|
|
79
|
+
};
|
|
80
|
+
switch (type) {
|
|
81
|
+
case "string":
|
|
82
|
+
case "number":
|
|
83
|
+
case "integer":
|
|
84
|
+
case "boolean":
|
|
85
|
+
case "null":
|
|
86
|
+
return [];
|
|
87
|
+
case "array": {
|
|
88
|
+
if (!schema.items) return [];
|
|
89
|
+
return buildIrModels(scopeName, modelName, schema.items);
|
|
90
|
+
}
|
|
91
|
+
case "object": {
|
|
92
|
+
const properties = [];
|
|
93
|
+
model.properties = properties;
|
|
94
|
+
const models = [];
|
|
95
|
+
if (!schema.properties) return [model];
|
|
96
|
+
for (const [subName, subSchema] of Object.entries(schema.properties)) {
|
|
97
|
+
const subModels = buildIrModels(scopeName, subName, subSchema);
|
|
98
|
+
const mainModel = subModels.find((m) => m.modelName === subName) ?? subSchema;
|
|
99
|
+
const property = {
|
|
100
|
+
type: mainModel.type,
|
|
101
|
+
description: mainModel.description,
|
|
102
|
+
scopeName: mainModel.scopeName ?? scopeName,
|
|
103
|
+
modelName: mainModel.modelName ?? subName,
|
|
104
|
+
required: schema.required?.includes(subName)
|
|
105
|
+
};
|
|
106
|
+
const itemsSource = mainModel.properties?.[0]?.items ?? mainModel.items;
|
|
107
|
+
if (itemsSource) {
|
|
108
|
+
property.items = {
|
|
109
|
+
type: itemsSource.type,
|
|
110
|
+
description: itemsSource.description,
|
|
111
|
+
scopeName: itemsSource?.scopeName ?? scopeName,
|
|
112
|
+
modelName: itemsSource?.modelName ?? subName
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
properties.push(property);
|
|
116
|
+
models.push(...subModels);
|
|
117
|
+
}
|
|
118
|
+
return [model, ...models];
|
|
119
|
+
}
|
|
120
|
+
default:
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function buildIr(ctx) {
|
|
125
|
+
const { request, spec } = ctx;
|
|
126
|
+
if (!request) throw new Error("request is required");
|
|
127
|
+
if (!spec) throw new Error("spec is required");
|
|
128
|
+
const { hostRoles } = request;
|
|
129
|
+
const ir = {
|
|
130
|
+
package: {
|
|
131
|
+
project: request.project,
|
|
132
|
+
service: spec.name,
|
|
133
|
+
description: spec.description,
|
|
134
|
+
version: spec.version
|
|
135
|
+
},
|
|
136
|
+
networks: []
|
|
137
|
+
};
|
|
138
|
+
for (const [networkName, networkSpec] of Object.entries(spec.networks)) {
|
|
139
|
+
const hostRoleSpecs = hostRoles.map((hostRole) => networkSpec.roles[hostRole]);
|
|
140
|
+
const otherRoleSpecs = {};
|
|
141
|
+
for (const [roleName, roleSpec] of Object.entries(networkSpec.roles)) {
|
|
142
|
+
if (!hostRoles.includes(roleName)) {
|
|
143
|
+
otherRoleSpecs[roleName] = roleSpec;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const requiredRoles = /* @__PURE__ */ new Set();
|
|
147
|
+
for (const hostRoleSpec of hostRoleSpecs) {
|
|
148
|
+
for (const handlerSpec of Object.values(hostRoleSpec.messages)) {
|
|
149
|
+
if (handlerSpec.from) {
|
|
150
|
+
for (const fromRoleName of handlerSpec.from) {
|
|
151
|
+
requiredRoles.add(fromRoleName);
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
for (const key of Object.keys(otherRoleSpecs)) {
|
|
155
|
+
requiredRoles.add(key);
|
|
156
|
+
}
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const irNetwork = {
|
|
162
|
+
name: networkName,
|
|
163
|
+
description: networkSpec.description,
|
|
164
|
+
version: networkSpec.version,
|
|
165
|
+
roles: [],
|
|
166
|
+
handlers: [],
|
|
167
|
+
messages: [],
|
|
168
|
+
models: []
|
|
169
|
+
};
|
|
170
|
+
for (const hostRoleSpec of hostRoleSpecs) {
|
|
171
|
+
irNetwork.roles.push({
|
|
172
|
+
name: hostRoleSpec.name,
|
|
173
|
+
description: hostRoleSpec.description,
|
|
174
|
+
isHost: true,
|
|
175
|
+
endpoints: hostRoleSpec.endpoints || []
|
|
176
|
+
});
|
|
177
|
+
for (const [handlerName, handlerSpec] of Object.entries(hostRoleSpec.messages)) {
|
|
178
|
+
irNetwork.handlers.push({
|
|
179
|
+
roleName: hostRoleSpec.name,
|
|
180
|
+
handlerName,
|
|
181
|
+
description: handlerSpec.description
|
|
182
|
+
});
|
|
183
|
+
irNetwork.models.push(
|
|
184
|
+
...buildIrModels(hostRoleSpec.name, handlerName, handlerSpec.payload)
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
for (const [roleName, roleSpec] of Object.entries(otherRoleSpecs)) {
|
|
189
|
+
if (!requiredRoles.has(roleName)) continue;
|
|
190
|
+
irNetwork.roles.push({
|
|
191
|
+
name: roleName,
|
|
192
|
+
description: roleSpec.description,
|
|
193
|
+
isHost: false,
|
|
194
|
+
endpoints: roleSpec.endpoints || []
|
|
195
|
+
});
|
|
196
|
+
for (const [handlerName, handlerSpec] of Object.entries(roleSpec.messages)) {
|
|
197
|
+
irNetwork.messages.push({
|
|
198
|
+
roleName,
|
|
199
|
+
handlerName,
|
|
200
|
+
description: handlerSpec.description
|
|
201
|
+
});
|
|
202
|
+
irNetwork.models.push(...buildIrModels(roleName, handlerName, handlerSpec.payload));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
ir.networks.push(irNetwork);
|
|
206
|
+
}
|
|
207
|
+
validateIr(ir);
|
|
208
|
+
return {
|
|
209
|
+
...ctx,
|
|
210
|
+
ir
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// src/build-plan.ts
|
|
215
|
+
var planIndex = {
|
|
216
|
+
csharp: {
|
|
217
|
+
unity: "./plans/dotnet.js"
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
async function dispatchBuildPlan(ctx) {
|
|
221
|
+
const { request } = ctx;
|
|
222
|
+
if (!request) throw new Error("request is required");
|
|
223
|
+
const language = Object.keys(request.target)[0];
|
|
224
|
+
const targetConfig = request.target[language];
|
|
225
|
+
if (!targetConfig) throw new Error(`No target config for language: ${language}`);
|
|
226
|
+
const environment = targetConfig.environment;
|
|
227
|
+
const planPath = planIndex[language]?.[environment];
|
|
228
|
+
if (!planPath) throw new Error(`No plan for ${language}/${environment}`);
|
|
229
|
+
const { default: plan } = await import(planPath);
|
|
230
|
+
return plan(ctx);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// src/build-request.ts
|
|
234
|
+
import path from "path";
|
|
235
|
+
import process2 from "process";
|
|
236
|
+
import S2 from "@pocketgems/schema";
|
|
237
|
+
var validateBuildRequest = S2.obj({
|
|
238
|
+
specPath: S2.str,
|
|
239
|
+
outputPath: S2.str,
|
|
240
|
+
project: S2.str,
|
|
241
|
+
hostRoles: S2.arr(S2.str),
|
|
242
|
+
target: S2.obj({
|
|
243
|
+
csharp: S2.obj({
|
|
244
|
+
environment: S2.str.enum("unity"),
|
|
245
|
+
frameworks: S2.arr(S2.str.enum("newtonsoft")).optional()
|
|
246
|
+
}).optional(),
|
|
247
|
+
javascript: S2.obj({
|
|
248
|
+
environment: S2.str.enum("node", "browser"),
|
|
249
|
+
frameworks: S2.arr(S2.str.enum("fastify")).optional()
|
|
250
|
+
}).optional()
|
|
251
|
+
}).min(1).max(1).desc("The target platform to generate code for")
|
|
252
|
+
}).compile("BuildRequestValidator");
|
|
253
|
+
function buildRequest(ctx) {
|
|
254
|
+
const { rawInput } = ctx;
|
|
255
|
+
if (!rawInput) throw new Error("rawInput is required");
|
|
256
|
+
console.log("Host roles:", rawInput.hostRole);
|
|
257
|
+
const request = {
|
|
258
|
+
specPath: path.join(process2.cwd(), rawInput.spec),
|
|
259
|
+
outputPath: path.join(process2.cwd(), rawInput.out),
|
|
260
|
+
project: rawInput.project,
|
|
261
|
+
hostRoles: rawInput.hostRole,
|
|
262
|
+
target: {
|
|
263
|
+
[rawInput.language]: {
|
|
264
|
+
environment: rawInput.environment,
|
|
265
|
+
frameworks: rawInput.frameworks
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
validateBuildRequest(request);
|
|
270
|
+
return {
|
|
271
|
+
...ctx,
|
|
272
|
+
request
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// src/execute-plan.ts
|
|
277
|
+
import fs from "fs";
|
|
278
|
+
import path2 from "path";
|
|
279
|
+
import ejs from "ejs";
|
|
280
|
+
var rendererCache = {};
|
|
281
|
+
function renderTemplate(templatePath, data) {
|
|
282
|
+
if (rendererCache[templatePath]) {
|
|
283
|
+
return rendererCache[templatePath](data);
|
|
284
|
+
}
|
|
285
|
+
const templateContent = fs.readFileSync(templatePath, "utf8");
|
|
286
|
+
const renderer = ejs.compile(templateContent);
|
|
287
|
+
rendererCache[templatePath] = renderer;
|
|
288
|
+
return renderer(data);
|
|
289
|
+
}
|
|
290
|
+
function executePlan(ctx) {
|
|
291
|
+
const { plan } = ctx;
|
|
292
|
+
if (!plan) throw new Error("plan is required");
|
|
293
|
+
for (const step of plan) {
|
|
294
|
+
switch (step.command) {
|
|
295
|
+
case "copy":
|
|
296
|
+
if (step.input) {
|
|
297
|
+
fs.cpSync(step.input, step.output, { recursive: true });
|
|
298
|
+
}
|
|
299
|
+
break;
|
|
300
|
+
case "render": {
|
|
301
|
+
const { getData, template, output } = step;
|
|
302
|
+
if (!getData || !template) continue;
|
|
303
|
+
const data = getData();
|
|
304
|
+
console.log(data);
|
|
305
|
+
fs.mkdirSync(path2.dirname(output), { recursive: true });
|
|
306
|
+
fs.writeFileSync(output, renderTemplate(template, { ctx: data }));
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return ctx;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// src/load-spec.ts
|
|
315
|
+
import fs2 from "fs";
|
|
316
|
+
function loadSpec(ctx) {
|
|
317
|
+
const { request } = ctx;
|
|
318
|
+
if (!request) throw new Error("request is required");
|
|
319
|
+
const { specPath } = request;
|
|
320
|
+
const spec = JSON.parse(fs2.readFileSync(specPath, "utf8"));
|
|
321
|
+
return {
|
|
322
|
+
...ctx,
|
|
323
|
+
spec
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// src/parse-input.ts
|
|
328
|
+
import yargs from "yargs";
|
|
329
|
+
import { hideBin } from "yargs/helpers";
|
|
330
|
+
function parseInput(ctx) {
|
|
331
|
+
const args = yargs(hideBin(ctx.argv)).scriptName("openws-sdkgen").version(false).option("spec", {
|
|
332
|
+
type: "string",
|
|
333
|
+
description: "The path to the OpenWS spec file",
|
|
334
|
+
demandOption: true
|
|
335
|
+
}).option("out", {
|
|
336
|
+
type: "string",
|
|
337
|
+
description: "The path to the output directory",
|
|
338
|
+
demandOption: true
|
|
339
|
+
}).option("project", {
|
|
340
|
+
type: "string",
|
|
341
|
+
description: "The project name",
|
|
342
|
+
demandOption: true
|
|
343
|
+
}).option("hostRole", {
|
|
344
|
+
type: "array",
|
|
345
|
+
string: true,
|
|
346
|
+
description: "The target participant roles that use the generated code",
|
|
347
|
+
demandOption: true
|
|
348
|
+
}).option("language", {
|
|
349
|
+
type: "string",
|
|
350
|
+
description: "The language to generate code for",
|
|
351
|
+
choices: ["csharp", "javascript"],
|
|
352
|
+
default: "csharp"
|
|
353
|
+
}).option("environment", {
|
|
354
|
+
type: "string",
|
|
355
|
+
description: "The environment to generate code for",
|
|
356
|
+
choices: ["unity", "node", "browser"],
|
|
357
|
+
default: "unity"
|
|
358
|
+
}).option("frameworks", {
|
|
359
|
+
type: "array",
|
|
360
|
+
string: true,
|
|
361
|
+
description: "The frameworks to generate code for",
|
|
362
|
+
choices: ["fastify", "newtonsoft"]
|
|
363
|
+
}).strict().help().parseSync();
|
|
364
|
+
return {
|
|
365
|
+
...ctx,
|
|
366
|
+
rawInput: args
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// src/prepare-output.ts
|
|
371
|
+
import fs3 from "fs";
|
|
372
|
+
function prepareOutput(ctx) {
|
|
373
|
+
const { request } = ctx;
|
|
374
|
+
if (!request) throw new Error("request is required");
|
|
375
|
+
const { outputPath } = request;
|
|
376
|
+
fs3.rmSync(outputPath, { recursive: true, force: true });
|
|
377
|
+
fs3.mkdirSync(outputPath, { recursive: true });
|
|
378
|
+
return ctx;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// src/main.ts
|
|
382
|
+
var Pipeline = [
|
|
383
|
+
parseInput,
|
|
384
|
+
buildRequest,
|
|
385
|
+
prepareOutput,
|
|
386
|
+
loadSpec,
|
|
387
|
+
buildIr,
|
|
388
|
+
dispatchBuildPlan,
|
|
389
|
+
executePlan
|
|
390
|
+
];
|
|
391
|
+
async function main() {
|
|
392
|
+
let ctx = { argv: process.argv };
|
|
393
|
+
for (const step of Pipeline) {
|
|
394
|
+
ctx = await step(ctx);
|
|
395
|
+
}
|
|
396
|
+
return ctx;
|
|
397
|
+
}
|
|
398
|
+
main().then((result) => {
|
|
399
|
+
console.log(JSON.stringify(result, null, 2));
|
|
400
|
+
}).catch((err) => {
|
|
401
|
+
console.error(err);
|
|
402
|
+
process.exit(1);
|
|
403
|
+
});
|