@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.
Files changed (107) hide show
  1. package/README.md +0 -4
  2. package/build/cjs/index.js +48 -48
  3. package/build/cjs/index.js.map +1 -1
  4. package/build/esm/index.mjs +130 -104
  5. package/build/esm/index.mjs.map +1 -1
  6. package/build/umd/index.js +50 -50
  7. package/lib/Reflection.js +87 -119
  8. package/lib/Reflection.js.map +1 -1
  9. package/lib/Schema.js +195 -257
  10. package/lib/Schema.js.map +1 -1
  11. package/lib/annotations.d.ts +6 -6
  12. package/lib/annotations.js +64 -92
  13. package/lib/annotations.js.map +1 -1
  14. package/lib/changes/ChangeTree.d.ts +1 -1
  15. package/lib/changes/ChangeTree.js +63 -70
  16. package/lib/changes/ChangeTree.js.map +1 -1
  17. package/lib/changes/ReferenceTracker.js +24 -27
  18. package/lib/changes/ReferenceTracker.js.map +1 -1
  19. package/lib/codegen/api.js +9 -9
  20. package/lib/codegen/api.js.map +1 -1
  21. package/lib/codegen/argv.d.ts +1 -1
  22. package/lib/codegen/argv.js +11 -11
  23. package/lib/codegen/argv.js.map +1 -1
  24. package/lib/codegen/cli.js +21 -10
  25. package/lib/codegen/cli.js.map +1 -1
  26. package/lib/codegen/languages/cpp.js +126 -77
  27. package/lib/codegen/languages/cpp.js.map +1 -1
  28. package/lib/codegen/languages/csharp.js +121 -62
  29. package/lib/codegen/languages/csharp.js.map +1 -1
  30. package/lib/codegen/languages/haxe.js +34 -26
  31. package/lib/codegen/languages/haxe.js.map +1 -1
  32. package/lib/codegen/languages/java.js +39 -27
  33. package/lib/codegen/languages/java.js.map +1 -1
  34. package/lib/codegen/languages/js.js +48 -32
  35. package/lib/codegen/languages/js.js.map +1 -1
  36. package/lib/codegen/languages/lua.js +35 -24
  37. package/lib/codegen/languages/lua.js.map +1 -1
  38. package/lib/codegen/languages/ts.js +63 -68
  39. package/lib/codegen/languages/ts.js.map +1 -1
  40. package/lib/codegen/parser.d.ts +9 -1
  41. package/lib/codegen/parser.js +88 -46
  42. package/lib/codegen/parser.js.map +1 -1
  43. package/lib/codegen/types.d.ts +8 -0
  44. package/lib/codegen/types.js +64 -54
  45. package/lib/codegen/types.js.map +1 -1
  46. package/lib/encoding/decode.js +15 -15
  47. package/lib/encoding/decode.js.map +1 -1
  48. package/lib/encoding/encode.js +14 -14
  49. package/lib/encoding/encode.js.map +1 -1
  50. package/lib/events/EventEmitter.d.ts +1 -1
  51. package/lib/events/EventEmitter.js +16 -47
  52. package/lib/events/EventEmitter.js.map +1 -1
  53. package/lib/filters/index.js +7 -8
  54. package/lib/filters/index.js.map +1 -1
  55. package/lib/index.js +11 -11
  56. package/lib/index.js.map +1 -1
  57. package/lib/types/ArraySchema.d.ts +1 -1
  58. package/lib/types/ArraySchema.js +161 -219
  59. package/lib/types/ArraySchema.js.map +1 -1
  60. package/lib/types/CollectionSchema.d.ts +1 -1
  61. package/lib/types/CollectionSchema.js +63 -71
  62. package/lib/types/CollectionSchema.js.map +1 -1
  63. package/lib/types/HelperTypes.d.ts +9 -9
  64. package/lib/types/MapSchema.d.ts +16 -16
  65. package/lib/types/MapSchema.js +68 -78
  66. package/lib/types/MapSchema.js.map +1 -1
  67. package/lib/types/SetSchema.js +62 -71
  68. package/lib/types/SetSchema.js.map +1 -1
  69. package/lib/types/index.js +1 -1
  70. package/lib/types/index.js.map +1 -1
  71. package/lib/types/typeRegistry.js +1 -1
  72. package/lib/types/typeRegistry.js.map +1 -1
  73. package/lib/types/utils.js +9 -10
  74. package/lib/types/utils.js.map +1 -1
  75. package/lib/utils.js +10 -13
  76. package/lib/utils.js.map +1 -1
  77. package/package.json +18 -15
  78. package/src/Reflection.ts +159 -0
  79. package/src/Schema.ts +1024 -0
  80. package/src/annotations.ts +400 -0
  81. package/src/changes/ChangeTree.ts +295 -0
  82. package/src/changes/ReferenceTracker.ts +81 -0
  83. package/src/codegen/api.ts +46 -0
  84. package/src/codegen/argv.ts +40 -0
  85. package/src/codegen/cli.ts +65 -0
  86. package/src/codegen/languages/cpp.ts +297 -0
  87. package/src/codegen/languages/csharp.ts +208 -0
  88. package/src/codegen/languages/haxe.ts +110 -0
  89. package/src/codegen/languages/java.ts +115 -0
  90. package/src/codegen/languages/js.ts +115 -0
  91. package/src/codegen/languages/lua.ts +125 -0
  92. package/src/codegen/languages/ts.ts +129 -0
  93. package/src/codegen/parser.ts +299 -0
  94. package/src/codegen/types.ts +177 -0
  95. package/src/encoding/decode.ts +278 -0
  96. package/src/encoding/encode.ts +283 -0
  97. package/src/filters/index.ts +23 -0
  98. package/src/index.ts +59 -0
  99. package/src/spec.ts +49 -0
  100. package/src/types/ArraySchema.ts +612 -0
  101. package/src/types/CollectionSchema.ts +199 -0
  102. package/src/types/HelperTypes.ts +34 -0
  103. package/src/types/MapSchema.ts +268 -0
  104. package/src/types/SetSchema.ts +208 -0
  105. package/src/types/typeRegistry.ts +19 -0
  106. package/src/types/utils.ts +62 -0
  107. package/src/utils.ts +28 -0
