@colyseus/schema 4.0.6 → 4.0.7

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.
@@ -0,0 +1,1555 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ var fs = require('fs');
5
+ var path = require('path');
6
+ var ts = require('typescript');
7
+
8
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
9
+ function _interopNamespaceDefault(e) {
10
+ var n = Object.create(null);
11
+ if (e) {
12
+ Object.keys(e).forEach(function (k) {
13
+ if (k !== 'default') {
14
+ var d = Object.getOwnPropertyDescriptor(e, k);
15
+ Object.defineProperty(n, k, d.get ? d : {
16
+ enumerable: true,
17
+ get: function () { return e[k]; }
18
+ });
19
+ }
20
+ });
21
+ }
22
+ n.default = e;
23
+ return Object.freeze(n);
24
+ }
25
+
26
+ var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
27
+ var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
28
+ var ts__namespace = /*#__PURE__*/_interopNamespaceDefault(ts);
29
+
30
+ /**
31
+ * @author Ethan Davis
32
+ * https://github.com/ethanent/gar
33
+ */
34
+ var argv = (sargs) => {
35
+ let props = {};
36
+ let lones = [];
37
+ const convertIfApplicable = (value) => (isNaN(value) ? (value.toString().toLowerCase() === 'true' ? true : (value.toString().toLowerCase() === 'false' ? false : value)) : Number(value));
38
+ const removeStartHyphens = (value) => value.replace(/^\-+/g, '');
39
+ for (let i = 0; i < sargs.length; i++) {
40
+ const equalsIndex = sargs[i].indexOf('=');
41
+ const isNextRefProp = sargs[i].charAt(0) === '-' && sargs.length - 1 >= i + 1 && sargs[i + 1].indexOf('=') === -1 && sargs[i + 1].charAt(0) !== '-';
42
+ const argName = equalsIndex === -1 ? removeStartHyphens(sargs[i]) : removeStartHyphens(sargs[i].slice(0, equalsIndex));
43
+ if (equalsIndex !== -1) {
44
+ props[argName] = convertIfApplicable(sargs[i].slice(equalsIndex + 1));
45
+ }
46
+ else if (isNextRefProp) {
47
+ props[argName] = convertIfApplicable(sargs[i + 1]);
48
+ i++;
49
+ }
50
+ else if (sargs[i].charAt(0) === '-') {
51
+ if (sargs[i].charAt(1) === '-') {
52
+ props[argName] = true;
53
+ }
54
+ else {
55
+ for (let b = 0; b < argName.length; b++) {
56
+ props[argName.charAt(b)] = true;
57
+ }
58
+ }
59
+ }
60
+ else {
61
+ lones.push(convertIfApplicable(argName));
62
+ }
63
+ }
64
+ return Object.assign(props, {
65
+ '_': lones
66
+ });
67
+ };
68
+
69
+ if (typeof (__dirname) === "undefined") {
70
+ global.__dirname = path__namespace.dirname(new URL((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.cjs', document.baseURI).href))).pathname);
71
+ }
72
+ const VERSION = JSON.parse(fs__namespace.readFileSync(__dirname + "/../../package.json").toString()).version;
73
+ const COMMENT_HEADER = `
74
+ THIS FILE HAS BEEN GENERATED AUTOMATICALLY
75
+ DO NOT CHANGE IT MANUALLY UNLESS YOU KNOW WHAT YOU'RE DOING
76
+
77
+ GENERATED USING @colyseus/schema ${VERSION}
78
+ `;
79
+ function getCommentHeader(singleLineComment = "//") {
80
+ return `${COMMENT_HEADER.split("\n").map(line => `${singleLineComment} ${line}`).join("\n")}`;
81
+ }
82
+ class Context {
83
+ classes = [];
84
+ interfaces = [];
85
+ enums = [];
86
+ getStructures() {
87
+ return {
88
+ classes: this.classes.filter(klass => {
89
+ if (this.isSchemaClass(klass)) {
90
+ return true;
91
+ }
92
+ else {
93
+ let parentClass = klass;
94
+ while (parentClass = this.getParentClass(parentClass)) {
95
+ if (this.isSchemaClass(parentClass)) {
96
+ return true;
97
+ }
98
+ }
99
+ }
100
+ return false;
101
+ }),
102
+ interfaces: this.interfaces,
103
+ enums: this.enums,
104
+ };
105
+ }
106
+ addStructure(structure) {
107
+ if (structure.context === this) {
108
+ return;
109
+ } // skip if already added.
110
+ structure.context = this;
111
+ if (structure instanceof Class) {
112
+ this.classes.push(structure);
113
+ }
114
+ else if (structure instanceof Interface) {
115
+ this.interfaces.push(structure);
116
+ }
117
+ else if (structure instanceof Enum) {
118
+ this.enums.push(structure);
119
+ }
120
+ }
121
+ getParentClass(klass) {
122
+ return this.classes.find(c => c.name === klass.extends);
123
+ }
124
+ isSchemaClass(klass) {
125
+ let isSchema = false;
126
+ let currentClass = klass;
127
+ while (!isSchema && currentClass) {
128
+ //
129
+ // TODO: ideally we should check for actual @colyseus/schema module
130
+ // reference rather than arbitrary strings.
131
+ //
132
+ isSchema = (currentClass.extends === "Schema" ||
133
+ currentClass.extends === "schema.Schema" ||
134
+ currentClass.extends === "Schema.Schema");
135
+ //
136
+ // When extending from `schema.Schema`, it is required to
137
+ // normalize as "Schema" for code generation.
138
+ //
139
+ if (currentClass === klass && isSchema) {
140
+ klass.extends = "Schema";
141
+ }
142
+ currentClass = this.getParentClass(currentClass);
143
+ }
144
+ return isSchema;
145
+ }
146
+ }
147
+ class Interface {
148
+ context;
149
+ name;
150
+ properties = [];
151
+ addProperty(property) {
152
+ if (property.type.indexOf("[]") >= 0) {
153
+ // is array!
154
+ property.childType = property.type.match(/([^\[]+)/i)[1];
155
+ property.type = "array";
156
+ this.properties.push(property);
157
+ }
158
+ else {
159
+ this.properties.push(property);
160
+ }
161
+ }
162
+ }
163
+ class Class {
164
+ context;
165
+ name;
166
+ properties = [];
167
+ extends;
168
+ addProperty(property) {
169
+ property.index = this.properties.length;
170
+ this.properties.push(property);
171
+ }
172
+ postProcessing() {
173
+ /**
174
+ * Ensure the proprierties `index` are correct using inheritance
175
+ */
176
+ let parentKlass = this;
177
+ while (parentKlass &&
178
+ (parentKlass = this.context.classes.find(k => k.name === parentKlass.extends))) {
179
+ this.properties.forEach(prop => {
180
+ prop.index += parentKlass.properties.length;
181
+ });
182
+ }
183
+ }
184
+ }
185
+ class Enum {
186
+ context;
187
+ name;
188
+ properties = [];
189
+ addProperty(property) {
190
+ this.properties.push(property);
191
+ }
192
+ }
193
+ class Property {
194
+ index;
195
+ name;
196
+ type;
197
+ childType;
198
+ deprecated;
199
+ }
200
+ function getInheritanceTree(klass, allClasses, includeSelf = true) {
201
+ let currentClass = klass;
202
+ let inheritanceTree = [];
203
+ if (includeSelf) {
204
+ inheritanceTree.push(currentClass);
205
+ }
206
+ while (currentClass.extends !== "Schema") {
207
+ currentClass = allClasses.find(klass => klass.name == currentClass.extends);
208
+ inheritanceTree.push(currentClass);
209
+ }
210
+ return inheritanceTree;
211
+ }
212
+
213
+ let currentStructure;
214
+ let currentProperty;
215
+ let globalContext;
216
+ function defineProperty(property, initializer) {
217
+ if (ts__namespace.isIdentifier(initializer)) {
218
+ property.type = "ref";
219
+ property.childType = initializer.text;
220
+ }
221
+ else if (initializer.kind == ts__namespace.SyntaxKind.ObjectLiteralExpression) {
222
+ property.type = initializer.properties[0].name.text;
223
+ property.childType = initializer.properties[0].initializer.text;
224
+ }
225
+ else if (initializer.kind == ts__namespace.SyntaxKind.ArrayLiteralExpression) {
226
+ property.type = "array";
227
+ property.childType = initializer.elements[0].text;
228
+ }
229
+ else {
230
+ property.type = initializer.text;
231
+ }
232
+ }
233
+ function inspectNode(node, context, decoratorName) {
234
+ switch (node.kind) {
235
+ case ts__namespace.SyntaxKind.ImportClause:
236
+ const specifier = node.parent.moduleSpecifier;
237
+ if (specifier && specifier.text.startsWith('.')) {
238
+ const currentDir = path__namespace.dirname(node.getSourceFile().fileName);
239
+ const pathToImport = path__namespace.resolve(currentDir, specifier.text);
240
+ parseFiles([pathToImport], decoratorName, globalContext);
241
+ }
242
+ break;
243
+ case ts__namespace.SyntaxKind.ClassDeclaration:
244
+ currentStructure = new Class();
245
+ const heritageClauses = node.heritageClauses;
246
+ if (heritageClauses && heritageClauses.length > 0) {
247
+ currentStructure.extends = heritageClauses[0].types[0].expression.getText();
248
+ }
249
+ context.addStructure(currentStructure);
250
+ break;
251
+ case ts__namespace.SyntaxKind.InterfaceDeclaration:
252
+ //
253
+ // Only generate Interfaces if it has "Message" on its name.
254
+ // Example: MyMessage
255
+ //
256
+ const interfaceName = node.name.escapedText.toString();
257
+ if (interfaceName.indexOf("Message") !== -1) {
258
+ currentStructure = new Interface();
259
+ currentStructure.name = interfaceName;
260
+ context.addStructure(currentStructure);
261
+ }
262
+ break;
263
+ case ts__namespace.SyntaxKind.EnumDeclaration:
264
+ const enumName = node.name.escapedText.toString();
265
+ currentStructure = new Enum();
266
+ currentStructure.name = enumName;
267
+ context.addStructure(currentStructure);
268
+ break;
269
+ case ts__namespace.SyntaxKind.ExtendsKeyword:
270
+ // console.log(node.getText());
271
+ break;
272
+ case ts__namespace.SyntaxKind.PropertySignature:
273
+ if (currentStructure instanceof Interface) {
274
+ const interfaceDeclaration = node.parent;
275
+ if (currentStructure.name !== interfaceDeclaration.name.escapedText.toString()) {
276
+ // skip if property if for a another interface than the one we're interested in.
277
+ break;
278
+ }
279
+ // define a property of an interface
280
+ const property = new Property();
281
+ property.name = node.name.escapedText.toString();
282
+ property.type = node.type.getText();
283
+ currentStructure.addProperty(property);
284
+ }
285
+ break;
286
+ case ts__namespace.SyntaxKind.Identifier:
287
+ if (node.getText() === "deprecated" &&
288
+ node.parent.kind !== ts__namespace.SyntaxKind.ImportSpecifier) {
289
+ currentProperty = new Property();
290
+ currentProperty.deprecated = true;
291
+ break;
292
+ }
293
+ if (node.getText() === decoratorName) {
294
+ const prop = node.parent?.parent?.parent;
295
+ const propDecorator = getDecorators(prop);
296
+ const hasExpression = prop?.expression?.arguments;
297
+ const hasDecorator = (propDecorator?.length > 0);
298
+ /**
299
+ * neither a `@type()` decorator or `type()` call. skip.
300
+ */
301
+ if (!hasDecorator && !hasExpression) {
302
+ break;
303
+ }
304
+ // using as decorator
305
+ if (propDecorator) {
306
+ /**
307
+ * Calling `@type()` as decorator
308
+ */
309
+ const typeDecorator = propDecorator.find((decorator => {
310
+ return decorator.expression.expression.escapedText === decoratorName;
311
+ })).expression;
312
+ const property = currentProperty || new Property();
313
+ property.name = prop.name.escapedText;
314
+ currentStructure.addProperty(property);
315
+ const typeArgument = typeDecorator.arguments[0];
316
+ defineProperty(property, typeArgument);
317
+ }
318
+ else if (prop.expression.arguments?.[1] &&
319
+ prop.expression.expression.arguments?.[0]) {
320
+ /**
321
+ * Calling `type()` as a regular method
322
+ */
323
+ const property = currentProperty || new Property();
324
+ property.name = prop.expression.arguments[1].text;
325
+ currentStructure.addProperty(property);
326
+ const typeArgument = prop.expression.expression.arguments[0];
327
+ defineProperty(property, typeArgument);
328
+ }
329
+ }
330
+ else if (node.getText() === "setFields" &&
331
+ (node.parent.kind === ts__namespace.SyntaxKind.CallExpression ||
332
+ node.parent.kind === ts__namespace.SyntaxKind.PropertyAccessExpression)) {
333
+ /**
334
+ * Metadata.setFields(klassName, { ... })
335
+ */
336
+ const callExpression = (node.parent.kind === ts__namespace.SyntaxKind.PropertyAccessExpression)
337
+ ? node.parent.parent
338
+ : node.parent;
339
+ /**
340
+ * Skip if @codegen-ignore comment is found before the call expression
341
+ * TODO: currently, if @codegen-ignore is on the file, it will skip all the setFields calls.
342
+ */
343
+ const sourceFile = node.getSourceFile();
344
+ const fullText = sourceFile.getFullText();
345
+ const nodeStart = callExpression.getFullStart();
346
+ const textBeforeNode = fullText.substring(0, nodeStart);
347
+ if (textBeforeNode.includes('@codegen-ignore')) {
348
+ break;
349
+ }
350
+ if (callExpression.kind !== ts__namespace.SyntaxKind.CallExpression) {
351
+ break;
352
+ }
353
+ const classNameNode = callExpression.arguments[0];
354
+ const className = ts__namespace.isClassExpression(classNameNode)
355
+ ? classNameNode.name?.escapedText.toString()
356
+ : classNameNode.getText();
357
+ // skip if no className is provided
358
+ if (!className) {
359
+ break;
360
+ }
361
+ if (currentStructure?.name !== className) {
362
+ currentStructure = new Class();
363
+ }
364
+ context.addStructure(currentStructure);
365
+ currentStructure.extends = "Schema"; // force extends to Schema
366
+ currentStructure.name = className;
367
+ const types = callExpression.arguments[1];
368
+ for (let i = 0; i < types.properties.length; i++) {
369
+ const prop = types.properties[i];
370
+ const property = currentProperty || new Property();
371
+ property.name = prop.name.escapedText;
372
+ currentStructure.addProperty(property);
373
+ defineProperty(property, prop.initializer);
374
+ }
375
+ }
376
+ else if (node.getText() === "defineTypes" &&
377
+ (node.parent.kind === ts__namespace.SyntaxKind.CallExpression ||
378
+ node.parent.kind === ts__namespace.SyntaxKind.PropertyAccessExpression)) {
379
+ /**
380
+ * JavaScript source file (`.js`)
381
+ * Using `defineTypes()`
382
+ */
383
+ const callExpression = (node.parent.kind === ts__namespace.SyntaxKind.PropertyAccessExpression)
384
+ ? node.parent.parent
385
+ : node.parent;
386
+ if (callExpression.kind !== ts__namespace.SyntaxKind.CallExpression) {
387
+ break;
388
+ }
389
+ const className = callExpression.arguments[0].getText();
390
+ currentStructure.name = className;
391
+ const types = callExpression.arguments[1];
392
+ for (let i = 0; i < types.properties.length; i++) {
393
+ const prop = types.properties[i];
394
+ const property = currentProperty || new Property();
395
+ property.name = prop.name.escapedText;
396
+ currentStructure.addProperty(property);
397
+ defineProperty(property, prop.initializer);
398
+ }
399
+ }
400
+ if (node.parent.kind === ts__namespace.SyntaxKind.ClassDeclaration) {
401
+ currentStructure.name = node.getText();
402
+ }
403
+ currentProperty = undefined;
404
+ break;
405
+ case ts__namespace.SyntaxKind.CallExpression:
406
+ /**
407
+ * Defining schema via `schema.schema({ ... })`
408
+ * - schema.schema({})
409
+ * - schema({})
410
+ * - ClassName.extends({})
411
+ */
412
+ if (((node.expression?.getText() === "schema.schema" ||
413
+ node.expression?.getText() === "schema") ||
414
+ (node.expression?.getText().indexOf(".extends") !== -1)) &&
415
+ node.arguments[0].kind === ts__namespace.SyntaxKind.ObjectLiteralExpression) {
416
+ const callExpression = node;
417
+ let className = callExpression.arguments[1]?.getText();
418
+ if (!className && callExpression.parent.kind === ts__namespace.SyntaxKind.VariableDeclaration) {
419
+ className = callExpression.parent.name?.getText();
420
+ }
421
+ // skip if no className is provided
422
+ if (!className) {
423
+ break;
424
+ }
425
+ if (currentStructure?.name !== className) {
426
+ currentStructure = new Class();
427
+ context.addStructure(currentStructure);
428
+ }
429
+ if (node.expression?.getText().indexOf(".extends") !== -1) {
430
+ // if it's using `.extends({})`
431
+ const extendsClass = node.expression?.expression?.escapedText;
432
+ // skip if no extendsClass is provided
433
+ if (!extendsClass) {
434
+ break;
435
+ }
436
+ currentStructure.extends = extendsClass;
437
+ }
438
+ else {
439
+ // if it's using `schema({})`
440
+ currentStructure.extends = "Schema"; // force extends to Schema
441
+ }
442
+ currentStructure.name = className;
443
+ const types = callExpression.arguments[0];
444
+ for (let i = 0; i < types.properties.length; i++) {
445
+ const prop = types.properties[i];
446
+ const property = currentProperty || new Property();
447
+ property.name = prop.name.escapedText;
448
+ currentStructure.addProperty(property);
449
+ defineProperty(property, prop.initializer);
450
+ }
451
+ }
452
+ break;
453
+ case ts__namespace.SyntaxKind.EnumMember:
454
+ if (currentStructure instanceof Enum) {
455
+ const initializer = node.initializer?.text;
456
+ const name = node.getFirstToken().getText();
457
+ const property = currentProperty || new Property();
458
+ property.name = name;
459
+ if (initializer !== undefined) {
460
+ property.type = initializer;
461
+ }
462
+ currentStructure.addProperty(property);
463
+ currentProperty = undefined;
464
+ }
465
+ break;
466
+ }
467
+ ts__namespace.forEachChild(node, (n) => inspectNode(n, context, decoratorName));
468
+ }
469
+ let parsedFiles;
470
+ function parseFiles(fileNames, decoratorName = "type", context = new Context()) {
471
+ /**
472
+ * Re-set globalContext for each test case
473
+ */
474
+ if (globalContext !== context) {
475
+ parsedFiles = {};
476
+ globalContext = context;
477
+ }
478
+ fileNames.forEach((fileName) => {
479
+ let sourceFile;
480
+ let sourceFileName;
481
+ const fileNameAlternatives = [];
482
+ if (!fileName.endsWith(".ts") &&
483
+ !fileName.endsWith(".js") &&
484
+ !fileName.endsWith(".mjs")) {
485
+ fileNameAlternatives.push(`${fileName}.ts`);
486
+ fileNameAlternatives.push(`${fileName}/index.ts`);
487
+ }
488
+ else if (fileName.endsWith(".js")) {
489
+ // Handle .js extensions by also trying .ts (ESM imports often use .js extension)
490
+ fileNameAlternatives.push(fileName);
491
+ fileNameAlternatives.push(fileName.replace(/\.js$/, ".ts"));
492
+ }
493
+ else {
494
+ fileNameAlternatives.push(fileName);
495
+ }
496
+ for (let i = 0; i < fileNameAlternatives.length; i++) {
497
+ try {
498
+ sourceFileName = path__namespace.resolve(fileNameAlternatives[i]);
499
+ if (parsedFiles[sourceFileName]) {
500
+ break;
501
+ }
502
+ sourceFile = ts__namespace.createSourceFile(sourceFileName, fs.readFileSync(sourceFileName).toString(), ts__namespace.ScriptTarget.Latest, true);
503
+ parsedFiles[sourceFileName] = true;
504
+ break;
505
+ }
506
+ catch (e) {
507
+ // console.log(`${fileNameAlternatives[i]} => ${e.message}`);
508
+ }
509
+ }
510
+ if (sourceFile) {
511
+ inspectNode(sourceFile, context, decoratorName);
512
+ }
513
+ });
514
+ return context.getStructures();
515
+ }
516
+ /**
517
+ * TypeScript 4.8+ has introduced a change on how to access decorators.
518
+ * - https://github.com/microsoft/TypeScript/pull/49089
519
+ * - https://devblogs.microsoft.com/typescript/announcing-typescript-4-8/#decorators-are-placed-on-modifiers-on-typescripts-syntax-trees
520
+ */
521
+ function getDecorators(node) {
522
+ if (node == undefined) {
523
+ return undefined;
524
+ }
525
+ // TypeScript 4.7 and below
526
+ // @ts-ignore
527
+ if (node.decorators) {
528
+ return node.decorators;
529
+ }
530
+ // TypeScript 4.8 and above
531
+ // @ts-ignore
532
+ if (ts__namespace.canHaveDecorators && ts__namespace.canHaveDecorators(node)) {
533
+ // @ts-ignore
534
+ const decorators = ts__namespace.getDecorators(node);
535
+ return decorators ? Array.from(decorators) : undefined;
536
+ }
537
+ // @ts-ignore
538
+ return node.modifiers?.filter(ts__namespace.isDecorator);
539
+ }
540
+
541
+ const typeMaps$6 = {
542
+ "string": "string",
543
+ "number": "float",
544
+ "boolean": "bool",
545
+ "int8": "sbyte",
546
+ "uint8": "byte",
547
+ "int16": "short",
548
+ "uint16": "ushort",
549
+ "int32": "int",
550
+ "uint32": "uint",
551
+ "int64": "long",
552
+ "uint64": "ulong",
553
+ "float32": "float",
554
+ "float64": "double",
555
+ };
556
+ /**
557
+ * C# Code Generator
558
+ */
559
+ const capitalize$1 = (s) => {
560
+ if (typeof s !== 'string')
561
+ return '';
562
+ return s.charAt(0).toUpperCase() + s.slice(1);
563
+ };
564
+ function generate$7(context, options) {
565
+ // enrich typeMaps with enums
566
+ context.enums.forEach((structure) => {
567
+ typeMaps$6[structure.name] = structure.name;
568
+ });
569
+ return [
570
+ ...context.classes.map(structure => ({
571
+ name: `${structure.name}.cs`,
572
+ content: generateClass$6(structure, options.namespace)
573
+ })),
574
+ ...context.interfaces.map(structure => ({
575
+ name: `${structure.name}.cs`,
576
+ content: generateInterface$1(structure, options.namespace),
577
+ })),
578
+ ...context.enums.filter(structure => structure.name !== 'OPERATION').map((structure) => ({
579
+ name: `${structure.name}.cs`,
580
+ content: generateEnum(structure, options.namespace),
581
+ })),
582
+ ];
583
+ }
584
+ function generateClass$6(klass, namespace) {
585
+ const indent = (namespace) ? "\t" : "";
586
+ return `${getCommentHeader()}
587
+
588
+ using Colyseus.Schema;
589
+ #if UNITY_5_3_OR_NEWER
590
+ using UnityEngine.Scripting;
591
+ #endif
592
+ ${namespace ? `\nnamespace ${namespace} {` : ""}
593
+ ${indent}public partial class ${klass.name} : ${klass.extends} {
594
+ #if UNITY_5_3_OR_NEWER
595
+ [Preserve]
596
+ #endif
597
+ public ${klass.name}() { }
598
+ ${klass.properties.map((prop) => generateProperty$4(prop, indent)).join("\n\n")}
599
+ ${indent}}
600
+ ${namespace ? "}" : ""}
601
+ `;
602
+ }
603
+ function generateEnum(_enum, namespace) {
604
+ const indent = namespace ? "\t" : "";
605
+ return `${getCommentHeader()}
606
+ ${namespace ? `\nnamespace ${namespace} {` : ""}
607
+ ${indent}public struct ${_enum.name} {
608
+
609
+ ${_enum.properties
610
+ .map((prop) => {
611
+ let dataType = "int";
612
+ let value;
613
+ if (prop.type) {
614
+ if (isNaN(Number(prop.type))) {
615
+ value = `"${prop.type}"`;
616
+ dataType = "string";
617
+ }
618
+ else {
619
+ value = Number(prop.type);
620
+ dataType = Number.isInteger(value) ? 'int' : 'float';
621
+ }
622
+ }
623
+ else {
624
+ value = _enum.properties.indexOf(prop);
625
+ }
626
+ return `${indent}\tpublic const ${dataType} ${prop.name} = ${value};`;
627
+ })
628
+ .join("\n")}
629
+ ${indent}}
630
+ ${namespace ? "}" : ""}`;
631
+ }
632
+ function generateProperty$4(prop, indent = "") {
633
+ let typeArgs = `"${prop.type}"`;
634
+ let property = "public";
635
+ let langType;
636
+ let initializer = "";
637
+ if (prop.childType) {
638
+ const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
639
+ langType = getType(prop);
640
+ typeArgs += `, typeof(${langType})`;
641
+ if (!isUpcaseFirst) {
642
+ typeArgs += `, "${prop.childType}"`;
643
+ }
644
+ initializer = `null`;
645
+ }
646
+ else {
647
+ langType = getType(prop);
648
+ initializer = `default(${langType})`;
649
+ }
650
+ property += ` ${langType} ${prop.name}`;
651
+ let ret = (prop.deprecated) ? `\t\t[System.Obsolete("field '${prop.name}' is deprecated.", true)]\n` : '';
652
+ return ret + `\t${indent}[Type(${prop.index}, ${typeArgs})]
653
+ \t${indent}${property} = ${initializer};`;
654
+ }
655
+ function generateInterface$1(struct, namespace) {
656
+ const indent = (namespace) ? "\t" : "";
657
+ return `${getCommentHeader()}
658
+
659
+ using Colyseus.Schema;
660
+ ${namespace ? `\nnamespace ${namespace} {` : ""}
661
+ ${indent}public class ${struct.name} {
662
+ ${struct.properties.map(prop => `\t${indent}public ${getType(prop)} ${prop.name};`).join("\n")}
663
+ ${indent}}
664
+ ${namespace ? "}" : ""}
665
+ `;
666
+ }
667
+ function getChildType(prop) {
668
+ return typeMaps$6[prop.childType];
669
+ }
670
+ function getType(prop) {
671
+ if (prop.childType) {
672
+ const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
673
+ let type;
674
+ if (prop.type === "ref") {
675
+ type = (isUpcaseFirst)
676
+ ? prop.childType
677
+ : getChildType(prop);
678
+ }
679
+ else {
680
+ const containerClass = capitalize$1(prop.type);
681
+ type = (isUpcaseFirst)
682
+ ? `${containerClass}Schema<${prop.childType}>`
683
+ : `${containerClass}Schema<${getChildType(prop)}>`;
684
+ }
685
+ return type;
686
+ }
687
+ else {
688
+ return (prop.type === "array")
689
+ ? `${typeMaps$6[prop.childType] || prop.childType}[]`
690
+ : typeMaps$6[prop.type];
691
+ }
692
+ }
693
+
694
+ const typeMaps$5 = {
695
+ "string": "string",
696
+ "number": "varint_t",
697
+ "boolean": "bool",
698
+ "int8": "int8_t",
699
+ "uint8": "uint8_t",
700
+ "int16": "int16_t",
701
+ "uint16": "uint16_t",
702
+ "int32": "int32_t",
703
+ "uint32": "uint32_t",
704
+ "int64": "int64_t",
705
+ "uint64": "uint64_t",
706
+ "float32": "float32_t",
707
+ "float64": "float64_t",
708
+ };
709
+ const typeInitializer$2 = {
710
+ "string": '""',
711
+ "number": "0",
712
+ "boolean": "false",
713
+ "int8": "0",
714
+ "uint8": "0",
715
+ "int16": "0",
716
+ "uint16": "0",
717
+ "int32": "0",
718
+ "uint32": "0",
719
+ "int64": "0",
720
+ "uint64": "0",
721
+ "float32": "0",
722
+ "float64": "0",
723
+ };
724
+ /**
725
+ * C++ Code Generator
726
+ */
727
+ const capitalize = (s) => {
728
+ if (typeof s !== 'string')
729
+ return '';
730
+ return s.charAt(0).toUpperCase() + s.slice(1);
731
+ };
732
+ const distinct$3 = (value, index, self) => self.indexOf(value) === index;
733
+ function generate$6(context, options) {
734
+ return context.classes.map(klass => ({
735
+ name: klass.name + ".hpp",
736
+ content: generateClass$5(klass, options.namespace, context.classes)
737
+ }));
738
+ }
739
+ function generateClass$5(klass, namespace, allClasses) {
740
+ const propertiesPerType = {};
741
+ const allRefs = [];
742
+ klass.properties.forEach(property => {
743
+ let type = property.type;
744
+ if (!propertiesPerType[type]) {
745
+ propertiesPerType[type] = [];
746
+ }
747
+ propertiesPerType[type].push(property);
748
+ // keep all refs list
749
+ if ((type === "ref" || type === "array" || type === "map")) {
750
+ allRefs.push(property);
751
+ }
752
+ });
753
+ const allProperties = getAllProperties(klass, allClasses);
754
+ const createInstanceMethod = (allRefs.length === 0) ? "" :
755
+ `\tinline Schema* createInstance(std::type_index type) {
756
+ \t\t${generateFieldIfElseChain(allRefs, (property) => `type == typeid(${property.childType})`, (property) => `return new ${property.childType}();`, (property) => typeMaps$5[property.childType] === undefined)}
757
+ \t\treturn ${klass.extends}::createInstance(type);
758
+ \t}`;
759
+ return `${getCommentHeader()}
760
+ #ifndef __SCHEMA_CODEGEN_${klass.name.toUpperCase()}_H__
761
+ #define __SCHEMA_CODEGEN_${klass.name.toUpperCase()}_H__ 1
762
+
763
+ #include "schema.h"
764
+ #include <typeinfo>
765
+ #include <typeindex>
766
+
767
+ ${allRefs.
768
+ filter(ref => ref.childType && typeMaps$5[ref.childType] === undefined).
769
+ map(ref => ref.childType).
770
+ concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name)).
771
+ filter(distinct$3).
772
+ map(childType => `#include "${childType}.hpp"`).
773
+ join("\n")}
774
+
775
+ using namespace colyseus::schema;
776
+
777
+ ${namespace ? `namespace ${namespace} {` : ""}
778
+ class ${klass.name} : public ${klass.extends} {
779
+ public:
780
+ ${klass.properties.map(prop => generateProperty$3(prop)).join("\n")}
781
+
782
+ \t${klass.name}() {
783
+ \t\tthis->_indexes = ${generateAllIndexes(allProperties)};
784
+ \t\tthis->_types = ${generateAllTypes(allProperties)};
785
+ \t\tthis->_childPrimitiveTypes = ${generateAllChildPrimitiveTypes(allProperties)};
786
+ \t\tthis->_childSchemaTypes = ${generateAllChildSchemaTypes(allProperties)};
787
+ \t}
788
+
789
+ \tvirtual ~${klass.name}() {
790
+ \t\t${generateDestructors(allProperties).join("\n\t\t")}
791
+ \t}
792
+
793
+ protected:
794
+ ${Object.keys(propertiesPerType).map(type => generateGettersAndSetters(klass, type, propertiesPerType[type])).
795
+ join("\n")}
796
+
797
+ ${createInstanceMethod}
798
+ };
799
+ ${namespace ? "}" : ""}
800
+
801
+ #endif
802
+ `;
803
+ }
804
+ function generateProperty$3(prop) {
805
+ let property = "";
806
+ let langType;
807
+ let initializer = "";
808
+ let isPropPointer = "";
809
+ if (prop.childType) {
810
+ const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
811
+ if (prop.type === "ref") {
812
+ langType = `${prop.childType}`;
813
+ initializer = `new ${prop.childType}()`;
814
+ }
815
+ else if (prop.type === "array") {
816
+ langType = (isUpcaseFirst)
817
+ ? `ArraySchema<${prop.childType}*>`
818
+ : `ArraySchema<${typeMaps$5[prop.childType]}>`;
819
+ initializer = `new ${langType}()`;
820
+ }
821
+ else if (prop.type === "map") {
822
+ langType = (isUpcaseFirst)
823
+ ? `MapSchema<${prop.childType}*>`
824
+ : `MapSchema<${typeMaps$5[prop.childType]}>`;
825
+ initializer = `new ${langType}()`;
826
+ }
827
+ isPropPointer = "*";
828
+ }
829
+ else {
830
+ langType = typeMaps$5[prop.type];
831
+ initializer = typeInitializer$2[prop.type];
832
+ }
833
+ property += ` ${langType} ${isPropPointer}${prop.name}`;
834
+ return `\t${property} = ${initializer};`;
835
+ }
836
+ function generateGettersAndSetters(klass, type, properties) {
837
+ let langType = typeMaps$5[type];
838
+ let typeCast = "";
839
+ const getMethodName = `get${capitalize(type)}`;
840
+ const setMethodName = `set${capitalize(type)}`;
841
+ if (type === "ref") {
842
+ langType = "Schema*";
843
+ }
844
+ else if (type === "array") {
845
+ langType = `ArraySchema<char*> *`;
846
+ typeCast = `(ArraySchema<char*> *)`;
847
+ }
848
+ else if (type === "map") {
849
+ langType = `MapSchema<char*> *`;
850
+ typeCast = `(MapSchema<char*> *)`;
851
+ }
852
+ return `\tinline ${langType} ${getMethodName}(const string &field)
853
+ \t{
854
+ \t\t${generateFieldIfElseChain(properties, (property) => `field == "${property.name}"`, (property) => `return ${typeCast}this->${property.name};`)}
855
+ \t\treturn ${klass.extends}::${getMethodName}(field);
856
+ \t}
857
+
858
+ \tinline void ${setMethodName}(const string &field, ${langType} value)
859
+ \t{
860
+ \t\t${generateFieldIfElseChain(properties, (property) => `field == "${property.name}"`, (property) => {
861
+ const isSchemaType = (typeMaps$5[property.childType] === undefined);
862
+ if (type === "ref") {
863
+ langType = `${property.childType}*`;
864
+ typeCast = (isSchemaType)
865
+ ? `(${property.childType}*)`
866
+ : `/* bug? */`;
867
+ }
868
+ else if (type === "array") {
869
+ typeCast = (isSchemaType)
870
+ ? `(ArraySchema<${property.childType}*> *)`
871
+ : `(ArraySchema<${typeMaps$5[property.childType]}> *)`;
872
+ }
873
+ else if (type === "map") {
874
+ typeCast = (isSchemaType)
875
+ ? `(MapSchema<${property.childType}*> *)`
876
+ : `(MapSchema<${typeMaps$5[property.childType]}> *)`;
877
+ }
878
+ return `this->${property.name} = ${typeCast}value;\n\t\t\treturn;`;
879
+ })}
880
+ \t\treturn ${klass.extends}::${setMethodName}(field, value);
881
+ \t}`;
882
+ }
883
+ function generateFieldIfElseChain(properties, ifCallback, callback, filter = (_) => true) {
884
+ let chain = "";
885
+ const uniqueChecks = [];
886
+ properties.filter(filter).forEach((property, i) => {
887
+ const check = ifCallback(property);
888
+ if (uniqueChecks.indexOf(check) === -1) {
889
+ uniqueChecks.push(check);
890
+ }
891
+ else {
892
+ return;
893
+ }
894
+ if (i === 0) {
895
+ chain += "if ";
896
+ }
897
+ else {
898
+ chain += " else if ";
899
+ }
900
+ chain += `(${check})
901
+ \t\t{
902
+ \t\t\t${callback(property)}\n
903
+ \t\t}`;
904
+ });
905
+ return chain;
906
+ }
907
+ function generateAllIndexes(properties) {
908
+ return `{${properties.map((property, i) => `{${i}, "${property.name}"}`).join(", ")}}`;
909
+ }
910
+ function generateAllTypes(properties) {
911
+ return `{${properties.map((property, i) => `{${i}, "${property.type}"}`).join(", ")}}`;
912
+ }
913
+ function generateAllChildSchemaTypes(properties) {
914
+ return `{${properties.map((property, i) => {
915
+ if (property.childType && typeMaps$5[property.childType] === undefined) {
916
+ return `{${i}, typeid(${property.childType})}`;
917
+ }
918
+ else {
919
+ return null;
920
+ }
921
+ }).filter(r => r !== null).join(", ")}}`;
922
+ }
923
+ function generateAllChildPrimitiveTypes(properties) {
924
+ return `{${properties.map((property, i) => {
925
+ if (typeMaps$5[property.childType] !== undefined) {
926
+ return `{${i}, "${property.childType}"}`;
927
+ }
928
+ else {
929
+ return null;
930
+ }
931
+ }).filter(r => r !== null).join(", ")}}`;
932
+ }
933
+ function generateDestructors(properties) {
934
+ return properties.map((property, i) => {
935
+ if (property.childType) {
936
+ return `delete this->${property.name};`;
937
+ }
938
+ else {
939
+ return null;
940
+ }
941
+ }).filter(r => r !== null);
942
+ }
943
+ function getAllProperties(klass, allClasses) {
944
+ let properties = [];
945
+ getInheritanceTree(klass, allClasses).reverse().forEach((klass) => {
946
+ properties = properties.concat(klass.properties);
947
+ });
948
+ return properties;
949
+ }
950
+
951
+ const typeMaps$4 = {
952
+ "string": "String",
953
+ "number": "Dynamic",
954
+ "boolean": "Bool",
955
+ "int8": "Int",
956
+ "uint8": "UInt",
957
+ "int16": "Int",
958
+ "uint16": "UInt",
959
+ "int32": "Int",
960
+ "uint32": "UInt",
961
+ "int64": "Int",
962
+ "uint64": "UInt",
963
+ "float32": "Float",
964
+ "float64": "Float",
965
+ };
966
+ const typeInitializer$1 = {
967
+ "string": '""',
968
+ "number": "0",
969
+ "boolean": "false",
970
+ "int8": "0",
971
+ "uint8": "0",
972
+ "int16": "0",
973
+ "uint16": "0",
974
+ "int32": "0",
975
+ "uint32": "0",
976
+ "int64": "0",
977
+ "uint64": "0",
978
+ "float32": "0",
979
+ "float64": "0",
980
+ };
981
+ function generate$5(context, options) {
982
+ return context.classes.map(klass => ({
983
+ name: klass.name + ".hx",
984
+ content: generateClass$4(klass, options.namespace, context.classes)
985
+ }));
986
+ }
987
+ function generateClass$4(klass, namespace, allClasses) {
988
+ return `${getCommentHeader()}
989
+
990
+ ${namespace ? `package ${namespace};` : ""}
991
+ import io.colyseus.serializer.schema.Schema;
992
+ import io.colyseus.serializer.schema.types.*;
993
+
994
+ class ${klass.name} extends ${klass.extends} {
995
+ ${klass.properties.map(prop => generateProperty$2(prop)).join("\n")}
996
+ }
997
+ `;
998
+ }
999
+ function generateProperty$2(prop) {
1000
+ let langType;
1001
+ let initializer = "";
1002
+ let typeArgs = `"${prop.type}"`;
1003
+ if (prop.childType) {
1004
+ const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
1005
+ if (isUpcaseFirst) {
1006
+ typeArgs += `, ${prop.childType}`;
1007
+ }
1008
+ else {
1009
+ typeArgs += `, "${prop.childType}"`;
1010
+ }
1011
+ if (prop.type === "ref") {
1012
+ langType = `${prop.childType}`;
1013
+ initializer = `new ${prop.childType}()`;
1014
+ }
1015
+ else if (prop.type === "array") {
1016
+ langType = (isUpcaseFirst)
1017
+ ? `ArraySchema<${prop.childType}>`
1018
+ : `ArraySchema<${typeMaps$4[prop.childType]}>`;
1019
+ initializer = `new ${langType}()`;
1020
+ }
1021
+ else if (prop.type === "map") {
1022
+ langType = (isUpcaseFirst)
1023
+ ? `MapSchema<${prop.childType}>`
1024
+ : `MapSchema<${typeMaps$4[prop.childType]}>`;
1025
+ initializer = `new ${langType}()`;
1026
+ }
1027
+ }
1028
+ else {
1029
+ langType = typeMaps$4[prop.type];
1030
+ initializer = typeInitializer$1[prop.type];
1031
+ }
1032
+ // TODO: remove initializer. The callbacks at the Haxe decoder side have a
1033
+ // "FIXME" comment about this on Decoder.hx
1034
+ return `\t@:type(${typeArgs})\n\tpublic var ${prop.name}: ${langType} = ${initializer};\n`;
1035
+ // return `\t@:type(${typeArgs})\n\tpublic var ${prop.name}: ${langType};\n`
1036
+ }
1037
+
1038
+ const typeMaps$3 = {
1039
+ "string": "string",
1040
+ "number": "number",
1041
+ "boolean": "boolean",
1042
+ "int8": "number",
1043
+ "uint8": "number",
1044
+ "int16": "number",
1045
+ "uint16": "number",
1046
+ "int32": "number",
1047
+ "uint32": "number",
1048
+ "int64": "number",
1049
+ "uint64": "number",
1050
+ "float32": "number",
1051
+ "float64": "number",
1052
+ };
1053
+ const distinct$2 = (value, index, self) => self.indexOf(value) === index;
1054
+ function generate$4(context, options) {
1055
+ return [
1056
+ ...context.classes.map(structure => ({
1057
+ name: structure.name + ".ts",
1058
+ content: generateClass$3(structure, options.namespace, context.classes)
1059
+ })),
1060
+ ...context.interfaces.map(structure => ({
1061
+ name: structure.name + ".ts",
1062
+ content: generateInterface(structure, options.namespace, context.classes),
1063
+ }))
1064
+ ];
1065
+ }
1066
+ function generateClass$3(klass, namespace, allClasses) {
1067
+ const allRefs = [];
1068
+ klass.properties.forEach(property => {
1069
+ let type = property.type;
1070
+ // keep all refs list
1071
+ if ((type === "ref" || type === "array" || type === "map" || type === "set")) {
1072
+ allRefs.push(property);
1073
+ }
1074
+ });
1075
+ return `${getCommentHeader()}
1076
+
1077
+ import { Schema, type, ArraySchema, MapSchema, SetSchema, DataChange } from '@colyseus/schema';
1078
+ ${allRefs.
1079
+ filter(ref => ref.childType && typeMaps$3[ref.childType] === undefined).
1080
+ map(ref => ref.childType).
1081
+ concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name)).
1082
+ filter(distinct$2).
1083
+ map(childType => `import { ${childType} } from './${childType}'`).
1084
+ join("\n")}
1085
+
1086
+ export class ${klass.name} extends ${klass.extends} {
1087
+ ${klass.properties.map(prop => ` ${generateProperty$1(prop)}`).join("\n")}
1088
+ }
1089
+ `;
1090
+ }
1091
+ function generateProperty$1(prop) {
1092
+ let langType;
1093
+ let initializer = "";
1094
+ let typeArgs;
1095
+ if (prop.childType) {
1096
+ const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
1097
+ if (isUpcaseFirst) {
1098
+ typeArgs += `, ${prop.childType}`;
1099
+ }
1100
+ else {
1101
+ typeArgs += `, "${prop.childType}"`;
1102
+ }
1103
+ if (prop.type === "ref") {
1104
+ langType = `${prop.childType}`;
1105
+ initializer = `new ${prop.childType}()`;
1106
+ typeArgs = `${prop.childType}`;
1107
+ }
1108
+ else if (prop.type === "array") {
1109
+ langType = (isUpcaseFirst)
1110
+ ? `ArraySchema<${prop.childType}>`
1111
+ : `ArraySchema<${typeMaps$3[prop.childType]}>`;
1112
+ initializer = `new ${langType}()`;
1113
+ typeArgs = (isUpcaseFirst)
1114
+ ? `[ ${prop.childType} ]`
1115
+ : `[ "${prop.childType}" ]`;
1116
+ }
1117
+ else if (prop.type === "map") {
1118
+ langType = (isUpcaseFirst)
1119
+ ? `MapSchema<${prop.childType}>`
1120
+ : `MapSchema<${typeMaps$3[prop.childType]}>`;
1121
+ initializer = `new ${langType}()`;
1122
+ typeArgs = (isUpcaseFirst)
1123
+ ? `{ map: ${prop.childType} }`
1124
+ : `{ map: "${prop.childType}" }`;
1125
+ }
1126
+ else if (prop.type === "set") {
1127
+ langType = (isUpcaseFirst)
1128
+ ? `SetSchema<${prop.childType}>`
1129
+ : `SetSchema<${typeMaps$3[prop.childType]}>`;
1130
+ initializer = `new ${langType}()`;
1131
+ typeArgs = (isUpcaseFirst)
1132
+ ? `{ set: ${prop.childType} }`
1133
+ : `{ set: "${prop.childType}" }`;
1134
+ }
1135
+ }
1136
+ else {
1137
+ langType = typeMaps$3[prop.type];
1138
+ typeArgs = `"${prop.type}"`;
1139
+ }
1140
+ // TS1263: "Declarations with initializers cannot also have definite assignment assertions"
1141
+ const definiteAssertion = initializer ? "" : "!";
1142
+ return `@type(${typeArgs}) public ${prop.name}${definiteAssertion}: ${langType}${(initializer) ? ` = ${initializer}` : ""};`;
1143
+ }
1144
+ function generateInterface(structure, namespace, allClasses) {
1145
+ return `${getCommentHeader()}
1146
+
1147
+ export interface ${structure.name} {
1148
+ ${structure.properties.map(prop => ` ${prop.name}: ${prop.type};`).join("\n")}
1149
+ }
1150
+ `;
1151
+ }
1152
+
1153
+ const typeMaps$2 = {
1154
+ "string": "string",
1155
+ "number": "number",
1156
+ "boolean": "boolean",
1157
+ "int8": "number",
1158
+ "uint8": "number",
1159
+ "int16": "number",
1160
+ "uint16": "number",
1161
+ "int32": "number",
1162
+ "uint32": "number",
1163
+ "int64": "number",
1164
+ "uint64": "number",
1165
+ "float32": "number",
1166
+ "float64": "number",
1167
+ };
1168
+ const distinct$1 = (value, index, self) => self.indexOf(value) === index;
1169
+ function generate$3(context, options) {
1170
+ return context.classes.map(klass => ({
1171
+ name: klass.name + ".js",
1172
+ content: generateClass$2(klass, options.namespace, context.classes)
1173
+ }));
1174
+ }
1175
+ function generateClass$2(klass, namespace, allClasses) {
1176
+ const allRefs = [];
1177
+ klass.properties.forEach(property => {
1178
+ let type = property.type;
1179
+ // keep all refs list
1180
+ if ((type === "ref" || type === "array" || type === "map")) {
1181
+ allRefs.push(property);
1182
+ }
1183
+ });
1184
+ return `${getCommentHeader()}
1185
+
1186
+ const schema = require("@colyseus/schema");
1187
+ const Schema = schema.Schema;
1188
+ const type = schema.type;
1189
+ ${allRefs.
1190
+ filter(ref => ref.childType && typeMaps$2[ref.childType] === undefined).
1191
+ map(ref => ref.childType).
1192
+ concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name)).
1193
+ filter(distinct$1).
1194
+ map(childType => `const ${childType} = require("./${childType}");`).
1195
+ join("\n")}
1196
+
1197
+ class ${klass.name} extends ${klass.extends} {
1198
+ constructor () {
1199
+ super();
1200
+ ${klass.properties.
1201
+ filter(prop => prop.childType !== undefined).
1202
+ map(prop => " " + generatePropertyInitializer(prop)).join("\n")}
1203
+ }
1204
+ }
1205
+ ${klass.properties.map(prop => generatePropertyDeclaration$1(klass.name, prop)).join("\n")}
1206
+
1207
+ export default ${klass.name};
1208
+ `;
1209
+ }
1210
+ function generatePropertyDeclaration$1(className, prop) {
1211
+ let typeArgs;
1212
+ if (prop.childType) {
1213
+ const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
1214
+ if (isUpcaseFirst) {
1215
+ typeArgs += `, ${prop.childType}`;
1216
+ }
1217
+ else {
1218
+ typeArgs += `, "${prop.childType}"`;
1219
+ }
1220
+ if (prop.type === "ref") {
1221
+ typeArgs = `${prop.childType}`;
1222
+ }
1223
+ else if (prop.type === "array") {
1224
+ typeArgs = (isUpcaseFirst)
1225
+ ? `[ ${prop.childType} ]`
1226
+ : `[ "${prop.childType}" ]`;
1227
+ }
1228
+ else if (prop.type === "map") {
1229
+ typeArgs = (isUpcaseFirst)
1230
+ ? `{ map: ${prop.childType} }`
1231
+ : `{ map: "${prop.childType}" }`;
1232
+ }
1233
+ }
1234
+ else {
1235
+ typeArgs = `"${prop.type}"`;
1236
+ }
1237
+ return `type(${typeArgs})(${className}.prototype, "${prop.name}");`;
1238
+ }
1239
+ function generatePropertyInitializer(prop) {
1240
+ let initializer = "";
1241
+ if (prop.type === "ref") {
1242
+ initializer = `new ${prop.childType}()`;
1243
+ }
1244
+ else if (prop.type === "array") {
1245
+ initializer = `new schema.ArraySchema()`;
1246
+ }
1247
+ else if (prop.type === "map") {
1248
+ initializer = `new schema.MapSchema()`;
1249
+ }
1250
+ return `this.${prop.name} = ${initializer}`;
1251
+ }
1252
+
1253
+ const typeMaps$1 = {
1254
+ "string": "String",
1255
+ "number": "float",
1256
+ "boolean": "boolean",
1257
+ "int8": "byte",
1258
+ "uint8": "short",
1259
+ "int16": "short",
1260
+ "uint16": "int",
1261
+ "int32": "int",
1262
+ "uint32": "long",
1263
+ "int64": "long",
1264
+ "uint64": "long",
1265
+ "float32": "float",
1266
+ "float64": "double",
1267
+ };
1268
+ const typeInitializer = {
1269
+ "string": '""',
1270
+ "number": "0",
1271
+ "boolean": "false",
1272
+ "int8": "0",
1273
+ "uint8": "0",
1274
+ "int16": "0",
1275
+ "uint16": "0",
1276
+ "int32": "0",
1277
+ "uint32": "0",
1278
+ "int64": "0",
1279
+ "uint64": "0",
1280
+ "float32": "0",
1281
+ "float64": "0",
1282
+ };
1283
+ /**
1284
+ * C# Code Generator
1285
+ */
1286
+ function generate$2(context, options) {
1287
+ return context.classes.map(klass => ({
1288
+ name: klass.name + ".java",
1289
+ content: generateClass$1(klass, options.namespace)
1290
+ }));
1291
+ }
1292
+ function generateClass$1(klass, namespace) {
1293
+ const indent = (namespace) ? "\t" : "";
1294
+ return `${getCommentHeader()}
1295
+ ${namespace ? `\npackage ${namespace};` : ""}
1296
+
1297
+ import io.colyseus.serializer.schema.Schema;
1298
+ import io.colyseus.serializer.schema.annotations.SchemaClass;
1299
+ import io.colyseus.serializer.schema.annotations.SchemaField;
1300
+
1301
+ @SchemaClass
1302
+ ${indent}public class ${klass.name} extends ${klass.extends} {
1303
+ ${klass.properties.map(prop => generateProperty(prop, indent)).join("\n\n")}
1304
+ ${indent}}
1305
+ ${namespace ? "}" : ""}
1306
+ `;
1307
+ }
1308
+ function generateProperty(prop, indent = "") {
1309
+ let typeArgs = `${prop.index}/${prop.type}`;
1310
+ let property = "public";
1311
+ let langType;
1312
+ let ctorArgs = "";
1313
+ let initializer = "";
1314
+ if (prop.childType) {
1315
+ const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
1316
+ if (prop.type !== "ref" && isUpcaseFirst) {
1317
+ ctorArgs = `${prop.childType}.class`;
1318
+ }
1319
+ if (prop.type === "ref") {
1320
+ langType = (isUpcaseFirst)
1321
+ ? prop.childType
1322
+ : typeMaps$1[prop.childType];
1323
+ initializer = `new ${langType}${(prop.type !== "ref" && isUpcaseFirst) ? "<>" : ""}(${ctorArgs})`;
1324
+ }
1325
+ else if (prop.type === "array") {
1326
+ langType = (isUpcaseFirst)
1327
+ ? `ArraySchema<${prop.childType}>`
1328
+ : `ArraySchema`;
1329
+ initializer = `new ArraySchema${(isUpcaseFirst) ? "<>" : ""}(${ctorArgs})`;
1330
+ }
1331
+ else if (prop.type === "map") {
1332
+ langType = (isUpcaseFirst)
1333
+ ? `MapSchema<${prop.childType}>`
1334
+ : `MapSchema`;
1335
+ initializer = `new MapSchema${(isUpcaseFirst) ? "<>" : ""}(${ctorArgs})`;
1336
+ }
1337
+ if (prop.type !== "ref") {
1338
+ typeArgs += (isUpcaseFirst)
1339
+ ? `/ref`
1340
+ : `/${prop.childType}`;
1341
+ }
1342
+ }
1343
+ else {
1344
+ langType = typeMaps$1[prop.type];
1345
+ initializer = typeInitializer[prop.type];
1346
+ }
1347
+ property += ` ${langType} ${prop.name}`;
1348
+ return `\t@SchemaField("${typeArgs}")\t${indent}
1349
+ \t${indent}${property} = ${initializer};`;
1350
+ }
1351
+
1352
+ /**
1353
+ TODO:
1354
+ - Support inheritance
1355
+ - Support importing Schema dependencies
1356
+ */
1357
+ const typeMaps = {
1358
+ "string": "string",
1359
+ "number": "number",
1360
+ "boolean": "boolean",
1361
+ "int8": "number",
1362
+ "uint8": "number",
1363
+ "int16": "number",
1364
+ "uint16": "number",
1365
+ "int32": "number",
1366
+ "uint32": "number",
1367
+ "int64": "number",
1368
+ "uint64": "number",
1369
+ "float32": "number",
1370
+ "float64": "number",
1371
+ };
1372
+ const distinct = (value, index, self) => self.indexOf(value) === index;
1373
+ function generate$1(context, options) {
1374
+ return context.classes.map(klass => ({
1375
+ name: klass.name + ".lua",
1376
+ content: generateClass(klass, options.namespace, context.classes)
1377
+ }));
1378
+ }
1379
+ function generateClass(klass, namespace, allClasses) {
1380
+ const allRefs = [];
1381
+ klass.properties.forEach(property => {
1382
+ let type = property.type;
1383
+ // keep all refs list
1384
+ if ((type === "ref" || type === "array" || type === "map")) {
1385
+ allRefs.push(property);
1386
+ }
1387
+ });
1388
+ // Inheritance support
1389
+ const inherits = (klass.extends !== "Schema")
1390
+ ? `, ${klass.extends}`
1391
+ : "";
1392
+ return `${getCommentHeader().replace(/\/\//mg, "--")}
1393
+
1394
+ local schema = require 'colyseus.serializer.schema.schema'
1395
+ ${allRefs.
1396
+ filter(ref => ref.childType && typeMaps[ref.childType] === undefined).
1397
+ map(ref => ref.childType).
1398
+ concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name)).
1399
+ filter(distinct).
1400
+ map(childType => `local ${childType} = require '${(namespace ? `${namespace}.` : '')}${childType}'`).
1401
+ join("\n")}
1402
+
1403
+ ---@class ${klass.name}: ${klass.extends}
1404
+ ${klass.properties.map(prop => `---@field ${prop.name} ${getLUATypeAnnotation(prop)}`).join("\n")}
1405
+ local ${klass.name} = schema.define({
1406
+ ${klass.properties.map(prop => generatePropertyDeclaration(prop)).join(",\n")},
1407
+ ["_fields_by_index"] = { ${klass.properties.map(prop => `"${prop.name}"`).join(", ")} },
1408
+ }${inherits})
1409
+
1410
+ return ${klass.name}
1411
+ `;
1412
+ }
1413
+ function generatePropertyDeclaration(prop) {
1414
+ let typeArgs;
1415
+ if (prop.childType) {
1416
+ const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
1417
+ if (isUpcaseFirst) {
1418
+ typeArgs += `${prop.childType}`;
1419
+ }
1420
+ else {
1421
+ typeArgs += `"${prop.childType}"`;
1422
+ }
1423
+ if (prop.type === "ref") {
1424
+ typeArgs = (isUpcaseFirst)
1425
+ ? `${prop.childType}`
1426
+ : `"${prop.childType}"`;
1427
+ }
1428
+ else {
1429
+ typeArgs = (isUpcaseFirst)
1430
+ ? `{ ${prop.type} = ${prop.childType} }`
1431
+ : `{ ${prop.type} = "${prop.childType}" }`;
1432
+ }
1433
+ }
1434
+ else {
1435
+ typeArgs = `"${prop.type}"`;
1436
+ }
1437
+ return ` ["${prop.name}"] = ${typeArgs}`;
1438
+ }
1439
+ function getLUATypeAnnotation(prop) {
1440
+ if (prop.type === "ref") {
1441
+ return prop.childType;
1442
+ }
1443
+ else if (prop.type === "array") {
1444
+ return "ArraySchema";
1445
+ }
1446
+ else if (prop.type === "map") {
1447
+ return "MapSchema";
1448
+ }
1449
+ else {
1450
+ return typeMaps[prop.type];
1451
+ }
1452
+ }
1453
+
1454
+ const generators = { csharp: generate$7, cpp: generate$6, haxe: generate$5, ts: generate$4, js: generate$3, java: generate$2, lua: generate$1, };
1455
+ function generate(targetId, options) {
1456
+ const generator = generators[targetId];
1457
+ if (!generator) {
1458
+ throw new Error("You must provide a valid generator as argument, such as: --csharp, --haxe or --cpp");
1459
+ }
1460
+ if (!fs__namespace.existsSync(options.output)) {
1461
+ console.log("Creating", options.output, "directory");
1462
+ fs__namespace.mkdirSync(options.output);
1463
+ }
1464
+ /**
1465
+ * Default `@type()` decorator name
1466
+ */
1467
+ if (!options.decorator) {
1468
+ options.decorator = "type";
1469
+ }
1470
+ // resolve wildcard files
1471
+ options.files = options.files.reduce((acc, cur) => {
1472
+ if (cur.endsWith("*")) {
1473
+ acc.push(...recursiveFiles(cur.slice(0, -1)).filter(filename => /\.(js|ts|mjs)$/.test(filename)));
1474
+ }
1475
+ else {
1476
+ acc.push(cur);
1477
+ }
1478
+ return acc;
1479
+ }, []);
1480
+ const structures = parseFiles(options.files, options.decorator);
1481
+ // Post-process classes before generating
1482
+ structures.classes.forEach(klass => klass.postProcessing());
1483
+ const files = generator(structures, options);
1484
+ files.forEach((file) => {
1485
+ const outputPath = path__namespace.resolve(options.output, file.name);
1486
+ fs__namespace.writeFileSync(outputPath, file.content);
1487
+ console.log("generated:", file.name);
1488
+ });
1489
+ }
1490
+ function recursiveFiles(dir) {
1491
+ const files = fs__namespace.readdirSync(dir, { withFileTypes: true });
1492
+ let collect = [];
1493
+ files.forEach(file => {
1494
+ const filename = path__namespace.resolve(dir, file.name);
1495
+ file.isDirectory() ? collect.push(...recursiveFiles(filename)) : collect.push(filename);
1496
+ });
1497
+ return collect;
1498
+ }
1499
+
1500
+ const supportedTargets = {
1501
+ csharp: 'generate for C#/Unity',
1502
+ cpp: 'generate for C++',
1503
+ haxe: 'generate for Haxe',
1504
+ ts: 'generate for TypeScript',
1505
+ js: 'generate for JavaScript',
1506
+ java: 'generate for Java',
1507
+ lua: 'generate for LUA',
1508
+ };
1509
+ function displayHelp() {
1510
+ console.log(`\nschema-codegen [path/to/Schema.ts]
1511
+
1512
+ Usage (C#/Unity)
1513
+ schema-codegen src/Schema.ts --output client-side/ --csharp --namespace MyGame.Schema
1514
+
1515
+ Valid options:
1516
+ --output: the output directory for generated client-side schema files
1517
+ ${Object.
1518
+ keys(supportedTargets).
1519
+ map((targetId) => (` --${targetId}: ${supportedTargets[targetId]}`)).
1520
+ join("\n")}
1521
+
1522
+ Optional:
1523
+ --namespace: generate namespace on output code
1524
+ --decorator: custom name for @type decorator to scan for`);
1525
+ process.exit();
1526
+ }
1527
+ const args = argv(process.argv.slice(2));
1528
+ if (args.help) {
1529
+ displayHelp();
1530
+ }
1531
+ let targetId;
1532
+ for (let target in supportedTargets) {
1533
+ if (args[target]) {
1534
+ targetId = target;
1535
+ }
1536
+ }
1537
+ if (!args.output) {
1538
+ console.error("You must provide a valid --output directory.");
1539
+ displayHelp();
1540
+ }
1541
+ try {
1542
+ args.files = args._;
1543
+ generate(targetId, {
1544
+ files: args._,
1545
+ decorator: args.decorator,
1546
+ output: args.output,
1547
+ namespace: args.namespace
1548
+ });
1549
+ }
1550
+ catch (e) {
1551
+ console.error(e.message);
1552
+ console.error(e.stack);
1553
+ displayHelp();
1554
+ }
1555
+ //# sourceMappingURL=cli.cjs.map