@colyseus/schema 4.0.13 → 4.0.14
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/README.md +31 -0
- package/build/codegen/api.d.ts +2 -0
- package/build/codegen/cli.cjs +934 -177
- package/build/codegen/cli.cjs.map +1 -1
- package/build/codegen/languages/c.d.ts +11 -0
- package/build/codegen/languages/cpp.d.ts +8 -0
- package/build/codegen/languages/csharp.d.ts +8 -0
- package/build/codegen/languages/gdscript.d.ts +14 -0
- package/build/codegen/languages/haxe.d.ts +8 -0
- package/build/codegen/languages/java.d.ts +11 -1
- package/build/codegen/languages/js.d.ts +8 -0
- package/build/codegen/languages/lua.d.ts +8 -0
- package/build/codegen/languages/ts.d.ts +8 -0
- package/build/codegen/types.d.ts +14 -0
- package/package.json +1 -1
- package/src/codegen/api.ts +26 -15
- package/src/codegen/cli.ts +9 -15
- package/src/codegen/languages/c.ts +282 -0
- package/src/codegen/languages/cpp.ts +74 -22
- package/src/codegen/languages/csharp.ts +87 -19
- package/src/codegen/languages/gdscript.ts +219 -0
- package/src/codegen/languages/haxe.ts +41 -5
- package/src/codegen/languages/java.ts +45 -4
- package/src/codegen/languages/js.ts +62 -20
- package/src/codegen/languages/lua.ts +60 -18
- package/src/codegen/languages/ts.ts +65 -14
- package/src/codegen/types.ts +15 -0
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
import { GenerateOptions } from "../api.js";
|
|
10
10
|
import { Context } from "../types.js";
|
|
11
11
|
|
|
12
|
+
export const name = "Unity/C#";
|
|
13
|
+
|
|
12
14
|
const typeMaps: { [key: string]: string } = {
|
|
13
15
|
"string": "string",
|
|
14
16
|
"number": "float",
|
|
@@ -25,6 +27,11 @@ const typeMaps: { [key: string]: string } = {
|
|
|
25
27
|
"float64": "double",
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
const COMMON_IMPORTS = `using Colyseus.Schema;
|
|
31
|
+
#if UNITY_5_3_OR_NEWER
|
|
32
|
+
using UnityEngine.Scripting;
|
|
33
|
+
#endif`;
|
|
34
|
+
|
|
28
35
|
/**
|
|
29
36
|
* C# Code Generator
|
|
30
37
|
*/
|
|
@@ -33,6 +40,9 @@ const capitalize = (s: string) => {
|
|
|
33
40
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
34
41
|
}
|
|
35
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Generate individual files for each class/interface/enum
|
|
45
|
+
*/
|
|
36
46
|
export function generate(context: Context, options: GenerateOptions): File[] {
|
|
37
47
|
// enrich typeMaps with enums
|
|
38
48
|
context.enums.forEach((structure) => {
|
|
@@ -54,31 +64,69 @@ export function generate(context: Context, options: GenerateOptions): File[] {
|
|
|
54
64
|
];
|
|
55
65
|
}
|
|
56
66
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Generate a single bundled file containing all classes, interfaces, and enums
|
|
69
|
+
*/
|
|
70
|
+
export function renderBundle(context: Context, options: GenerateOptions): File {
|
|
71
|
+
const fileName = options.namespace ? `${options.namespace}.cs` : "Schema.cs";
|
|
72
|
+
const indent = options.namespace ? "\t" : "";
|
|
60
73
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
74
|
+
// enrich typeMaps with enums
|
|
75
|
+
context.enums.forEach((structure) => {
|
|
76
|
+
typeMaps[structure.name] = structure.name;
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Collect all bodies
|
|
80
|
+
const classBodies = context.classes.map(klass => generateClassBody(klass, indent));
|
|
81
|
+
const interfaceBodies = context.interfaces.map(iface => generateInterfaceBody(iface, indent));
|
|
82
|
+
const enumBodies = context.enums
|
|
83
|
+
.filter(structure => structure.name !== 'OPERATION')
|
|
84
|
+
.map(e => generateEnumBody(e, indent));
|
|
85
|
+
|
|
86
|
+
const allBodies = [...classBodies, ...interfaceBodies, ...enumBodies].join("\n\n");
|
|
87
|
+
|
|
88
|
+
const content = `${getCommentHeader()}
|
|
89
|
+
|
|
90
|
+
${COMMON_IMPORTS}
|
|
91
|
+
${options.namespace ? `\nnamespace ${options.namespace} {\n` : ""}
|
|
92
|
+
${allBodies}
|
|
93
|
+
${options.namespace ? "}" : ""}`;
|
|
94
|
+
|
|
95
|
+
return { name: fileName, content };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Generate just the class body (without imports/namespace) for bundling
|
|
100
|
+
*/
|
|
101
|
+
function generateClassBody(klass: Class, indent: string = ""): string {
|
|
102
|
+
return `${indent}public partial class ${klass.name} : ${klass.extends} {
|
|
67
103
|
#if UNITY_5_3_OR_NEWER
|
|
68
104
|
[Preserve]
|
|
69
105
|
#endif
|
|
70
106
|
public ${klass.name}() { }
|
|
71
107
|
${klass.properties.map((prop) => generateProperty(prop, indent)).join("\n\n")}
|
|
72
|
-
${indent}}
|
|
73
|
-
${namespace ? "}" : ""}
|
|
74
|
-
`;
|
|
108
|
+
${indent}}`;
|
|
75
109
|
}
|
|
76
110
|
|
|
77
|
-
|
|
78
|
-
|
|
111
|
+
/**
|
|
112
|
+
* Generate a complete class file with imports/namespace (for individual file mode)
|
|
113
|
+
*/
|
|
114
|
+
function generateClass(klass: Class, namespace: string) {
|
|
115
|
+
const indent = (namespace) ? "\t" : "";
|
|
79
116
|
return `${getCommentHeader()}
|
|
117
|
+
|
|
118
|
+
${COMMON_IMPORTS}
|
|
80
119
|
${namespace ? `\nnamespace ${namespace} {` : ""}
|
|
81
|
-
${indent}
|
|
120
|
+
${generateClassBody(klass, indent)}
|
|
121
|
+
${namespace ? "}" : ""}
|
|
122
|
+
`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Generate just the enum body (without imports/namespace) for bundling
|
|
127
|
+
*/
|
|
128
|
+
function generateEnumBody(_enum: Enum, indent: string = ""): string {
|
|
129
|
+
return `${indent}public struct ${_enum.name} {
|
|
82
130
|
|
|
83
131
|
${_enum.properties
|
|
84
132
|
.map((prop) => {
|
|
@@ -99,7 +147,17 @@ ${_enum.properties
|
|
|
99
147
|
return `${indent}\tpublic const ${dataType} ${prop.name} = ${value};`;
|
|
100
148
|
})
|
|
101
149
|
.join("\n")}
|
|
102
|
-
${indent}}
|
|
150
|
+
${indent}}`;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Generate a complete enum file with imports/namespace (for individual file mode)
|
|
155
|
+
*/
|
|
156
|
+
function generateEnum(_enum: Enum, namespace: string) {
|
|
157
|
+
const indent = namespace ? "\t" : "";
|
|
158
|
+
return `${getCommentHeader()}
|
|
159
|
+
${namespace ? `\nnamespace ${namespace} {` : ""}
|
|
160
|
+
${generateEnumBody(_enum, indent)}
|
|
103
161
|
${namespace ? "}" : ""}`
|
|
104
162
|
}
|
|
105
163
|
|
|
@@ -134,15 +192,25 @@ function generateProperty(prop: Property, indent: string = "") {
|
|
|
134
192
|
\t${indent}${property} = ${initializer};`;
|
|
135
193
|
}
|
|
136
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Generate just the interface body (without imports/namespace) for bundling
|
|
197
|
+
*/
|
|
198
|
+
function generateInterfaceBody(struct: Interface, indent: string = ""): string {
|
|
199
|
+
return `${indent}public class ${struct.name} {
|
|
200
|
+
${struct.properties.map(prop => `\t${indent}public ${getType(prop)} ${prop.name};`).join("\n")}
|
|
201
|
+
${indent}}`;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Generate a complete interface file with imports/namespace (for individual file mode)
|
|
206
|
+
*/
|
|
137
207
|
function generateInterface(struct: Interface, namespace: string) {
|
|
138
208
|
const indent = (namespace) ? "\t" : "";
|
|
139
209
|
return `${getCommentHeader()}
|
|
140
210
|
|
|
141
211
|
using Colyseus.Schema;
|
|
142
212
|
${namespace ? `\nnamespace ${namespace} {` : ""}
|
|
143
|
-
${indent}
|
|
144
|
-
${struct.properties.map(prop => `\t${indent}public ${getType(prop)} ${prop.name};`).join("\n")}
|
|
145
|
-
${indent}}
|
|
213
|
+
${generateInterfaceBody(struct, indent)}
|
|
146
214
|
${namespace ? "}" : ""}
|
|
147
215
|
`;
|
|
148
216
|
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Class,
|
|
3
|
+
Property,
|
|
4
|
+
File,
|
|
5
|
+
getCommentHeader,
|
|
6
|
+
getInheritanceTree,
|
|
7
|
+
Context,
|
|
8
|
+
Enum,
|
|
9
|
+
} from "../types.js";
|
|
10
|
+
import { GenerateOptions } from "../api.js";
|
|
11
|
+
|
|
12
|
+
export const name = "GDScript";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Type mappings from schema types to GDScript Colyseus.Schema type constants
|
|
16
|
+
*/
|
|
17
|
+
const typeMaps: { [key: string]: string } = {
|
|
18
|
+
"string": "Colyseus.Schema.STRING",
|
|
19
|
+
"number": "Colyseus.Schema.NUMBER",
|
|
20
|
+
"boolean": "Colyseus.Schema.BOOLEAN",
|
|
21
|
+
"int8": "Colyseus.Schema.INT8",
|
|
22
|
+
"uint8": "Colyseus.Schema.UINT8",
|
|
23
|
+
"int16": "Colyseus.Schema.INT16",
|
|
24
|
+
"uint16": "Colyseus.Schema.UINT16",
|
|
25
|
+
"int32": "Colyseus.Schema.INT32",
|
|
26
|
+
"uint32": "Colyseus.Schema.UINT32",
|
|
27
|
+
"int64": "Colyseus.Schema.INT64",
|
|
28
|
+
"uint64": "Colyseus.Schema.UINT64",
|
|
29
|
+
"float32": "Colyseus.Schema.FLOAT32",
|
|
30
|
+
"float64": "Colyseus.Schema.FLOAT64",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const containerMaps: { [key: string]: string } = {
|
|
34
|
+
"array": "Colyseus.Schema.ARRAY",
|
|
35
|
+
"map": "Colyseus.Schema.MAP",
|
|
36
|
+
"ref": "Colyseus.Schema.REF",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const distinct = (value: string, index: number, self: string[]) =>
|
|
40
|
+
self.indexOf(value) === index;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* GDScript Code Generator
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Generate individual files for each class
|
|
48
|
+
*/
|
|
49
|
+
export function generate(context: Context, options: GenerateOptions): File[] {
|
|
50
|
+
// Enrich typeMaps with enums
|
|
51
|
+
context.enums.forEach((structure) => {
|
|
52
|
+
typeMaps[structure.name] = structure.name;
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return [
|
|
56
|
+
...context.classes.map(klass => ({
|
|
57
|
+
name: `${klass.name}.gd`,
|
|
58
|
+
content: generateClass(klass, options.namespace, context.classes)
|
|
59
|
+
})),
|
|
60
|
+
...context.enums.filter(structure => structure.name !== 'OPERATION').map((structure) => ({
|
|
61
|
+
name: `${structure.name}.gd`,
|
|
62
|
+
content: generateEnum(structure, options.namespace),
|
|
63
|
+
})),
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Generate a single bundled file containing all classes and enums
|
|
69
|
+
*/
|
|
70
|
+
export function renderBundle(context: Context, options: GenerateOptions): File {
|
|
71
|
+
const fileName = options.namespace ? `${options.namespace}.gd` : "schema.gd";
|
|
72
|
+
|
|
73
|
+
// Enrich typeMaps with enums
|
|
74
|
+
context.enums.forEach((structure) => {
|
|
75
|
+
typeMaps[structure.name] = structure.name;
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const enumBodies = context.enums
|
|
79
|
+
.filter(structure => structure.name !== 'OPERATION')
|
|
80
|
+
.map(e => generateEnumBody(e));
|
|
81
|
+
|
|
82
|
+
const classBodies = context.classes.map(klass => generateClassBody(klass));
|
|
83
|
+
|
|
84
|
+
const content = `${getCommentHeader("#")}
|
|
85
|
+
|
|
86
|
+
${enumBodies.length > 0 ? enumBodies.join("\n\n") + "\n\n" : ""}${classBodies.join("\n\n")}
|
|
87
|
+
`;
|
|
88
|
+
|
|
89
|
+
return { name: fileName, content };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Generate just the class body (without preload) for bundling
|
|
94
|
+
*/
|
|
95
|
+
function generateClassBody(klass: Class): string {
|
|
96
|
+
// Determine parent class
|
|
97
|
+
const parentClass = (klass.extends !== "Schema")
|
|
98
|
+
? klass.extends
|
|
99
|
+
: "Colyseus.Schema";
|
|
100
|
+
|
|
101
|
+
const properties = klass.properties;
|
|
102
|
+
|
|
103
|
+
const fieldsContent = properties.length > 0
|
|
104
|
+
? properties.map(prop => generateFieldDefinition(prop)).join(",\n") + ","
|
|
105
|
+
: "";
|
|
106
|
+
|
|
107
|
+
// Generate _to_string() method
|
|
108
|
+
const toStringMethod = generateToStringMethod(klass.name, properties);
|
|
109
|
+
|
|
110
|
+
return `class ${klass.name} extends ${parentClass}:
|
|
111
|
+
static func definition():
|
|
112
|
+
return [
|
|
113
|
+
${fieldsContent}
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
${toStringMethod}`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Generate _to_string() method for the class
|
|
121
|
+
*/
|
|
122
|
+
function generateToStringMethod(className: string, properties: Property[]): string {
|
|
123
|
+
const fieldNames = properties.map(prop => prop.name);
|
|
124
|
+
const allFields = ["__ref_id", ...fieldNames];
|
|
125
|
+
|
|
126
|
+
const formatParts = allFields.map(name => `${name}: %s`).join(", ");
|
|
127
|
+
const formatString = `${className}(${formatParts})`;
|
|
128
|
+
|
|
129
|
+
const selfReferences = allFields.map(name => `self.${name}`).join(", ");
|
|
130
|
+
|
|
131
|
+
return `\tfunc _to_string() -> String:
|
|
132
|
+
return "${formatString}" % [${selfReferences}]`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Generate a complete class file with preload (for individual file mode)
|
|
137
|
+
*/
|
|
138
|
+
function generateClass(klass: Class, namespace: string, allClasses: Class[]) {
|
|
139
|
+
const allRefs: Property[] = [];
|
|
140
|
+
klass.properties.forEach(property => {
|
|
141
|
+
let type = property.type;
|
|
142
|
+
|
|
143
|
+
// Keep all refs list
|
|
144
|
+
if ((type === "ref" || type === "array" || type === "map")) {
|
|
145
|
+
allRefs.push(property);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Get required preloads for referenced types
|
|
150
|
+
const preloads = allRefs
|
|
151
|
+
.filter(ref => ref.childType && typeMaps[ref.childType] === undefined)
|
|
152
|
+
.map(ref => ref.childType)
|
|
153
|
+
.concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name))
|
|
154
|
+
.filter(distinct)
|
|
155
|
+
.map(childType => `const ${childType} = preload("${childType}.gd")`)
|
|
156
|
+
.join("\n");
|
|
157
|
+
|
|
158
|
+
return `${getCommentHeader("#")}
|
|
159
|
+
|
|
160
|
+
${preloads ? preloads + "\n\n" : ""}${generateClassBody(klass)}
|
|
161
|
+
`;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Generate a field definition for the definition() array
|
|
166
|
+
*/
|
|
167
|
+
function generateFieldDefinition(prop: Property): string {
|
|
168
|
+
let args: string[];
|
|
169
|
+
|
|
170
|
+
if (prop.childType) {
|
|
171
|
+
const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
|
|
172
|
+
|
|
173
|
+
// Array or Map container
|
|
174
|
+
const containerType = containerMaps[prop.type];
|
|
175
|
+
const childTypeRef = isUpcaseFirst ? prop.childType : typeMaps[prop.childType] || `"${prop.childType}"`;
|
|
176
|
+
args = [`"${prop.name}"`, containerType, childTypeRef];
|
|
177
|
+
} else {
|
|
178
|
+
// Primitive type
|
|
179
|
+
const typeRef = typeMaps[prop.type] || `"${prop.type}"`;
|
|
180
|
+
args = [`"${prop.name}"`, typeRef];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return `\t\t\tColyseus.Schema.Field.new(${args.join(", ")})`;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Generate just the enum body for bundling
|
|
188
|
+
*/
|
|
189
|
+
function generateEnumBody(_enum: Enum): string {
|
|
190
|
+
const enumValues = _enum.properties.map((prop, index) => {
|
|
191
|
+
let value: any;
|
|
192
|
+
|
|
193
|
+
if (prop.type) {
|
|
194
|
+
if (isNaN(Number(prop.type))) {
|
|
195
|
+
value = `"${prop.type}"`;
|
|
196
|
+
} else {
|
|
197
|
+
value = Number(prop.type);
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
value = index;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return `\t"${prop.name}": ${value},`;
|
|
204
|
+
}).join("\n");
|
|
205
|
+
|
|
206
|
+
return `const ${_enum.name} = {
|
|
207
|
+
${enumValues}
|
|
208
|
+
}`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Generate a complete enum file (for individual file mode)
|
|
213
|
+
*/
|
|
214
|
+
function generateEnum(_enum: Enum, _namespace: string) {
|
|
215
|
+
return `${getCommentHeader("#")}
|
|
216
|
+
|
|
217
|
+
${generateEnumBody(_enum)}
|
|
218
|
+
`;
|
|
219
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Class, Property, File, getCommentHeader, Context } from "../types.js";
|
|
2
2
|
import { GenerateOptions } from "../api.js";
|
|
3
3
|
|
|
4
|
+
export const name = "Haxe";
|
|
5
|
+
|
|
4
6
|
const typeMaps: { [key: string]: string } = {
|
|
5
7
|
"string": "String",
|
|
6
8
|
"number": "Dynamic",
|
|
@@ -33,6 +35,12 @@ const typeInitializer: { [key: string]: string } = {
|
|
|
33
35
|
"float64": "0",
|
|
34
36
|
}
|
|
35
37
|
|
|
38
|
+
const COMMON_IMPORTS = `import io.colyseus.serializer.schema.Schema;
|
|
39
|
+
import io.colyseus.serializer.schema.types.*;`;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Generate individual files for each class
|
|
43
|
+
*/
|
|
36
44
|
export function generate (context: Context, options: GenerateOptions): File[] {
|
|
37
45
|
return context.classes.map(klass => ({
|
|
38
46
|
name: klass.name + ".hx",
|
|
@@ -40,6 +48,25 @@ export function generate (context: Context, options: GenerateOptions): File[] {
|
|
|
40
48
|
}));
|
|
41
49
|
}
|
|
42
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Generate a single bundled file containing all classes
|
|
53
|
+
*/
|
|
54
|
+
export function renderBundle(context: Context, options: GenerateOptions): File {
|
|
55
|
+
const fileName = options.namespace ? `${options.namespace}.hx` : "Schema.hx";
|
|
56
|
+
|
|
57
|
+
const classBodies = context.classes.map(klass => generateClassBody(klass));
|
|
58
|
+
|
|
59
|
+
const content = `${getCommentHeader()}
|
|
60
|
+
|
|
61
|
+
${options.namespace ? `package ${options.namespace};` : ""}
|
|
62
|
+
${COMMON_IMPORTS}
|
|
63
|
+
|
|
64
|
+
${classBodies.join("\n\n")}
|
|
65
|
+
`;
|
|
66
|
+
|
|
67
|
+
return { name: fileName, content };
|
|
68
|
+
}
|
|
69
|
+
|
|
43
70
|
function getInheritanceTree(klass: Class, allClasses: Class[], includeSelf: boolean = true) {
|
|
44
71
|
let currentClass = klass;
|
|
45
72
|
let inheritanceTree: Class[] = [];
|
|
@@ -56,16 +83,25 @@ function getInheritanceTree(klass: Class, allClasses: Class[], includeSelf: bool
|
|
|
56
83
|
return inheritanceTree;
|
|
57
84
|
}
|
|
58
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Generate just the class body (without package/imports) for bundling
|
|
88
|
+
*/
|
|
89
|
+
function generateClassBody(klass: Class): string {
|
|
90
|
+
return `class ${klass.name} extends ${klass.extends} {
|
|
91
|
+
${klass.properties.map(prop => generateProperty(prop)).join("\n")}
|
|
92
|
+
}`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Generate a complete class file with package/imports (for individual file mode)
|
|
97
|
+
*/
|
|
59
98
|
function generateClass(klass: Class, namespace: string, allClasses: Class[]) {
|
|
60
99
|
return `${getCommentHeader()}
|
|
61
100
|
|
|
62
101
|
${namespace ? `package ${namespace};` : ""}
|
|
63
|
-
|
|
64
|
-
import io.colyseus.serializer.schema.types.*;
|
|
102
|
+
${COMMON_IMPORTS}
|
|
65
103
|
|
|
66
|
-
|
|
67
|
-
${klass.properties.map(prop => generateProperty(prop)).join("\n")}
|
|
68
|
-
}
|
|
104
|
+
${generateClassBody(klass)}
|
|
69
105
|
`;
|
|
70
106
|
}
|
|
71
107
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Class, Property, File, getCommentHeader, Context } from "../types.js";
|
|
2
2
|
import { GenerateOptions } from "../api.js";
|
|
3
3
|
|
|
4
|
+
export const name = "Java";
|
|
5
|
+
|
|
4
6
|
const typeMaps: { [key: string]: string } = {
|
|
5
7
|
"string": "String",
|
|
6
8
|
"number": "float",
|
|
@@ -33,10 +35,17 @@ const typeInitializer: { [key: string]: string } = {
|
|
|
33
35
|
"float64": "0",
|
|
34
36
|
}
|
|
35
37
|
|
|
38
|
+
const COMMON_IMPORTS = `import io.colyseus.serializer.schema.Schema;
|
|
39
|
+
import io.colyseus.serializer.schema.annotations.SchemaClass;
|
|
40
|
+
import io.colyseus.serializer.schema.annotations.SchemaField;`;
|
|
41
|
+
|
|
36
42
|
/**
|
|
37
|
-
*
|
|
43
|
+
* Java Code Generator
|
|
38
44
|
*/
|
|
39
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Generate individual files for each class
|
|
48
|
+
*/
|
|
40
49
|
export function generate (context: Context, options: GenerateOptions): File[] {
|
|
41
50
|
return context.classes.map(klass => ({
|
|
42
51
|
name: klass.name + ".java",
|
|
@@ -44,14 +53,46 @@ export function generate (context: Context, options: GenerateOptions): File[] {
|
|
|
44
53
|
}));
|
|
45
54
|
}
|
|
46
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Generate a single bundled file containing all classes
|
|
58
|
+
* Note: Java typically requires one public class per file, so bundled mode
|
|
59
|
+
* generates all classes in a single file with package-private visibility
|
|
60
|
+
*/
|
|
61
|
+
export function renderBundle(context: Context, options: GenerateOptions): File {
|
|
62
|
+
const fileName = options.namespace ? `Schema.java` : "Schema.java";
|
|
63
|
+
|
|
64
|
+
const classBodies = context.classes.map(klass => generateClassBody(klass));
|
|
65
|
+
|
|
66
|
+
const content = `${getCommentHeader()}
|
|
67
|
+
${options.namespace ? `\npackage ${options.namespace};` : ""}
|
|
68
|
+
|
|
69
|
+
${COMMON_IMPORTS}
|
|
70
|
+
|
|
71
|
+
${classBodies.join("\n\n")}
|
|
72
|
+
`;
|
|
73
|
+
|
|
74
|
+
return { name: fileName, content };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Generate just the class body (without package/imports) for bundling
|
|
79
|
+
*/
|
|
80
|
+
function generateClassBody(klass: Class): string {
|
|
81
|
+
return `@SchemaClass
|
|
82
|
+
class ${klass.name} extends ${klass.extends} {
|
|
83
|
+
${klass.properties.map(prop => generateProperty(prop, "")).join("\n\n")}
|
|
84
|
+
}`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Generate a complete class file with package/imports (for individual file mode)
|
|
89
|
+
*/
|
|
47
90
|
function generateClass(klass: Class, namespace: string) {
|
|
48
91
|
const indent = (namespace) ? "\t" : "";
|
|
49
92
|
return `${getCommentHeader()}
|
|
50
93
|
${namespace ? `\npackage ${namespace};` : ""}
|
|
51
94
|
|
|
52
|
-
|
|
53
|
-
import io.colyseus.serializer.schema.annotations.SchemaClass;
|
|
54
|
-
import io.colyseus.serializer.schema.annotations.SchemaField;
|
|
95
|
+
${COMMON_IMPORTS}
|
|
55
96
|
|
|
56
97
|
@SchemaClass
|
|
57
98
|
${indent}public class ${klass.name} extends ${klass.extends} {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Class, Property, File, getCommentHeader, getInheritanceTree, Context } from "../types.js";
|
|
2
2
|
import { GenerateOptions } from "../api.js";
|
|
3
3
|
|
|
4
|
+
export const name = "JavaScript";
|
|
5
|
+
|
|
4
6
|
const typeMaps: { [key: string]: string } = {
|
|
5
7
|
"string": "string",
|
|
6
8
|
"number": "number",
|
|
@@ -17,9 +19,16 @@ const typeMaps: { [key: string]: string } = {
|
|
|
17
19
|
"float64": "number",
|
|
18
20
|
}
|
|
19
21
|
|
|
22
|
+
const COMMON_IMPORTS = `const schema = require("@colyseus/schema");
|
|
23
|
+
const Schema = schema.Schema;
|
|
24
|
+
const type = schema.type;`;
|
|
25
|
+
|
|
20
26
|
const distinct = (value: string, index: number, self: string[]) =>
|
|
21
27
|
self.indexOf(value) === index;
|
|
22
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Generate individual files for each class
|
|
31
|
+
*/
|
|
23
32
|
export function generate (context: Context, options: GenerateOptions): File[] {
|
|
24
33
|
return context.classes.map(klass => ({
|
|
25
34
|
name: klass.name + ".js",
|
|
@@ -27,6 +36,47 @@ export function generate (context: Context, options: GenerateOptions): File[] {
|
|
|
27
36
|
}));
|
|
28
37
|
}
|
|
29
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Generate a single bundled file containing all classes
|
|
41
|
+
*/
|
|
42
|
+
export function renderBundle(context: Context, options: GenerateOptions): File {
|
|
43
|
+
const fileName = options.namespace ? `${options.namespace}.js` : "schema.js";
|
|
44
|
+
|
|
45
|
+
const classBodies = context.classes.map(klass => generateClassBody(klass));
|
|
46
|
+
const classExports = context.classes.map(klass => ` ${klass.name},`).join("\n");
|
|
47
|
+
|
|
48
|
+
const content = `${getCommentHeader()}
|
|
49
|
+
|
|
50
|
+
${COMMON_IMPORTS}
|
|
51
|
+
|
|
52
|
+
${classBodies.join("\n\n")}
|
|
53
|
+
|
|
54
|
+
module.exports = {
|
|
55
|
+
${classExports}
|
|
56
|
+
};
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
return { name: fileName, content };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Generate just the class body (without imports) for bundling
|
|
64
|
+
*/
|
|
65
|
+
function generateClassBody(klass: Class): string {
|
|
66
|
+
return `class ${klass.name} extends ${klass.extends} {
|
|
67
|
+
constructor () {
|
|
68
|
+
super();
|
|
69
|
+
${klass.properties.
|
|
70
|
+
filter(prop => prop.childType !== undefined).
|
|
71
|
+
map(prop => " " + generatePropertyInitializer(prop)).join("\n")}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
${klass.properties.map(prop => generatePropertyDeclaration(klass.name, prop)).join("\n")}`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Generate a complete class file with imports (for individual file mode)
|
|
79
|
+
*/
|
|
30
80
|
function generateClass(klass: Class, namespace: string, allClasses: Class[]) {
|
|
31
81
|
const allRefs: Property[] = [];
|
|
32
82
|
klass.properties.forEach(property => {
|
|
@@ -38,28 +88,20 @@ function generateClass(klass: Class, namespace: string, allClasses: Class[]) {
|
|
|
38
88
|
}
|
|
39
89
|
});
|
|
40
90
|
|
|
91
|
+
const localImports = allRefs.
|
|
92
|
+
filter(ref => ref.childType && typeMaps[ref.childType] === undefined).
|
|
93
|
+
map(ref => ref.childType).
|
|
94
|
+
concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name)).
|
|
95
|
+
filter(distinct).
|
|
96
|
+
map(childType => `const ${childType} = require("./${childType}");`).
|
|
97
|
+
join("\n");
|
|
98
|
+
|
|
41
99
|
return `${getCommentHeader()}
|
|
42
100
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
${
|
|
47
|
-
filter(ref => ref.childType && typeMaps[ref.childType] === undefined).
|
|
48
|
-
map(ref => ref.childType).
|
|
49
|
-
concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name)).
|
|
50
|
-
filter(distinct).
|
|
51
|
-
map(childType => `const ${childType} = require("./${childType}");`).
|
|
52
|
-
join("\n")}
|
|
53
|
-
|
|
54
|
-
class ${klass.name} extends ${klass.extends} {
|
|
55
|
-
constructor () {
|
|
56
|
-
super();
|
|
57
|
-
${klass.properties.
|
|
58
|
-
filter(prop => prop.childType !== undefined).
|
|
59
|
-
map(prop => " " + generatePropertyInitializer(prop)).join("\n")}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
${klass.properties.map(prop => generatePropertyDeclaration(klass.name, prop)).join("\n")}
|
|
101
|
+
${COMMON_IMPORTS}
|
|
102
|
+
${localImports}
|
|
103
|
+
|
|
104
|
+
${generateClassBody(klass)}
|
|
63
105
|
|
|
64
106
|
export default ${klass.name};
|
|
65
107
|
`;
|