@@ -0,0 +1,81 @@
1
+ import { Schema } from "../Schema";
2
+ import { Ref } from "./ChangeTree";
3
+ import type { SchemaDefinition } from "../annotations";
4
+
5
+ export class ReferenceTracker {
6
+ //
7
+ // Relation of refId => Schema structure
8
+ // For direct access of structures during decoding time.
9
+ //
10
+ public refs = new Map<number, Ref>();
11
+ public refCounts: { [refId: number]: number; } = {};
12
+ public deletedRefs = new Set<number>();
13
+
14
+ protected nextUniqueId: number = 0;
15
+
16
+ getNextUniqueId() {
17
+ return this.nextUniqueId++;
18
+ }
19
+
20
+ // for decoding
21
+ addRef(refId: number, ref: Ref, incrementCount: boolean = true) {
22
+ this.refs.set(refId, ref);
23
+
24
+ if (incrementCount) {
25
+ this.refCounts[refId] = (this.refCounts[refId] || 0) + 1;
26
+ }
27
+ }
28
+
29
+ // for decoding
30
+ removeRef(refId) {
31
+ this.refCounts[refId] = this.refCounts[refId] - 1;
32
+ this.deletedRefs.add(refId);
33
+ }
34
+
35
+ clearRefs() {
36
+ this.refs.clear();
37
+ this.deletedRefs.clear();
38
+ this.refCounts = {};
39
+ }
40
+
41
+ // for decoding
42
+ garbageCollectDeletedRefs() {
43
+ this.deletedRefs.forEach((refId) => {
44
+ //
45
+ // Skip active references.
46
+ //
47
+ if (this.refCounts[refId] > 0) { return; }
48
+
49
+ const ref = this.refs.get(refId);
50
+
51
+ //
52
+ // Ensure child schema instances have their references removed as well.
53
+ //
54
+ if (ref instanceof Schema) {
55
+ for (const fieldName in ref['_definition'].schema) {
56
+ if (typeof (ref['_definition'].schema[fieldName]) !== "string" &&
57
+ ref[fieldName] &&
58
+ ref[fieldName]['$changes']) {
59
+ this.removeRef(ref[fieldName]['$changes'].refId);
60
+ }
61
+ }
62
+
63
+ } else {
64
+ const definition: SchemaDefinition = ref['$changes'].parent._definition;
65
+ const type = definition.schema[definition.fieldsByIndex[ref['$changes'].parentIndex]];
66
+
67
+ if (typeof (Object.values(type)[0]) === "function") {
68
+ Array.from(ref.values())
69
+ .forEach((child) => this.removeRef(child['$changes'].refId));
70
+ }
71
+ }
72
+
73
+ this.refs.delete(refId);
74
+ delete this.refCounts[refId];
75
+ });
76
+
77
+ // clear deleted refs.
78
+ this.deletedRefs.clear();
79
+ }
80
+
81
+ }
@@ -0,0 +1,46 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+
4
+ import { File } from "./types";
5
+ import { parseFiles } from "./parser";
6
+
7
+ export interface GenerateOptions {
8
+ files: string[],
9
+ output: string;
10
+ decorator?: string;
11
+ namespace?: string;
12
+ }
13
+
14
+ export function generate(targetId: string, options: GenerateOptions) {
15
+ let generator: Function;
16
+
17
+ try {
18
+ generator = require('./languages/' + targetId).generate;
19
+
20
+ } catch (e) {
21
+ throw new Error("You must provide a valid generator as argument, such as: --csharp, --haxe or --cpp");
22
+ }
23
+
24
+ if (!fs.existsSync(options.output)) {
25
+ console.log("Creating", options.output, "directory");
26
+ fs.mkdirSync(options.output);
27
+ }
28
+
29
+ /**
30
+ * Default `@type()` decorator name
31
+ */
32
+ if (!options.decorator) { options.decorator = "type"; }
33
+
34
+ const structures = parseFiles(options.files, options.decorator);
35
+
36
+ // Post-process classes before generating
37
+ structures.classes.forEach(klass => klass.postProcessing());
38
+
39
+ const files = generator(structures, options);
40
+
41
+ files.forEach((file: File) => {
42
+ const outputPath = path.resolve(options.output, file.name);
43
+ fs.writeFileSync(outputPath, file.content);
44
+ console.log("generated:", file.name);
45
+ });
46
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @author Ethan Davis
3
+ * https://github.com/ethanent/gar
4
+ */
5
+ export default (sargs): any => {
6
+ let props = {}
7
+ let lones = []
8
+
9
+ const convertIfApplicable = (value) => (isNaN(value) ? (value.toString().toLowerCase() === 'true' ? true : (value.toString().toLowerCase() === 'false' ? false : value)) : Number(value))
10
+ const removeStartHyphens = (value) => value.replace(/^\-+/g, '')
11
+
12
+ for (let i = 0; i < sargs.length; i++) {
13
+ const equalsIndex = sargs[i].indexOf('=')
14
+ const isNextRefProp = sargs[i].charAt(0) === '-' && sargs.length - 1 >= i + 1 && sargs[i + 1].indexOf('=') === -1 && sargs[i + 1].charAt(0) !== '-'
15
+ const argName = equalsIndex === -1 ? removeStartHyphens(sargs[i]) : removeStartHyphens(sargs[i].slice(0, equalsIndex))
16
+
17
+ if (equalsIndex !== -1) {
18
+ props[argName] = convertIfApplicable(sargs[i].slice(equalsIndex + 1))
19
+ }
20
+ else if (isNextRefProp) {
21
+ props[argName] = convertIfApplicable(sargs[i + 1])
22
+ i++
23
+ } else if (sargs[i].charAt(0) === '-') {
24
+ if (sargs[i].charAt(1) === '-') {
25
+ props[argName] = true
26
+ }
27
+ else {
28
+ for (let b = 0; b < argName.length; b++) {
29
+ props[argName.charAt(b)] = true
30
+ }
31
+ }
32
+ } else {
33
+ lones.push(convertIfApplicable(argName))
34
+ }
35
+ }
36
+
37
+ return Object.assign(props, {
38
+ '_': lones
39
+ })
40
+ }
@@ -0,0 +1,65 @@
1
+ import argv from "./argv";
2
+ import { generate } from "./api";
3
+
4
+ const supportedTargets = {
5
+ csharp: 'generate for C#/Unity',
6
+ cpp: 'generate for C++',
7
+ haxe: 'generate for Haxe',
8
+ ts: 'generate for TypeScript',
9
+ js: 'generate for JavaScript',
10
+ java: 'generate for Java',
11
+ lua: 'generate for LUA',
12
+ }
13
+
14
+ function displayHelp() {
15
+ console.log(`\nschema-codegen [path/to/Schema.ts]
16
+
17
+ Usage (C#/Unity)
18
+ schema-codegen src/Schema.ts --output client-side/ --csharp --namespace MyGame.Schema
19
+
20
+ Valid options:
21
+ --output: the output directory for generated client-side schema files
22
+ ${Object.
23
+ keys(supportedTargets).
24
+ map((targetId) => (
25
+ ` --${targetId}: ${supportedTargets[targetId]}`
26
+ )).
27
+ join("\n")}
28
+
29
+ Optional:
30
+ --namespace: generate namespace on output code
31
+ --decorator: custom name for @type decorator to scan for`);
32
+ process.exit();
33
+ }
34
+
35
+ const args = argv(process.argv.slice(2));
36
+ if (args.help) {
37
+ displayHelp();
38
+ }
39
+
40
+ let targetId: string;
41
+ for (let target in supportedTargets) {
42
+ if (args[target]) {
43
+ targetId = target;
44
+ }
45
+ }
46
+
47
+ if (!args.output) {
48
+ console.error("You must provide a valid --output directory.");
49
+ displayHelp();
50
+ }
51
+
52
+ try {
53
+ args.files = args._;
54
+ generate(targetId, {
55
+ files: args._,
56
+ decorator: args.decorator,
57
+ output: args.output,
58
+ namespace: args.namespace
59
+ });
60
+
61
+ } catch (e) {
62
+ console.error(e.message);
63
+ console.error(e.stack);
64
+ displayHelp();
65
+ }
@@ -0,0 +1,297 @@
1
+ import { Class, Property, File, getCommentHeader, getInheritanceTree, Context } from "../types";
2
+ import { GenerateOptions } from "../api";
3
+
4
+ const typeMaps = {
5
+ "string": "string",
6
+ "number": "varint_t",
7
+ "boolean": "bool",
8
+ "int8": "int8_t",
9
+ "uint8": "uint8_t",
10
+ "int16": "int16_t",
11
+ "uint16": "uint16_t",
12
+ "int32": "int32_t",
13
+ "uint32": "uint32_t",
14
+ "int64": "int64_t",
15
+ "uint64": "uint64_t",
16
+ "float32": "float32_t",
17
+ "float64": "float64_t",
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
+ const capitalize = (s) => {
41
+ if (typeof s !== 'string') return ''
42
+ return s.charAt(0).toUpperCase() + s.slice(1);
43
+ }
44
+ const distinct = (value, index, self) => self.indexOf(value) === index;
45
+
46
+ export function generate (context: Context, options: GenerateOptions): File[] {
47
+ return context.classes.map(klass => ({
48
+ name: klass.name + ".hpp",
49
+ content: generateClass(klass, options.namespace, context.classes)
50
+ }));
51
+ }
52
+
53
+ function generateClass(klass: Class, namespace: string, allClasses: Class[]) {
54
+ const propertiesPerType: {[type: string]: Property[]} = {};
55
+ const allRefs: Property[] = [];
56
+ klass.properties.forEach(property => {
57
+ let type = property.type;
58
+
59
+ if (!propertiesPerType[type]) {
60
+ propertiesPerType[type] = [];
61
+ }
62
+
63
+ propertiesPerType[type].push(property);
64
+
65
+ // keep all refs list
66
+ if ((type === "ref" || type === "array" || type === "map")) {
67
+ allRefs.push(property);
68
+ }
69
+ });
70
+
71
+ const allProperties = getAllProperties(klass, allClasses);
72
+ const createInstanceMethod = (allRefs.length === 0) ? "" :
73
+ `\tinline Schema* createInstance(std::type_index type) {
74
+ \t\t${generateFieldIfElseChain(allRefs,
75
+ (property) => `type == typeid(${property.childType})`,
76
+ (property) => `return new ${property.childType}();`,
77
+ (property) => typeMaps[property.childType] === undefined)}
78
+ \t\treturn ${klass.extends}::createInstance(type);
79
+ \t}`;
80
+
81
+ return `${getCommentHeader()}
82
+ #ifndef __SCHEMA_CODEGEN_${klass.name.toUpperCase()}_H__
83
+ #define __SCHEMA_CODEGEN_${klass.name.toUpperCase()}_H__ 1
84
+
85
+ #include "schema.h"
86
+ #include <typeinfo>
87
+ #include <typeindex>
88
+
89
+ ${allRefs.
90
+ filter(ref => ref.childType && typeMaps[ref.childType] === undefined).
91
+ map(ref => ref.childType).
92
+ concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name)).
93
+ filter(distinct).
94
+ map(childType => `#include "${childType}.hpp"`).
95
+ join("\n")}
96
+
97
+ using namespace colyseus::schema;
98
+
99
+ ${namespace ? `namespace ${namespace} {` : ""}
100
+ class ${klass.name} : public ${klass.extends} {
101
+ public:
102
+ ${klass.properties.map(prop => generateProperty(prop)).join("\n")}
103
+
104
+ \t${klass.name}() {
105
+ \t\tthis->_indexes = ${generateAllIndexes(allProperties)};
106
+ \t\tthis->_types = ${generateAllTypes(allProperties)};
107
+ \t\tthis->_childPrimitiveTypes = ${generateAllChildPrimitiveTypes(allProperties)};
108
+ \t\tthis->_childSchemaTypes = ${generateAllChildSchemaTypes(allProperties)};
109
+ \t}
110
+
111
+ \tvirtual ~${klass.name}() {
112
+ \t\t${generateDestructors(allProperties).join("\n\t\t")}
113
+ \t}
114
+
115
+ protected:
116
+ ${Object.keys(propertiesPerType).map(type =>
117
+ generateGettersAndSetters(klass, type, propertiesPerType[type])).
118
+ join("\n")}
119
+
120
+ ${createInstanceMethod}
121
+ };
122
+ ${namespace ? "}" : ""}
123
+
124
+ #endif
125
+ `;
126
+ }
127
+
128
+ function generateProperty(prop: Property) {
129
+ let property = "";
130
+ let langType: string;
131
+ let initializer = "";
132
+ let isPropPointer = "";
133
+
134
+ if (prop.childType) {
135
+ const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
136
+
137
+ if(prop.type === "ref") {
138
+ langType = `${prop.childType}`;
139
+ initializer = `new ${prop.childType}()`;
140
+
141
+ } else if(prop.type === "array") {
142
+ langType = (isUpcaseFirst)
143
+ ? `ArraySchema<${prop.childType}*>`
144
+ : `ArraySchema<${typeMaps[prop.childType]}>`;
145
+ initializer = `new ${langType}()`;
146
+
147
+ } else if(prop.type === "map") {
148
+ langType = (isUpcaseFirst)
149
+ ? `MapSchema<${prop.childType}*>`
150
+ : `MapSchema<${typeMaps[prop.childType]}>`;
151
+ initializer = `new ${langType}()`;
152
+ }
153
+ isPropPointer = "*";
154
+
155
+ } else {
156
+ langType = typeMaps[prop.type];
157
+ initializer = typeInitializer[prop.type];
158
+ }
159
+
160
+ property += ` ${langType} ${isPropPointer}${prop.name}`;
161
+
162
+ return `\t${property} = ${initializer};`
163
+ }
164
+
165
+ function generateGettersAndSetters(klass: Class, type: string, properties: Property[]) {
166
+ let langType = typeMaps[type];
167
+ let typeCast = "";
168
+
169
+ const getMethodName = `get${capitalize(type)}`;
170
+ const setMethodName = `set${capitalize(type)}`;
171
+
172
+ if (type === "ref") {
173
+ langType = "Schema*";
174
+
175
+ } else if (type === "array") {
176
+ langType = `ArraySchema<char*> *`;
177
+ typeCast = `(ArraySchema<char*> *)`;
178
+
179
+ } else if (type === "map") {
180
+ langType = `MapSchema<char*> *`;
181
+ typeCast = `(MapSchema<char*> *)`;
182
+ }
183
+
184
+ return `\tinline ${langType} ${getMethodName}(const string &field)
185
+ \t{
186
+ \t\t${generateFieldIfElseChain(properties,
187
+ (property) => `field == "${property.name}"`,
188
+ (property) => `return ${typeCast}this->${property.name};`)}
189
+ \t\treturn ${klass.extends}::${getMethodName}(field);
190
+ \t}
191
+
192
+ \tinline void ${setMethodName}(const string &field, ${langType} value)
193
+ \t{
194
+ \t\t${generateFieldIfElseChain(properties,
195
+ (property) => `field == "${property.name}"`,
196
+ (property) => {
197
+ const isSchemaType = (typeMaps[property.childType] === undefined)
198
+
199
+ if (type === "ref") {
200
+ langType = `${property.childType}*`;
201
+ typeCast = (isSchemaType)
202
+ ? `(${property.childType}*)`
203
+ : `/* bug? */`;
204
+
205
+ } else if (type === "array") {
206
+ typeCast = (isSchemaType)
207
+ ? `(ArraySchema<${property.childType}*> *)`
208
+ : `(ArraySchema<${typeMaps[property.childType]}> *)`;
209
+
210
+ } else if (type === "map") {
211
+ typeCast = (isSchemaType)
212
+ ? `(MapSchema<${property.childType}*> *)`
213
+ : `(MapSchema<${typeMaps[property.childType]}> *)`;
214
+ }
215
+
216
+ return `this->${property.name} = ${typeCast}value;\n\t\t\treturn;`
217
+ })}
218
+ \t\treturn ${klass.extends}::${setMethodName}(field, value);
219
+ \t}`;
220
+ }
221
+
222
+ function generateFieldIfElseChain(
223
+ properties: Property[],
224
+ ifCallback: (property: Property) => string,
225
+ callback: (property: Property) => string,
226
+ filter: (property: Property) => boolean = (_) => true,
227
+ ) {
228
+ let chain = "";
229
+
230
+ const uniqueChecks: string[] = [];
231
+ properties.filter(filter).forEach((property, i) => {
232
+ const check = ifCallback(property);
233
+ if (uniqueChecks.indexOf(check) === -1) {
234
+ uniqueChecks.push(check);
235
+
236
+ } else {
237
+ return;
238
+ }
239
+
240
+ if (i === 0) { chain += "if " } else { chain += " else if " }
241
+ chain += `(${check})
242
+ \t\t{
243
+ \t\t\t${callback(property)}\n
244
+ \t\t}`
245
+ });
246
+
247
+ return chain;
248
+ }
249
+
250
+ function generateAllIndexes(properties: Property[]) {
251
+ return `{${properties.map((property, i) => `{${i}, "${property.name}"}`).join(", ")}}`
252
+
253
+ }
254
+
255
+ function generateAllTypes(properties: Property[]) {
256
+ return `{${properties.map((property, i) => `{${i}, "${property.type}"}`).join(", ")}}`
257
+ }
258
+
259
+ function generateAllChildSchemaTypes(properties: Property[]) {
260
+ return `{${properties.map((property, i) => {
261
+ if (property.childType && typeMaps[property.childType] === undefined) {
262
+ return `{${i}, typeid(${property.childType})}`
263
+ } else {
264
+ return null;
265
+ }
266
+ }).filter(r => r !== null).join(", ")}}`
267
+ }
268
+
269
+ function generateAllChildPrimitiveTypes(properties: Property[]) {
270
+ return `{${properties.map((property, i) => {
271
+ if (typeMaps[property.childType] !== undefined) {
272
+ return `{${i}, "${property.childType}"}`
273
+ } else {
274
+ return null;
275
+ }
276
+ }).filter(r => r !== null).join(", ")}}`
277
+ }
278
+
279
+ function generateDestructors(properties: Property[]) {
280
+ return properties.map((property, i) => {
281
+ if (property.childType) {
282
+ return `delete this->${property.name};`;
283
+ } else {
284
+ return null;
285
+ }
286
+ }).filter(r => r !== null);
287
+ }
288
+
289
+ function getAllProperties (klass: Class, allClasses: Class[]) {
290
+ let properties: Property[] = [];
291
+
292
+ getInheritanceTree(klass, allClasses).reverse().forEach((klass) => {
293
+ properties = properties.concat(klass.properties);
294
+ });
295
+
296
+ return properties;
297
+ }