@colyseus/schema 2.0.4 → 2.0.6
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 +0 -4
- package/build/cjs/index.js +48 -48
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +130 -104
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +50 -50
- package/lib/Reflection.js +87 -119
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.js +195 -257
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.d.ts +6 -6
- package/lib/annotations.js +64 -92
- package/lib/annotations.js.map +1 -1
- package/lib/changes/ChangeTree.d.ts +1 -1
- package/lib/changes/ChangeTree.js +63 -70
- package/lib/changes/ChangeTree.js.map +1 -1
- package/lib/changes/ReferenceTracker.js +24 -27
- package/lib/changes/ReferenceTracker.js.map +1 -1
- package/lib/codegen/api.js +9 -9
- package/lib/codegen/api.js.map +1 -1
- package/lib/codegen/argv.d.ts +1 -1
- package/lib/codegen/argv.js +11 -11
- package/lib/codegen/argv.js.map +1 -1
- package/lib/codegen/cli.js +21 -10
- package/lib/codegen/cli.js.map +1 -1
- package/lib/codegen/languages/cpp.js +126 -77
- package/lib/codegen/languages/cpp.js.map +1 -1
- package/lib/codegen/languages/csharp.js +121 -62
- package/lib/codegen/languages/csharp.js.map +1 -1
- package/lib/codegen/languages/haxe.js +34 -26
- package/lib/codegen/languages/haxe.js.map +1 -1
- package/lib/codegen/languages/java.js +39 -27
- package/lib/codegen/languages/java.js.map +1 -1
- package/lib/codegen/languages/js.js +48 -32
- package/lib/codegen/languages/js.js.map +1 -1
- package/lib/codegen/languages/lua.js +35 -24
- package/lib/codegen/languages/lua.js.map +1 -1
- package/lib/codegen/languages/ts.js +63 -68
- package/lib/codegen/languages/ts.js.map +1 -1
- package/lib/codegen/parser.d.ts +9 -1
- package/lib/codegen/parser.js +88 -46
- package/lib/codegen/parser.js.map +1 -1
- package/lib/codegen/types.d.ts +8 -0
- package/lib/codegen/types.js +64 -54
- package/lib/codegen/types.js.map +1 -1
- package/lib/encoding/decode.js +15 -15
- package/lib/encoding/decode.js.map +1 -1
- package/lib/encoding/encode.js +14 -14
- package/lib/encoding/encode.js.map +1 -1
- package/lib/events/EventEmitter.d.ts +1 -1
- package/lib/events/EventEmitter.js +16 -47
- package/lib/events/EventEmitter.js.map +1 -1
- package/lib/filters/index.js +7 -8
- package/lib/filters/index.js.map +1 -1
- package/lib/index.js +11 -11
- package/lib/index.js.map +1 -1
- package/lib/types/ArraySchema.d.ts +1 -1
- package/lib/types/ArraySchema.js +161 -219
- package/lib/types/ArraySchema.js.map +1 -1
- package/lib/types/CollectionSchema.d.ts +1 -1
- package/lib/types/CollectionSchema.js +63 -71
- package/lib/types/CollectionSchema.js.map +1 -1
- package/lib/types/HelperTypes.d.ts +9 -9
- package/lib/types/MapSchema.d.ts +16 -16
- package/lib/types/MapSchema.js +68 -78
- package/lib/types/MapSchema.js.map +1 -1
- package/lib/types/SetSchema.js +62 -71
- package/lib/types/SetSchema.js.map +1 -1
- package/lib/types/index.js +1 -1
- package/lib/types/index.js.map +1 -1
- package/lib/types/typeRegistry.js +1 -1
- package/lib/types/typeRegistry.js.map +1 -1
- package/lib/types/utils.js +9 -10
- package/lib/types/utils.js.map +1 -1
- package/lib/utils.js +10 -13
- package/lib/utils.js.map +1 -1
- package/package.json +18 -15
- package/src/Reflection.ts +159 -0
- package/src/Schema.ts +1024 -0
- package/src/annotations.ts +400 -0
- package/src/changes/ChangeTree.ts +295 -0
- package/src/changes/ReferenceTracker.ts +81 -0
- package/src/codegen/api.ts +46 -0
- package/src/codegen/argv.ts +40 -0
- package/src/codegen/cli.ts +65 -0
- package/src/codegen/languages/cpp.ts +297 -0
- package/src/codegen/languages/csharp.ts +208 -0
- package/src/codegen/languages/haxe.ts +110 -0
- package/src/codegen/languages/java.ts +115 -0
- package/src/codegen/languages/js.ts +115 -0
- package/src/codegen/languages/lua.ts +125 -0
- package/src/codegen/languages/ts.ts +129 -0
- package/src/codegen/parser.ts +299 -0
- package/src/codegen/types.ts +177 -0
- package/src/encoding/decode.ts +278 -0
- package/src/encoding/encode.ts +283 -0
- package/src/filters/index.ts +23 -0
- package/src/index.ts +59 -0
- package/src/spec.ts +49 -0
- package/src/types/ArraySchema.ts +612 -0
- package/src/types/CollectionSchema.ts +199 -0
- package/src/types/HelperTypes.ts +34 -0
- package/src/types/MapSchema.ts +268 -0
- package/src/types/SetSchema.ts +208 -0
- package/src/types/typeRegistry.ts +19 -0
- package/src/types/utils.ts +62 -0
- package/src/utils.ts +28 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Class,
|
|
3
|
+
Property,
|
|
4
|
+
File,
|
|
5
|
+
getCommentHeader,
|
|
6
|
+
Interface,
|
|
7
|
+
Enum,
|
|
8
|
+
} from "../types";
|
|
9
|
+
import { GenerateOptions } from "../api";
|
|
10
|
+
import { Context } from "../types";
|
|
11
|
+
|
|
12
|
+
const typeMaps = {
|
|
13
|
+
"string": "string",
|
|
14
|
+
"number": "float",
|
|
15
|
+
"boolean": "bool",
|
|
16
|
+
"int8": "sbyte",
|
|
17
|
+
"uint8": "byte",
|
|
18
|
+
"int16": "short",
|
|
19
|
+
"uint16": "ushort",
|
|
20
|
+
"int32": "int",
|
|
21
|
+
"uint32": "uint",
|
|
22
|
+
"int64": "long",
|
|
23
|
+
"uint64": "ulong",
|
|
24
|
+
"float32": "float",
|
|
25
|
+
"float64": "double",
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* C# Code Generator
|
|
30
|
+
*/
|
|
31
|
+
const capitalize = (s) => {
|
|
32
|
+
if (typeof s !== 'string') return ''
|
|
33
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function generate(context: Context, options: GenerateOptions): File[] {
|
|
37
|
+
// enrich typeMaps with enums
|
|
38
|
+
context.enums.forEach((structure) => {
|
|
39
|
+
typeMaps[structure.name] = structure.name;
|
|
40
|
+
});
|
|
41
|
+
return [
|
|
42
|
+
...context.classes.map(structure => ({
|
|
43
|
+
name: `${structure.name}.cs`,
|
|
44
|
+
content: generateClass(structure, options.namespace)
|
|
45
|
+
})),
|
|
46
|
+
...context.interfaces.map(structure => ({
|
|
47
|
+
name: `${structure.name}.cs`,
|
|
48
|
+
content: generateInterface(structure, options.namespace),
|
|
49
|
+
})),
|
|
50
|
+
...context.enums.filter(structure => structure.name !== 'OPERATION').map((structure) => ({
|
|
51
|
+
name: `${structure.name}.cs`,
|
|
52
|
+
content: generateEnum(structure, options.namespace),
|
|
53
|
+
})),
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function generateClass(klass: Class, namespace: string) {
|
|
58
|
+
const indent = (namespace) ? "\t" : "";
|
|
59
|
+
return `${getCommentHeader()}
|
|
60
|
+
|
|
61
|
+
using Colyseus.Schema;
|
|
62
|
+
using Action = System.Action;
|
|
63
|
+
${namespace ? `\nnamespace ${namespace} {` : ""}
|
|
64
|
+
${indent}public partial class ${klass.name} : ${klass.extends} {
|
|
65
|
+
${klass.properties.map((prop) => generateProperty(prop, indent)).join("\n\n")}
|
|
66
|
+
|
|
67
|
+
${indent}\t/*
|
|
68
|
+
${indent}\t * Support for individual property change callbacks below...
|
|
69
|
+
${indent}\t */
|
|
70
|
+
|
|
71
|
+
${generateAllFieldCallbacks(klass, indent)}
|
|
72
|
+
${indent}}
|
|
73
|
+
${namespace ? "}" : ""}
|
|
74
|
+
`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function generateEnum(_enum: Enum, namespace: string) {
|
|
78
|
+
const indent = namespace ? "\t" : "";
|
|
79
|
+
return `${getCommentHeader()}
|
|
80
|
+
${namespace ? `\nnamespace ${namespace} {` : ""}
|
|
81
|
+
${indent}public struct ${_enum.name} {
|
|
82
|
+
|
|
83
|
+
${_enum.properties
|
|
84
|
+
.map((prop) => {
|
|
85
|
+
let dataType: string = "int";
|
|
86
|
+
let value: any;
|
|
87
|
+
|
|
88
|
+
if(prop.type) {
|
|
89
|
+
if(isNaN(Number(prop.type))) {
|
|
90
|
+
value = prop.type;
|
|
91
|
+
dataType = "string";
|
|
92
|
+
} else {
|
|
93
|
+
value = Number(prop.type);
|
|
94
|
+
dataType = Number.isInteger(value)? 'int': 'float';
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
value = _enum.properties.indexOf(prop);
|
|
98
|
+
}
|
|
99
|
+
return `${indent}\tpublic const ${dataType} ${prop.name} = ${value};`;
|
|
100
|
+
})
|
|
101
|
+
.join("\n")}
|
|
102
|
+
${indent}}`
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function generateProperty(prop: Property, indent: string = "") {
|
|
106
|
+
let typeArgs = `"${prop.type}"`;
|
|
107
|
+
let property = "public";
|
|
108
|
+
let langType: string;
|
|
109
|
+
let initializer = "";
|
|
110
|
+
|
|
111
|
+
if (prop.childType) {
|
|
112
|
+
const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
|
|
113
|
+
|
|
114
|
+
langType = getType(prop);
|
|
115
|
+
typeArgs += `, typeof(${langType})`;
|
|
116
|
+
|
|
117
|
+
if (!isUpcaseFirst) {
|
|
118
|
+
typeArgs += `, "${prop.childType}"`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
initializer = `new ${langType}()`;
|
|
122
|
+
|
|
123
|
+
} else {
|
|
124
|
+
langType = getType(prop);
|
|
125
|
+
initializer = `default(${langType})`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
property += ` ${langType} ${prop.name}`;
|
|
129
|
+
|
|
130
|
+
let ret = (prop.deprecated) ? `\t\t[System.Obsolete("field '${prop.name}' is deprecated.", true)]\n` : '';
|
|
131
|
+
|
|
132
|
+
return ret + `\t${indent}[Type(${prop.index}, ${typeArgs})]
|
|
133
|
+
\t${indent}${property} = ${initializer};`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function generateInterface(struct: Interface, namespace: string) {
|
|
137
|
+
const indent = (namespace) ? "\t" : "";
|
|
138
|
+
return `${getCommentHeader()}
|
|
139
|
+
|
|
140
|
+
using Colyseus.Schema;
|
|
141
|
+
${namespace ? `\nnamespace ${namespace} {` : ""}
|
|
142
|
+
${indent}public class ${struct.name} {
|
|
143
|
+
${struct.properties.map(prop => `\t${indent}public ${getType(prop)} ${prop.name};`).join("\n")}
|
|
144
|
+
${indent}}
|
|
145
|
+
${namespace ? "}" : ""}
|
|
146
|
+
`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function generateAllFieldCallbacks(klass: Class, indent: string) {
|
|
150
|
+
//
|
|
151
|
+
// TODO: improve me. It would be great to generate less boilerplate in favor
|
|
152
|
+
// of a single implementation on C# Schema class itself.
|
|
153
|
+
//
|
|
154
|
+
const eventNames: string[] = [];
|
|
155
|
+
return `${klass.properties
|
|
156
|
+
.filter(prop => !prop.deprecated) // generate only for properties that haven't been deprecated.
|
|
157
|
+
.map(prop => {
|
|
158
|
+
const eventName = `_${prop.name}Change`;
|
|
159
|
+
eventNames.push(eventName);
|
|
160
|
+
return `\t${indent}protected event PropertyChangeHandler<${getType(prop)}> ${eventName};
|
|
161
|
+
\t${indent}public Action On${capitalize(prop.name)}Change(PropertyChangeHandler<${getType(prop)}> handler) {
|
|
162
|
+
\t${indent}\tif (__callbacks == null) { __callbacks = new SchemaCallbacks(); }
|
|
163
|
+
\t${indent}\t__callbacks.AddPropertyCallback(nameof(${prop.name}));
|
|
164
|
+
\t${indent}\t${eventName} += handler;
|
|
165
|
+
\t${indent}\treturn () => {
|
|
166
|
+
\t${indent}\t\t__callbacks.RemovePropertyCallback(nameof(${prop.name}));
|
|
167
|
+
\t${indent}\t\t${eventName} -= handler;
|
|
168
|
+
\t${indent}\t};
|
|
169
|
+
\t${indent}}`;
|
|
170
|
+
}).join("\n\n")}
|
|
171
|
+
|
|
172
|
+
\t${indent}protected override void TriggerFieldChange(DataChange change) {
|
|
173
|
+
\t${indent}\tswitch (change.Field) {
|
|
174
|
+
${klass.properties.filter(prop => !prop.deprecated).map((prop, i) => {
|
|
175
|
+
return `\t${indent}\t\tcase nameof(${prop.name}): ${eventNames[i]}?.Invoke((${getType(prop)}) change.Value, (${getType(prop)}) change.PreviousValue); break;`;
|
|
176
|
+
}).join("\n")}
|
|
177
|
+
\t${indent}\t\tdefault: break;
|
|
178
|
+
\t\t${indent}}
|
|
179
|
+
\t${indent}}`;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function getChildType(prop: Property) {
|
|
183
|
+
return typeMaps[prop.childType];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function getType(prop: Property) {
|
|
187
|
+
if (prop.childType) {
|
|
188
|
+
const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
|
|
189
|
+
let type: string;
|
|
190
|
+
|
|
191
|
+
if(prop.type === "ref") {
|
|
192
|
+
type = (isUpcaseFirst)
|
|
193
|
+
? prop.childType
|
|
194
|
+
: getChildType(prop);
|
|
195
|
+
} else {
|
|
196
|
+
const containerClass = capitalize(prop.type);
|
|
197
|
+
type = (isUpcaseFirst)
|
|
198
|
+
? `${containerClass}Schema<${prop.childType}>`
|
|
199
|
+
: `${containerClass}Schema<${getChildType(prop)}>`;
|
|
200
|
+
}
|
|
201
|
+
return type;
|
|
202
|
+
|
|
203
|
+
} else {
|
|
204
|
+
return (prop.type === "array")
|
|
205
|
+
? `${typeMaps[prop.childType] || prop.childType}[]`
|
|
206
|
+
: typeMaps[prop.type];
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Class, Property, File, getCommentHeader, Context } from "../types";
|
|
2
|
+
import { GenerateOptions } from "../api";
|
|
3
|
+
|
|
4
|
+
const typeMaps = {
|
|
5
|
+
"string": "String",
|
|
6
|
+
"number": "Dynamic",
|
|
7
|
+
"boolean": "Bool",
|
|
8
|
+
"int8": "Int",
|
|
9
|
+
"uint8": "UInt",
|
|
10
|
+
"int16": "Int",
|
|
11
|
+
"uint16": "UInt",
|
|
12
|
+
"int32": "Int",
|
|
13
|
+
"uint32": "UInt",
|
|
14
|
+
"int64": "Int",
|
|
15
|
+
"uint64": "UInt",
|
|
16
|
+
"float32": "Float",
|
|
17
|
+
"float64": "Float",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const typeInitializer = {
|
|
21
|
+
"string": '""',
|
|
22
|
+
"number": "0",
|
|
23
|
+
"boolean": "false",
|
|
24
|
+
"int8": "0",
|
|
25
|
+
"uint8": "0",
|
|
26
|
+
"int16": "0",
|
|
27
|
+
"uint16": "0",
|
|
28
|
+
"int32": "0",
|
|
29
|
+
"uint32": "0",
|
|
30
|
+
"int64": "0",
|
|
31
|
+
"uint64": "0",
|
|
32
|
+
"float32": "0",
|
|
33
|
+
"float64": "0",
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function generate (context: Context, options: GenerateOptions): File[] {
|
|
37
|
+
return context.classes.map(klass => ({
|
|
38
|
+
name: klass.name + ".hx",
|
|
39
|
+
content: generateClass(klass, options.namespace, context.classes)
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getInheritanceTree(klass: Class, allClasses: Class[], includeSelf: boolean = true) {
|
|
44
|
+
let currentClass = klass;
|
|
45
|
+
let inheritanceTree: Class[] = [];
|
|
46
|
+
|
|
47
|
+
if (includeSelf) {
|
|
48
|
+
inheritanceTree.push(currentClass);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
while (currentClass.extends !== "Schema") {
|
|
52
|
+
currentClass = allClasses.find(klass => klass.name == currentClass.extends);
|
|
53
|
+
inheritanceTree.push(currentClass);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return inheritanceTree;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function generateClass(klass: Class, namespace: string, allClasses: Class[]) {
|
|
60
|
+
return `${getCommentHeader()}
|
|
61
|
+
|
|
62
|
+
${namespace ? `package ${namespace};` : ""}
|
|
63
|
+
import io.colyseus.serializer.schema.Schema;
|
|
64
|
+
import io.colyseus.serializer.schema.types.*;
|
|
65
|
+
|
|
66
|
+
class ${klass.name} extends ${klass.extends} {
|
|
67
|
+
${klass.properties.map(prop => generateProperty(prop)).join("\n")}
|
|
68
|
+
}
|
|
69
|
+
`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function generateProperty(prop: Property) {
|
|
73
|
+
let langType: string;
|
|
74
|
+
let initializer = "";
|
|
75
|
+
let typeArgs = `"${prop.type}"`;
|
|
76
|
+
|
|
77
|
+
if (prop.childType) {
|
|
78
|
+
const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
|
|
79
|
+
|
|
80
|
+
if (isUpcaseFirst) {
|
|
81
|
+
typeArgs += `, ${prop.childType}`;
|
|
82
|
+
|
|
83
|
+
} else {
|
|
84
|
+
typeArgs += `, "${prop.childType}"`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if(prop.type === "ref") {
|
|
88
|
+
langType = `${prop.childType}`;
|
|
89
|
+
initializer = `new ${prop.childType}()`;
|
|
90
|
+
|
|
91
|
+
} else if(prop.type === "array") {
|
|
92
|
+
langType = (isUpcaseFirst)
|
|
93
|
+
? `ArraySchema<${prop.childType}>`
|
|
94
|
+
: `ArraySchema<${typeMaps[prop.childType]}>`;
|
|
95
|
+
initializer = `new ${langType}()`;
|
|
96
|
+
|
|
97
|
+
} else if(prop.type === "map") {
|
|
98
|
+
langType = (isUpcaseFirst)
|
|
99
|
+
? `MapSchema<${prop.childType}>`
|
|
100
|
+
: `MapSchema<${typeMaps[prop.childType]}>`;
|
|
101
|
+
initializer = `new ${langType}()`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
} else {
|
|
105
|
+
langType = typeMaps[prop.type];
|
|
106
|
+
initializer = typeInitializer[prop.type];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return `\t@:type(${typeArgs})\n\tpublic var ${prop.name}: ${langType} = ${initializer};\n`
|
|
110
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Class, Property, File, getCommentHeader, Context } from "../types";
|
|
2
|
+
import { GenerateOptions } from "../api";
|
|
3
|
+
|
|
4
|
+
const typeMaps = {
|
|
5
|
+
"string": "String",
|
|
6
|
+
"number": "float",
|
|
7
|
+
"boolean": "boolean",
|
|
8
|
+
"int8": "byte",
|
|
9
|
+
"uint8": "short",
|
|
10
|
+
"int16": "short",
|
|
11
|
+
"uint16": "int",
|
|
12
|
+
"int32": "int",
|
|
13
|
+
"uint32": "long",
|
|
14
|
+
"int64": "long",
|
|
15
|
+
"uint64": "long",
|
|
16
|
+
"float32": "float",
|
|
17
|
+
"float64": "double",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const typeInitializer = {
|
|
21
|
+
"string": '""',
|
|
22
|
+
"number": "0",
|
|
23
|
+
"boolean": "false",
|
|
24
|
+
"int8": "0",
|
|
25
|
+
"uint8": "0",
|
|
26
|
+
"int16": "0",
|
|
27
|
+
"uint16": "0",
|
|
28
|
+
"int32": "0",
|
|
29
|
+
"uint32": "0",
|
|
30
|
+
"int64": "0",
|
|
31
|
+
"uint64": "0",
|
|
32
|
+
"float32": "0",
|
|
33
|
+
"float64": "0",
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* C# Code Generator
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
export function generate (context: Context, options: GenerateOptions): File[] {
|
|
41
|
+
return context.classes.map(klass => ({
|
|
42
|
+
name: klass.name + ".java",
|
|
43
|
+
content: generateClass(klass, options.namespace)
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function generateClass(klass: Class, namespace: string) {
|
|
48
|
+
const indent = (namespace) ? "\t" : "";
|
|
49
|
+
return `${getCommentHeader()}
|
|
50
|
+
${namespace ? `\npackage ${namespace};` : ""}
|
|
51
|
+
|
|
52
|
+
import io.colyseus.serializer.schema.Schema;
|
|
53
|
+
import io.colyseus.serializer.schema.annotations.SchemaClass;
|
|
54
|
+
import io.colyseus.serializer.schema.annotations.SchemaField;
|
|
55
|
+
|
|
56
|
+
@SchemaClass
|
|
57
|
+
${indent}public class ${klass.name} extends ${klass.extends} {
|
|
58
|
+
${klass.properties.map(prop => generateProperty(prop, indent)).join("\n\n")}
|
|
59
|
+
${indent}}
|
|
60
|
+
${namespace ? "}" : ""}
|
|
61
|
+
`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function generateProperty(prop: Property, indent: string = "") {
|
|
65
|
+
let typeArgs = `${prop.index}/${prop.type}`;
|
|
66
|
+
let property = "public";
|
|
67
|
+
let langType: string;
|
|
68
|
+
let ctorArgs: string = "";
|
|
69
|
+
let initializer = "";
|
|
70
|
+
|
|
71
|
+
if (prop.childType) {
|
|
72
|
+
const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
|
|
73
|
+
|
|
74
|
+
if (prop.type !== "ref" && isUpcaseFirst) {
|
|
75
|
+
ctorArgs = `${prop.childType}.class`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if(prop.type === "ref") {
|
|
79
|
+
langType = (isUpcaseFirst)
|
|
80
|
+
? prop.childType
|
|
81
|
+
: typeMaps[prop.childType];
|
|
82
|
+
|
|
83
|
+
initializer = `new ${langType}${(prop.type !== "ref" && isUpcaseFirst) ? "<>" : ""}(${ctorArgs})`;
|
|
84
|
+
|
|
85
|
+
} else if(prop.type === "array") {
|
|
86
|
+
langType = (isUpcaseFirst)
|
|
87
|
+
? `ArraySchema<${prop.childType}>`
|
|
88
|
+
: `ArraySchema`;
|
|
89
|
+
|
|
90
|
+
initializer = `new ArraySchema${(isUpcaseFirst) ? "<>" : ""}(${ctorArgs})`;
|
|
91
|
+
|
|
92
|
+
} else if(prop.type === "map") {
|
|
93
|
+
langType = (isUpcaseFirst)
|
|
94
|
+
? `MapSchema<${prop.childType}>`
|
|
95
|
+
: `MapSchema`;
|
|
96
|
+
|
|
97
|
+
initializer = `new MapSchema${(isUpcaseFirst) ? "<>" : ""}(${ctorArgs})`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (prop.type !== "ref") {
|
|
101
|
+
typeArgs += (isUpcaseFirst)
|
|
102
|
+
? `/ref`
|
|
103
|
+
: `/${prop.childType}`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
} else {
|
|
107
|
+
langType = typeMaps[prop.type];
|
|
108
|
+
initializer = typeInitializer[prop.type];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
property += ` ${langType} ${prop.name}`;
|
|
112
|
+
|
|
113
|
+
return `\t@SchemaField("${typeArgs}")\t${indent}
|
|
114
|
+
\t${indent}${property} = ${initializer};`
|
|
115
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Class, Property, File, getCommentHeader, getInheritanceTree, Context } from "../types";
|
|
2
|
+
import { GenerateOptions } from "../api";
|
|
3
|
+
|
|
4
|
+
const typeMaps = {
|
|
5
|
+
"string": "string",
|
|
6
|
+
"number": "number",
|
|
7
|
+
"boolean": "boolean",
|
|
8
|
+
"int8": "number",
|
|
9
|
+
"uint8": "number",
|
|
10
|
+
"int16": "number",
|
|
11
|
+
"uint16": "number",
|
|
12
|
+
"int32": "number",
|
|
13
|
+
"uint32": "number",
|
|
14
|
+
"int64": "number",
|
|
15
|
+
"uint64": "number",
|
|
16
|
+
"float32": "number",
|
|
17
|
+
"float64": "number",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const distinct = (value, index, self) => self.indexOf(value) === index;
|
|
21
|
+
|
|
22
|
+
export function generate (context: Context, options: GenerateOptions): File[] {
|
|
23
|
+
return context.classes.map(klass => ({
|
|
24
|
+
name: klass.name + ".js",
|
|
25
|
+
content: generateClass(klass, options.namespace, context.classes)
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function generateClass(klass: Class, namespace: string, allClasses: Class[]) {
|
|
30
|
+
const allRefs: Property[] = [];
|
|
31
|
+
klass.properties.forEach(property => {
|
|
32
|
+
let type = property.type;
|
|
33
|
+
|
|
34
|
+
// keep all refs list
|
|
35
|
+
if ((type === "ref" || type === "array" || type === "map")) {
|
|
36
|
+
allRefs.push(property);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return `${getCommentHeader()}
|
|
41
|
+
|
|
42
|
+
const schema = require("@colyseus/schema");
|
|
43
|
+
const Schema = schema.Schema;
|
|
44
|
+
const type = schema.type;
|
|
45
|
+
${allRefs.
|
|
46
|
+
filter(ref => ref.childType && typeMaps[ref.childType] === undefined).
|
|
47
|
+
map(ref => ref.childType).
|
|
48
|
+
concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name)).
|
|
49
|
+
filter(distinct).
|
|
50
|
+
map(childType => `const ${childType} = require("./${childType}");`).
|
|
51
|
+
join("\n")}
|
|
52
|
+
|
|
53
|
+
class ${klass.name} extends ${klass.extends} {
|
|
54
|
+
constructor () {
|
|
55
|
+
super();
|
|
56
|
+
${klass.properties.
|
|
57
|
+
filter(prop => prop.childType !== undefined).
|
|
58
|
+
map(prop => " " + generatePropertyInitializer(prop)).join("\n")}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
${klass.properties.map(prop => generatePropertyDeclaration(klass.name, prop)).join("\n")}
|
|
62
|
+
|
|
63
|
+
export default ${klass.name};
|
|
64
|
+
`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function generatePropertyDeclaration(className: string, prop: Property) {
|
|
68
|
+
let typeArgs: string;
|
|
69
|
+
|
|
70
|
+
if (prop.childType) {
|
|
71
|
+
const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
|
|
72
|
+
|
|
73
|
+
if (isUpcaseFirst) {
|
|
74
|
+
typeArgs += `, ${prop.childType}`;
|
|
75
|
+
|
|
76
|
+
} else {
|
|
77
|
+
typeArgs += `, "${prop.childType}"`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if(prop.type === "ref") {
|
|
81
|
+
typeArgs = `${prop.childType}`;
|
|
82
|
+
|
|
83
|
+
} else if(prop.type === "array") {
|
|
84
|
+
typeArgs = (isUpcaseFirst)
|
|
85
|
+
? `[ ${prop.childType} ]`
|
|
86
|
+
: `[ "${prop.childType}" ]`;
|
|
87
|
+
|
|
88
|
+
} else if(prop.type === "map") {
|
|
89
|
+
typeArgs = (isUpcaseFirst)
|
|
90
|
+
? `{ map: ${prop.childType} }`
|
|
91
|
+
: `{ map: "${prop.childType}" }`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
} else {
|
|
95
|
+
typeArgs = `"${prop.type}"`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return `type(${typeArgs})(${className}.prototype, "${prop.name}");`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function generatePropertyInitializer(prop: Property) {
|
|
102
|
+
let initializer = "";
|
|
103
|
+
|
|
104
|
+
if(prop.type === "ref") {
|
|
105
|
+
initializer = `new ${prop.childType}()`;
|
|
106
|
+
|
|
107
|
+
} else if(prop.type === "array") {
|
|
108
|
+
initializer = `new schema.ArraySchema()`;
|
|
109
|
+
|
|
110
|
+
} else if(prop.type === "map") {
|
|
111
|
+
initializer = `new schema.MapSchema()`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return `this.${prop.name} = ${initializer}`;
|
|
115
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { Class, Property, File, getCommentHeader, getInheritanceTree, Context } from "../types";
|
|
2
|
+
import { GenerateOptions } from "../api";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
TODO:
|
|
6
|
+
- Support inheritance
|
|
7
|
+
- Support importing Schema dependencies
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const typeMaps = {
|
|
11
|
+
"string": "string",
|
|
12
|
+
"number": "number",
|
|
13
|
+
"boolean": "boolean",
|
|
14
|
+
"int8": "number",
|
|
15
|
+
"uint8": "number",
|
|
16
|
+
"int16": "number",
|
|
17
|
+
"uint16": "number",
|
|
18
|
+
"int32": "number",
|
|
19
|
+
"uint32": "number",
|
|
20
|
+
"int64": "number",
|
|
21
|
+
"uint64": "number",
|
|
22
|
+
"float32": "number",
|
|
23
|
+
"float64": "number",
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const distinct = (value, index, self) => self.indexOf(value) === index;
|
|
27
|
+
|
|
28
|
+
export function generate (context: Context, options: GenerateOptions): File[] {
|
|
29
|
+
return context.classes.map(klass => ({
|
|
30
|
+
name: klass.name + ".lua",
|
|
31
|
+
content: generateClass(klass, options.namespace, context.classes)
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function generateClass(klass: Class, namespace: string, allClasses: Class[]) {
|
|
36
|
+
const allRefs: Property[] = [];
|
|
37
|
+
klass.properties.forEach(property => {
|
|
38
|
+
let type = property.type;
|
|
39
|
+
|
|
40
|
+
// keep all refs list
|
|
41
|
+
if ((type === "ref" || type === "array" || type === "map")) {
|
|
42
|
+
allRefs.push(property);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// TOOD: inheritance
|
|
47
|
+
|
|
48
|
+
return `${getCommentHeader().replace(/\/\//mg, "--")}
|
|
49
|
+
|
|
50
|
+
local schema = require 'colyseus.serialization.schema.schema'
|
|
51
|
+
${allRefs.
|
|
52
|
+
filter(ref => ref.childType && typeMaps[ref.childType] === undefined).
|
|
53
|
+
map(ref => ref.childType).
|
|
54
|
+
concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name)).
|
|
55
|
+
filter(distinct).
|
|
56
|
+
map(childType => `local ${childType} = require '${(namespace ? `${namespace}.` : '')}${childType}'`).
|
|
57
|
+
join("\n")}
|
|
58
|
+
|
|
59
|
+
local ${klass.name} = schema.define({
|
|
60
|
+
${klass.properties.map(prop => generatePropertyDeclaration(prop)).join(",\n")},
|
|
61
|
+
["_fields_by_index"] = { ${klass.properties.map(prop => `"${prop.name}"`).join(", ")} },
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
return ${klass.name}
|
|
65
|
+
`;
|
|
66
|
+
|
|
67
|
+
// ["on_change"] = function(changes)
|
|
68
|
+
// -- on change logic here
|
|
69
|
+
// end,
|
|
70
|
+
|
|
71
|
+
// ["on_add"] = function()
|
|
72
|
+
// -- on add logic here
|
|
73
|
+
// end,
|
|
74
|
+
|
|
75
|
+
// ["on_remove"] = function()
|
|
76
|
+
// -- on remove logic here
|
|
77
|
+
// end,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function generatePropertyDeclaration(prop: Property) {
|
|
81
|
+
let typeArgs: string;
|
|
82
|
+
|
|
83
|
+
if (prop.childType) {
|
|
84
|
+
const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
|
|
85
|
+
|
|
86
|
+
if (isUpcaseFirst) {
|
|
87
|
+
typeArgs += `${prop.childType}`;
|
|
88
|
+
|
|
89
|
+
} else {
|
|
90
|
+
typeArgs += `"${prop.childType}"`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if(prop.type === "ref") {
|
|
94
|
+
typeArgs = (isUpcaseFirst)
|
|
95
|
+
? `${prop.childType}`
|
|
96
|
+
: `"${prop.childType}"`;
|
|
97
|
+
|
|
98
|
+
} else {
|
|
99
|
+
typeArgs = (isUpcaseFirst)
|
|
100
|
+
? `{ ${prop.type} = ${prop.childType} }`
|
|
101
|
+
: `{ ${prop.type} = "${prop.childType}" }`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
} else {
|
|
105
|
+
typeArgs = `"${prop.type}"`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return ` ["${prop.name}"] = ${typeArgs}`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// function generatePropertyInitializer(prop: Property) {
|
|
112
|
+
// let initializer = "";
|
|
113
|
+
|
|
114
|
+
// if(prop.type === "ref") {
|
|
115
|
+
// initializer = `new ${prop.childType}()`;
|
|
116
|
+
|
|
117
|
+
// } else if(prop.type === "array") {
|
|
118
|
+
// initializer = `new schema.ArraySchema()`;
|
|
119
|
+
|
|
120
|
+
// } else if(prop.type === "map") {
|
|
121
|
+
// initializer = `new schema.MapSchema()`;
|
|
122
|
+
// }
|
|
123
|
+
|
|
124
|
+
// return `this.${prop.name} = ${initializer}`;
|
|
125
|
+
// }
|