UNPKG

@colyseus/schema

Version:

Binary state serializer with delta encoding for games

2,348 lines 79.6 kB
#!/usr/bin/env node
'use strict';

var fs = require('fs');
var path = require('path');
var ts$1 = require('typescript');

var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
function _interopNamespaceDefault(e) {
    var n = Object.create(null);
    if (e) {
        Object.keys(e).forEach(function (k) {
            if (k !== 'default') {
                var d = Object.getOwnPropertyDescriptor(e, k);
                Object.defineProperty(n, k, d.get ? d : {
                    enumerable: true,
                    get: function () { return e[k]; }
                });
            }
        });
    }
    n.default = e;
    return Object.freeze(n);
}

var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
var ts__namespace = /*#__PURE__*/_interopNamespaceDefault(ts$1);

/**
 * @author Ethan Davis
 * https://github.com/ethanent/gar
 */
var argv = (sargs) => {
    let props = {};
    let lones = [];
    const convertIfApplicable = (value) => (isNaN(value) ? (value.toString().toLowerCase() === 'true' ? true : (value.toString().toLowerCase() === 'false' ? false : value)) : Number(value));
    const removeStartHyphens = (value) => value.replace(/^\-+/g, '');
    for (let i = 0; i < sargs.length; i++) {
        const equalsIndex = sargs[i].indexOf('=');
        const isNextRefProp = sargs[i].charAt(0) === '-' && sargs.length - 1 >= i + 1 && sargs[i + 1].indexOf('=') === -1 && sargs[i + 1].charAt(0) !== '-';
        const argName = equalsIndex === -1 ? removeStartHyphens(sargs[i]) : removeStartHyphens(sargs[i].slice(0, equalsIndex));
        if (equalsIndex !== -1) {
            props[argName] = convertIfApplicable(sargs[i].slice(equalsIndex + 1));
        }
        else if (isNextRefProp) {
            props[argName] = convertIfApplicable(sargs[i + 1]);
            i++;
        }
        else if (sargs[i].charAt(0) === '-') {
            if (sargs[i].charAt(1) === '-') {
                props[argName] = true;
            }
            else {
                for (let b = 0; b < argName.length; b++) {
                    props[argName.charAt(b)] = true;
                }
            }
        }
        else {
            lones.push(convertIfApplicable(argName));
        }
    }
    return Object.assign(props, {
        '_': lones
    });
};

if (typeof (__dirname) === "undefined") {
    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);
}
const VERSION = JSON.parse(fs__namespace.readFileSync(__dirname + "/../../package.json").toString()).version;
const COMMENT_HEADER = `
THIS FILE HAS BEEN GENERATED AUTOMATICALLY
DO NOT CHANGE IT MANUALLY UNLESS YOU KNOW WHAT YOU'RE DOING

GENERATED USING @colyseus/schema ${VERSION}
`;
function getCommentHeader(singleLineComment = "//") {
    return `${COMMENT_HEADER.split("\n").map(line => `${singleLineComment} ${line}`).join("\n")}`;
}
class Context {
    classes = [];
    interfaces = [];
    enums = [];
    getStructures() {
        return {
            classes: this.classes.filter(klass => {
                if (this.isSchemaClass(klass)) {
                    return true;
                }
                else {
                    let parentClass = klass;
                    while (parentClass = this.getParentClass(parentClass)) {
                        if (this.isSchemaClass(parentClass)) {
                            return true;
                        }
                    }
                }
                return false;
            }),
            interfaces: this.interfaces,
            enums: this.enums,
        };
    }
    addStructure(structure) {
        if (structure.context === this) {
            return;
        } // skip if already added.
        structure.context = this;
        if (structure instanceof Class) {
            this.classes.push(structure);
        }
        else if (structure instanceof Interface) {
            this.interfaces.push(structure);
        }
        else if (structure instanceof Enum) {
            this.enums.push(structure);
        }
    }
    getParentClass(klass) {
        return this.classes.find(c => c.name === klass.extends);
    }
    isSchemaClass(klass) {
        let isSchema = false;
        let currentClass = klass;
        while (!isSchema && currentClass) {
            //
            // TODO: ideally we should check for actual @colyseus/schema module
            // reference rather than arbitrary strings.
            //
            isSchema = (currentClass.extends === "Schema" ||
                currentClass.extends === "schema.Schema" ||
                currentClass.extends === "Schema.Schema");
            //
            // When extending from `schema.Schema`, it is required to
            // normalize as "Schema" for code generation.
            //
            if (currentClass === klass && isSchema) {
                klass.extends = "Schema";
            }
            currentClass = this.getParentClass(currentClass);
        }
        return isSchema;
    }
}
class Interface {
    context;
    name;
    properties = [];
    addProperty(property) {
        if (property.type.indexOf("[]") >= 0) {
            // is array!
            property.childType = property.type.match(/([^\[]+)/i)[1];
            property.type = "array";
            this.properties.push(property);
        }
        else {
            this.properties.push(property);
        }
    }
}
class Class {
    context;
    name;
    properties = [];
    extends;
    addProperty(property) {
        property.index = this.properties.length;
        this.properties.push(property);
    }
    postProcessing() {
        /**
         * Ensure the proprierties `index` are correct using inheritance
         */
        let parentKlass = this;
        while (parentKlass &&
            (parentKlass = this.context.classes.find(k => k.name === parentKlass.extends))) {
            this.properties.forEach(prop => {
                prop.index += parentKlass.properties.length;
            });
        }
    }
}
class Enum {
    context;
    name;
    properties = [];
    addProperty(property) {
        this.properties.push(property);
    }
}
class Property {
    index;
    name;
    type;
    childType;
    deprecated;
}
function getInheritanceTree(klass, allClasses, includeSelf = true) {
    let currentClass = klass;
    let inheritanceTree = [];
    if (includeSelf) {
        inheritanceTree.push(currentClass);
    }
    while (currentClass.extends !== "Schema") {
        currentClass = allClasses.find(klass => klass.name == currentClass.extends);
        inheritanceTree.push(currentClass);
    }
    return inheritanceTree;
}

let currentStructure;
let currentProperty;
let globalContext;
function defineProperty(property, initializer) {
    if (ts__namespace.isIdentifier(initializer)) {
        property.type = "ref";
        property.childType = initializer.text;
    }
    else if (initializer.kind == ts__namespace.SyntaxKind.ObjectLiteralExpression) {
        property.type = initializer.properties[0].name.text;
        property.childType = initializer.properties[0].initializer.text;
    }
    else if (initializer.kind == ts__namespace.SyntaxKind.ArrayLiteralExpression) {
        property.type = "array";
        property.childType = initializer.elements[0].text;
    }
    else {
        property.type = initializer.text;
    }
}
function inspectNode(node, context, decoratorName) {
    switch (node.kind) {
        case ts__namespace.SyntaxKind.ImportClause:
            const specifier = node.parent.moduleSpecifier;
            if (specifier && specifier.text.startsWith('.')) {
                const currentDir = path__namespace.dirname(node.getSourceFile().fileName);
                const pathToImport = path__namespace.resolve(currentDir, specifier.text);
                parseFiles([pathToImport], decoratorName, globalContext);
            }
            break;
        case ts__namespace.SyntaxKind.ClassDeclaration:
            currentStructure = new Class();
            const heritageClauses = node.heritageClauses;
            if (heritageClauses && heritageClauses.length > 0) {
                currentStructure.extends = heritageClauses[0].types[0].expression.getText();
            }
            context.addStructure(currentStructure);
            break;
        case ts__namespace.SyntaxKind.InterfaceDeclaration:
            //
            // Only generate Interfaces if it has "Message" on its name.
            // Example: MyMessage
            //
            const interfaceName = node.name.escapedText.toString();
            if (interfaceName.indexOf("Message") !== -1) {
                currentStructure = new Interface();
                currentStructure.name = interfaceName;
                context.addStructure(currentStructure);
            }
            break;
        case ts__namespace.SyntaxKind.EnumDeclaration:
            const enumName = node.name.escapedText.toString();
            currentStructure = new Enum();
            currentStructure.name = enumName;
            context.addStructure(currentStructure);
            break;
        case ts__namespace.SyntaxKind.ExtendsKeyword:
            // console.log(node.getText());
            break;
        case ts__namespace.SyntaxKind.PropertySignature:
            if (currentStructure instanceof Interface) {
                const parent = node.parent;
                // Only process direct children of InterfaceDeclaration, skip TypeLiterals
                if (!ts__namespace.isInterfaceDeclaration(parent)) {
                    break;
                }
                // Skip if property if for a another interface than the one we're interested in.
                if (currentStructure.name !== parent.name.escapedText.toString()) {
                    break;
                }
                // define a property of an interface
                const property = new Property();
                property.name = node.name.escapedText.toString();
                property.type = node.type.getText();
                currentStructure.addProperty(property);
            }
            break;
        case ts__namespace.SyntaxKind.Identifier:
            if (node.getText() === "deprecated" &&
                node.parent.kind !== ts__namespace.SyntaxKind.ImportSpecifier) {
                currentProperty = new Property();
                currentProperty.deprecated = true;
                break;
            }
            if (node.getText() === decoratorName) {
                const prop = node.parent?.parent?.parent;
                const propDecorator = getDecorators(prop);
                const hasExpression = prop?.expression?.arguments;
                const hasDecorator = (propDecorator?.length > 0);
                /**
                 * neither a `@type()` decorator or `type()` call. skip.
                 */
                if (!hasDecorator && !hasExpression) {
                    break;
                }
                // using as decorator
                if (propDecorator) {
                    /**
                     * Calling `@type()` as decorator
                     */
                    const typeDecorator = propDecorator.find((decorator => {
                        return decorator.expression.expression.escapedText === decoratorName;
                    })).expression;
                    const property = currentProperty || new Property();
                    property.name = prop.name.escapedText;
                    currentStructure.addProperty(property);
                    const typeArgument = typeDecorator.arguments[0];
                    defineProperty(property, typeArgument);
                }
                else if (prop.expression.arguments?.[1] &&
                    prop.expression.expression.arguments?.[0]) {
                    /**
                     * Calling `type()` as a regular method
                     */
                    const property = currentProperty || new Property();
                    property.name = prop.expression.arguments[1].text;
                    currentStructure.addProperty(property);
                    const typeArgument = prop.expression.expression.arguments[0];
                    defineProperty(property, typeArgument);
                }
            }
            else if (node.getText() === "setFields" &&
                (node.parent.kind === ts__namespace.SyntaxKind.CallExpression ||
                    node.parent.kind === ts__namespace.SyntaxKind.PropertyAccessExpression)) {
                /**
                 * Metadata.setFields(klassName, { ... })
                 */
                const callExpression = (node.parent.kind === ts__namespace.SyntaxKind.PropertyAccessExpression)
                    ? node.parent.parent
                    : node.parent;
                /**
                 * Skip if @codegen-ignore comment is found before the call expression
                 * TODO: currently, if @codegen-ignore is on the file, it will skip all the setFields calls.
                 */
                const sourceFile = node.getSourceFile();
                const fullText = sourceFile.getFullText();
                const nodeStart = callExpression.getFullStart();
                const textBeforeNode = fullText.substring(0, nodeStart);
                if (textBeforeNode.includes('@codegen-ignore')) {
                    break;
                }
                if (callExpression.kind !== ts__namespace.SyntaxKind.CallExpression) {
                    break;
                }
                const classNameNode = callExpression.arguments[0];
                const className = ts__namespace.isClassExpression(classNameNode)
                    ? classNameNode.name?.escapedText.toString()
                    : classNameNode.getText();
                // skip if no className is provided
                if (!className) {
                    break;
                }
                if (currentStructure?.name !== className) {
                    currentStructure = new Class();
                }
                context.addStructure(currentStructure);
                currentStructure.extends = "Schema"; // force extends to Schema
                currentStructure.name = className;
                const types = callExpression.arguments[1];
                for (let i = 0; i < types.properties.length; i++) {
                    const prop = types.properties[i];
                    const property = currentProperty || new Property();
                    property.name = prop.name.escapedText;
                    currentStructure.addProperty(property);
                    defineProperty(property, prop.initializer);
                }
            }
            else if (node.getText() === "defineTypes" &&
                (node.parent.kind === ts__namespace.SyntaxKind.CallExpression ||
                    node.parent.kind === ts__namespace.SyntaxKind.PropertyAccessExpression)) {
                /**
                 * JavaScript source file (`.js`)
                 * Using `defineTypes()`
                 */
                const callExpression = (node.parent.kind === ts__namespace.SyntaxKind.PropertyAccessExpression)
                    ? node.parent.parent
                    : node.parent;
                if (callExpression.kind !== ts__namespace.SyntaxKind.CallExpression) {
                    break;
                }
                const className = callExpression.arguments[0].getText();
                currentStructure.name = className;
                const types = callExpression.arguments[1];
                for (let i = 0; i < types.properties.length; i++) {
                    const prop = types.properties[i];
                    const property = currentProperty || new Property();
                    property.name = prop.name.escapedText;
                    currentStructure.addProperty(property);
                    defineProperty(property, prop.initializer);
                }
            }
            if (node.parent.kind === ts__namespace.SyntaxKind.ClassDeclaration) {
                currentStructure.name = node.getText();
            }
            currentProperty = undefined;
            break;
        case ts__namespace.SyntaxKind.CallExpression:
            /**
             * Defining schema via `schema.schema({ ... })`
             * - schema.schema({})
             * - schema({})
             * - ClassName.extends({})
             */
            if (((node.expression?.getText() === "schema.schema" ||
                node.expression?.getText() === "schema") ||
                (node.expression?.getText().indexOf(".extends") !== -1)) &&
                node.arguments[0].kind === ts__namespace.SyntaxKind.ObjectLiteralExpression) {
                const callExpression = node;
                let className = callExpression.arguments[1]?.getText();
                if (!className && callExpression.parent.kind === ts__namespace.SyntaxKind.VariableDeclaration) {
                    className = callExpression.parent.name?.getText();
                }
                // skip if no className is provided
                if (!className) {
                    break;
                }
                if (currentStructure?.name !== className) {
                    currentStructure = new Class();
                    context.addStructure(currentStructure);
                }
                if (node.expression?.getText().indexOf(".extends") !== -1) {
                    // if it's using `.extends({})`
                    const extendsClass = node.expression?.expression?.escapedText;
                    // skip if no extendsClass is provided
                    if (!extendsClass) {
                        break;
                    }
                    currentStructure.extends = extendsClass;
                }
                else {
                    // if it's using `schema({})`
                    currentStructure.extends = "Schema"; // force extends to Schema
                }
                currentStructure.name = className;
                const types = callExpression.arguments[0];
                for (let i = 0; i < types.properties.length; i++) {
                    const prop = types.properties[i];
                    const property = currentProperty || new Property();
                    property.name = prop.name.escapedText;
                    currentStructure.addProperty(property);
                    defineProperty(property, prop.initializer);
                }
            }
            break;
        case ts__namespace.SyntaxKind.EnumMember:
            if (currentStructure instanceof Enum) {
                const initializer = node.initializer?.text;
                const name = node.getFirstToken().getText();
                const property = currentProperty || new Property();
                property.name = name;
                if (initializer !== undefined) {
                    property.type = initializer;
                }
                currentStructure.addProperty(property);
                currentProperty = undefined;
            }
            break;
    }
    ts__namespace.forEachChild(node, (n) => inspectNode(n, context, decoratorName));
}
let parsedFiles;
function parseFiles(fileNames, decoratorName = "type", context = new Context()) {
    if (typeof ts__namespace.createSourceFile !== "function") {
        // typescript@7+ (native) no longer ships the JS compiler API
        throw new Error(`schema-codegen requires the TypeScript compiler API, which the installed "typescript@${ts__namespace.version}" package does not provide.\n` +
            `TypeScript 7+ no longer ships the JS compiler API — install typescript 5.x or 6.x (e.g. \`npm install --save-dev typescript@6\`) to use schema-codegen.`);
    }
    /**
     * Re-set globalContext for each test case
     */
    if (globalContext !== context) {
        parsedFiles = {};
        globalContext = context;
    }
    fileNames.forEach((fileName) => {
        let sourceFile;
        let sourceFileName;
        const fileNameAlternatives = [];
        if (!fileName.endsWith(".ts") &&
            !fileName.endsWith(".js") &&
            !fileName.endsWith(".mjs")) {
            fileNameAlternatives.push(`${fileName}.ts`);
            fileNameAlternatives.push(`${fileName}/index.ts`);
        }
        else if (fileName.endsWith(".js")) {
            // Handle .js extensions by also trying .ts (ESM imports often use .js extension)
            fileNameAlternatives.push(fileName);
            fileNameAlternatives.push(fileName.replace(/\.js$/, ".ts"));
        }
        else {
            fileNameAlternatives.push(fileName);
        }
        for (let i = 0; i < fileNameAlternatives.length; i++) {
            try {
                sourceFileName = path__namespace.resolve(fileNameAlternatives[i]);
                if (parsedFiles[sourceFileName]) {
                    break;
                }
                sourceFile = ts__namespace.createSourceFile(sourceFileName, fs.readFileSync(sourceFileName).toString(), ts__namespace.ScriptTarget.Latest, true);
                parsedFiles[sourceFileName] = true;
                break;
            }
            catch (e) {
                // only swallow fs errors (ENOENT/EISDIR) while probing alternatives
                if (!e?.code) {
                    throw e;
                }
            }
        }
        if (sourceFile) {
            inspectNode(sourceFile, context, decoratorName);
        }
    });
    return context.getStructures();
}
/**
 * TypeScript 4.8+ has introduced a change on how to access decorators.
 * - https://github.com/microsoft/TypeScript/pull/49089
 * - https://devblogs.microsoft.com/typescript/announcing-typescript-4-8/#decorators-are-placed-on-modifiers-on-typescripts-syntax-trees
 */
function getDecorators(node) {
    if (node == undefined) {
        return undefined;
    }
    // TypeScript 4.7 and below
    // @ts-ignore
    if (node.decorators) {
        return node.decorators;
    }
    // TypeScript 4.8 and above
    // @ts-ignore
    if (ts__namespace.canHaveDecorators && ts__namespace.canHaveDecorators(node)) {
        // @ts-ignore
        const decorators = ts__namespace.getDecorators(node);
        return decorators ? Array.from(decorators) : undefined;
    }
    // @ts-ignore
    return node.modifiers?.filter(ts__namespace.isDecorator);
}

const name$8 = "Unity/C#";
const typeMaps$8 = {
    "string": "string",
    "number": "float",
    "boolean": "bool",
    "int8": "sbyte",
    "uint8": "byte",
    "int16": "short",
    "uint16": "ushort",
    "int32": "int",
    "uint32": "uint",
    "int64": "long",
    "uint64": "ulong",
    "float32": "float",
    "float64": "double",
};
const COMMON_IMPORTS$5 = `using Colyseus.Schema;
#if UNITY_5_3_OR_NEWER
using UnityEngine.Scripting;
#endif`;
/**
 * C# Code Generator
 */
const capitalize$1 = (s) => {
    if (typeof s !== 'string')
        return '';
    return s.charAt(0).toUpperCase() + s.slice(1);
};
/**
 * Generate individual files for each class/interface/enum
 */
function generate$9(context, options) {
    // enrich typeMaps with enums
    context.enums.forEach((structure) => {
        typeMaps$8[structure.name] = structure.name;
    });
    return [
        ...context.classes.map(structure => ({
            name: `${structure.name}.cs`,
            content: generateClass$8(structure, options.namespace)
        })),
        ...context.interfaces.map(structure => ({
            name: `${structure.name}.cs`,
            content: generateInterface$1(structure, options.namespace),
        })),
        ...context.enums.filter(structure => structure.name !== 'OPERATION').map((structure) => ({
            name: `${structure.name}.cs`,
            content: generateEnum$1(structure, options.namespace),
        })),
    ];
}
/**
 * Generate a single bundled file containing all classes, interfaces, and enums
 */
function renderBundle$8(context, options) {
    const fileName = options.namespace ? `${options.namespace}.cs` : "Schema.cs";
    const indent = options.namespace ? "\t" : "";
    // enrich typeMaps with enums
    context.enums.forEach((structure) => {
        typeMaps$8[structure.name] = structure.name;
    });
    // Collect all bodies
    const classBodies = context.classes.map(klass => generateClassBody$8(klass, indent));
    const interfaceBodies = context.interfaces.map(iface => generateInterfaceBody$1(iface, indent));
    const enumBodies = context.enums
        .filter(structure => structure.name !== 'OPERATION')
        .map(e => generateEnumBody$1(e, indent));
    const allBodies = [...classBodies, ...interfaceBodies, ...enumBodies].join("\n\n");
    const content = `${getCommentHeader()}

${COMMON_IMPORTS$5}
${options.namespace ? `\nnamespace ${options.namespace} {\n` : ""}
${allBodies}
${options.namespace ? "}" : ""}`;
    return { name: fileName, content };
}
/**
 * Generate just the class body (without imports/namespace) for bundling
 */
function generateClassBody$8(klass, indent = "") {
    return `${indent}public partial class ${klass.name} : ${klass.extends} {
#if UNITY_5_3_OR_NEWER
[Preserve]
#endif
public ${klass.name}() { }
${klass.properties.map((prop) => generateProperty$4(prop, indent)).join("\n\n")}
${indent}}`;
}
/**
 * Generate a complete class file with imports/namespace (for individual file mode)
 */
function generateClass$8(klass, namespace) {
    const indent = (namespace) ? "\t" : "";
    return `${getCommentHeader()}

${COMMON_IMPORTS$5}
${namespace ? `\nnamespace ${namespace} {` : ""}
${generateClassBody$8(klass, indent)}
${namespace ? "}" : ""}
`;
}
/**
 * Check if all enum members resolve to non-negative integers,
 * allowing emission as a native C# `enum` (which only supports integral types).
 */
function canUseNativeEnum(_enum) {
    return _enum.properties.every((prop) => {
        if (!prop.type)
            return true;
        const n = Number(prop.type);
        return Number.isInteger(n) && n >= 0;
    });
}
/**
 * Generate just the enum body (without imports/namespace) for bundling
 */
function generateEnumBody$1(_enum, indent = "") {
    if (canUseNativeEnum(_enum)) {
        const members = _enum.properties
            .map((prop, i) => {
            const value = prop.type ? Number(prop.type) : i;
            return `${indent}\t${prop.name} = ${value},`;
        })
            .join("\n");
        return `${indent}public enum ${_enum.name} : int {
${members}
${indent}}`;
    }
    return `${indent}public struct ${_enum.name} {

${_enum.properties
        .map((prop) => {
        let dataType = "int";
        let value;
        if (prop.type) {
            if (isNaN(Number(prop.type))) {
                value = `"${prop.type}"`;
                dataType = "string";
            }
            else {
                value = Number(prop.type);
                dataType = Number.isInteger(value) ? 'int' : 'float';
            }
        }
        else {
            value = _enum.properties.indexOf(prop);
        }
        return `${indent}\tpublic const ${dataType} ${prop.name} = ${value};`;
    })
        .join("\n")}
${indent}}`;
}
/**
 * Generate a complete enum file with imports/namespace (for individual file mode)
 */
function generateEnum$1(_enum, namespace) {
    const indent = namespace ? "\t" : "";
    return `${getCommentHeader()}
${namespace ? `\nnamespace ${namespace} {` : ""}
${generateEnumBody$1(_enum, indent)}
${namespace ? "}" : ""}`;
}
function generateProperty$4(prop, indent = "") {
    let typeArgs = `"${prop.type}"`;
    let property = "public";
    let langType;
    let initializer = "";
    if (prop.childType) {
        const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
        langType = getType(prop);
        typeArgs += `, typeof(${langType})`;
        if (!isUpcaseFirst) {
            typeArgs += `, "${prop.childType}"`;
        }
        initializer = `null`;
    }
    else {
        langType = getType(prop);
        initializer = `default(${langType})`;
    }
    property += ` ${langType} ${prop.name}`;
    let ret = (prop.deprecated) ? `\t\t[System.Obsolete("field '${prop.name}' is deprecated.", true)]\n` : '';
    return ret + `\t${indent}[Type(${prop.index}, ${typeArgs})]
\t${indent}${property} = ${initializer};`;
}
/**
 * Generate just the interface body (without imports/namespace) for bundling
 */
function generateInterfaceBody$1(struct, indent = "") {
    return `${indent}public class ${struct.name} {
${struct.properties.map(prop => `\t${indent}public ${getType(prop)} ${prop.name};`).join("\n")}
${indent}}`;
}
/**
 * Generate a complete interface file with imports/namespace (for individual file mode)
 */
function generateInterface$1(struct, namespace) {
    const indent = (namespace) ? "\t" : "";
    return `${getCommentHeader()}

using Colyseus.Schema;
${namespace ? `\nnamespace ${namespace} {` : ""}
${generateInterfaceBody$1(struct, indent)}
${namespace ? "}" : ""}
`;
}
function getChildType(prop) {
    return typeMaps$8[prop.childType];
}
function getType(prop) {
    if (prop.childType) {
        const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
        let type;
        if (prop.type === "ref") {
            type = (isUpcaseFirst)
                ? prop.childType
                : getChildType(prop);
        }
        else {
            const containerClass = capitalize$1(prop.type);
            type = (isUpcaseFirst)
                ? `${containerClass}Schema<${prop.childType}>`
                : `${containerClass}Schema<${getChildType(prop)}>`;
        }
        return type;
    }
    else {
        return (prop.type === "array")
            ? `${typeMaps$8[prop.childType] || prop.childType}[]`
            : typeMaps$8[prop.type];
    }
}

var csharp = /*#__PURE__*/Object.freeze({
    __proto__: null,
    generate: generate$9,
    name: name$8,
    renderBundle: renderBundle$8
});

const name$7 = "C++";
const typeMaps$7 = {
    "string": "string",
    "number": "varint_t",
    "boolean": "bool",
    "int8": "int8_t",
    "uint8": "uint8_t",
    "int16": "int16_t",
    "uint16": "uint16_t",
    "int32": "int32_t",
    "uint32": "uint32_t",
    "int64": "int64_t",
    "uint64": "uint64_t",
    "float32": "float32_t",
    "float64": "float64_t",
};
const typeInitializer$2 = {
    "string": '""',
    "number": "0",
    "boolean": "false",
    "int8": "0",
    "uint8": "0",
    "int16": "0",
    "uint16": "0",
    "int32": "0",
    "uint32": "0",
    "int64": "0",
    "uint64": "0",
    "float32": "0",
    "float64": "0",
};
const COMMON_INCLUDES$1 = `#include "schema.h"
#include <typeinfo>
#include <typeindex>

using namespace colyseus::schema;`;
/**
 * C++ Code Generator
 */
const capitalize = (s) => {
    if (typeof s !== 'string')
        return '';
    return s.charAt(0).toUpperCase() + s.slice(1);
};
const distinct$5 = (value, index, self) => self.indexOf(value) === index;
/**
 * Generate individual files for each class
 */
function generate$8(context, options) {
    return context.classes.map(klass => ({
        name: klass.name + ".hpp",
        content: generateClass$7(klass, options.namespace, context.classes)
    }));
}
/**
 * Generate a single bundled header file containing all classes
 */
function renderBundle$7(context, options) {
    const fileName = options.namespace ? `${options.namespace}.hpp` : "schema.hpp";
    const guardName = `__SCHEMA_CODEGEN_${(options.namespace || "SCHEMA").toUpperCase()}_H__`;
    const classBodies = context.classes.map(klass => generateClassBody$7(klass, context.classes, options.namespace));
    const content = `${getCommentHeader()}
#ifndef ${guardName}
#define ${guardName} 1

${COMMON_INCLUDES$1}

${options.namespace ? `namespace ${options.namespace} {\n` : ""}
${classBodies.join("\n\n")}
${options.namespace ? "}" : ""}

#endif
`;
    return { name: fileName, content };
}
/**
 * Generate just the class body (without includes/guards) for bundling
 */
function generateClassBody$7(klass, allClasses, namespace) {
    const propertiesPerType = {};
    const allRefs = [];
    klass.properties.forEach(property => {
        let type = property.type;
        if (!propertiesPerType[type]) {
            propertiesPerType[type] = [];
        }
        propertiesPerType[type].push(property);
        // keep all refs list
        if ((type === "ref" || type === "array" || type === "map")) {
            allRefs.push(property);
        }
    });
    const allProperties = getAllProperties$1(klass, allClasses);
    const createInstanceMethod = (allRefs.length === 0) ? "" :
        `\tinline Schema* createInstance(std::type_index type) {
\t\t${generateFieldIfElseChain(allRefs, (property) => `type == typeid(${property.childType})`, (property) => `return new ${property.childType}();`, (property) => typeMaps$7[property.childType] === undefined)}
\t\treturn ${klass.extends}::createInstance(type);
\t}`;
    return `class ${klass.name} : public ${klass.extends} {
public:
${klass.properties.map(prop => generateProperty$3(prop)).join("\n")}

\t${klass.name}() {
\t\tthis->_indexes = ${generateAllIndexes(allProperties)};
\t\tthis->_types = ${generateAllTypes(allProperties)};
\t\tthis->_childPrimitiveTypes = ${generateAllChildPrimitiveTypes(allProperties)};
\t\tthis->_childSchemaTypes = ${generateAllChildSchemaTypes(allProperties)};
\t}

\tvirtual ~${klass.name}() {
\t\t${generateDestructors(allProperties).join("\n\t\t")}
\t}

protected:
${Object.keys(propertiesPerType).map(type => generateGettersAndSetters(klass, type, propertiesPerType[type])).
        join("\n")}

${createInstanceMethod}
};`;
}
/**
 * Generate a complete class file with includes/guards (for individual file mode)
 */
function generateClass$7(klass, namespace, allClasses) {
    const allRefs = [];
    klass.properties.forEach(property => {
        let type = property.type;
        // keep all refs list
        if ((type === "ref" || type === "array" || type === "map")) {
            allRefs.push(property);
        }
    });
    const localIncludes = allRefs.
        filter(ref => ref.childType && typeMaps$7[ref.childType] === undefined).
        map(ref => ref.childType).
        concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name)).
        filter(distinct$5).
        map(childType => `#include "${childType}.hpp"`).
        join("\n");
    return `${getCommentHeader()}
#ifndef __SCHEMA_CODEGEN_${klass.name.toUpperCase()}_H__
#define __SCHEMA_CODEGEN_${klass.name.toUpperCase()}_H__ 1

${COMMON_INCLUDES$1}
${localIncludes}

${namespace ? `namespace ${namespace} {` : ""}
${generateClassBody$7(klass, allClasses)}
${namespace ? "}" : ""}

#endif
`;
}
function generateProperty$3(prop) {
    let property = "";
    let langType;
    let initializer = "";
    let isPropPointer = "";
    if (prop.childType) {
        const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
        if (prop.type === "ref") {
            langType = `${prop.childType}`;
            initializer = `new ${prop.childType}()`;
        }
        else if (prop.type === "array") {
            langType = (isUpcaseFirst)
                ? `ArraySchema<${prop.childType}*>`
                : `ArraySchema<${typeMaps$7[prop.childType]}>`;
            initializer = `new ${langType}()`;
        }
        else if (prop.type === "map") {
            langType = (isUpcaseFirst)
                ? `MapSchema<${prop.childType}*>`
                : `MapSchema<${typeMaps$7[prop.childType]}>`;
            initializer = `new ${langType}()`;
        }
        isPropPointer = "*";
    }
    else {
        langType = typeMaps$7[prop.type];
        initializer = typeInitializer$2[prop.type];
    }
    property += ` ${langType} ${isPropPointer}${prop.name}`;
    return `\t${property} = ${initializer};`;
}
function generateGettersAndSetters(klass, type, properties) {
    let langType = typeMaps$7[type];
    let typeCast = "";
    const getMethodName = `get${capitalize(type)}`;
    const setMethodName = `set${capitalize(type)}`;
    if (type === "ref") {
        langType = "Schema*";
    }
    else if (type === "array") {
        langType = `ArraySchema<char*> *`;
        typeCast = `(ArraySchema<char*> *)`;
    }
    else if (type === "map") {
        langType = `MapSchema<char*> *`;
        typeCast = `(MapSchema<char*> *)`;
    }
    return `\tinline ${langType} ${getMethodName}(const string &field)
\t{
\t\t${generateFieldIfElseChain(properties, (property) => `field == "${property.name}"`, (property) => `return ${typeCast}this->${property.name};`)}
\t\treturn ${klass.extends}::${getMethodName}(field);
\t}

\tinline void ${setMethodName}(const string &field, ${langType} value)
\t{
\t\t${generateFieldIfElseChain(properties, (property) => `field == "${property.name}"`, (property) => {
        const isSchemaType = (typeMaps$7[property.childType] === undefined);
        if (type === "ref") {
            langType = `${property.childType}*`;
            typeCast = (isSchemaType)
                ? `(${property.childType}*)`
                : `/* bug? */`;
        }
        else if (type === "array") {
            typeCast = (isSchemaType)
                ? `(ArraySchema<${property.childType}*> *)`
                : `(ArraySchema<${typeMaps$7[property.childType]}> *)`;
        }
        else if (type === "map") {
            typeCast = (isSchemaType)
                ? `(MapSchema<${property.childType}*> *)`
                : `(MapSchema<${typeMaps$7[property.childType]}> *)`;
        }
        return `this->${property.name} = ${typeCast}value;\n\t\t\treturn;`;
    })}
\t\treturn ${klass.extends}::${setMethodName}(field, value);
\t}`;
}
function generateFieldIfElseChain(properties, ifCallback, callback, filter = (_) => true) {
    let chain = "";
    const uniqueChecks = [];
    properties.filter(filter).forEach((property, i) => {
        const check = ifCallback(property);
        if (uniqueChecks.indexOf(check) === -1) {
            uniqueChecks.push(check);
        }
        else {
            return;
        }
        if (i === 0) {
            chain += "if ";
        }
        else {
            chain += " else if ";
        }
        chain += `(${check})
\t\t{
\t\t\t${callback(property)}\n
\t\t}`;
    });
    return chain;
}
function generateAllIndexes(properties) {
    return `{${properties.map((property, i) => `{${i}, "${property.name}"}`).join(", ")}}`;
}
function generateAllTypes(properties) {
    return `{${properties.map((property, i) => `{${i}, "${property.type}"}`).join(", ")}}`;
}
function generateAllChildSchemaTypes(properties) {
    return `{${properties.map((property, i) => {
        if (property.childType && typeMaps$7[property.childType] === undefined) {
            return `{${i}, typeid(${property.childType})}`;
        }
        else {
            return null;
        }
    }).filter(r => r !== null).join(", ")}}`;
}
function generateAllChildPrimitiveTypes(properties) {
    return `{${properties.map((property, i) => {
        if (typeMaps$7[property.childType] !== undefined) {
            return `{${i}, "${property.childType}"}`;
        }
        else {
            return null;
        }
    }).filter(r => r !== null).join(", ")}}`;
}
function generateDestructors(properties) {
    return properties.map((property, i) => {
        if (property.childType) {
            return `delete this->${property.name};`;
        }
        else {
            return null;
        }
    }).filter(r => r !== null);
}
function getAllProperties$1(klass, allClasses) {
    let properties = [];
    getInheritanceTree(klass, allClasses).reverse().forEach((klass) => {
        properties = properties.concat(klass.properties);
    });
    return properties;
}

var cpp = /*#__PURE__*/Object.freeze({
    __proto__: null,
    generate: generate$8,
    name: name$7,
    renderBundle: renderBundle$7
});

const name$6 = "Haxe";
const typeMaps$6 = {
    "string": "String",
    "number": "Dynamic",
    "boolean": "Bool",
    "int8": "Int",
    "uint8": "UInt",
    "int16": "Int",
    "uint16": "UInt",
    "int32": "Int",
    "uint32": "UInt",
    "int64": "Int",
    "uint64": "UInt",
    "float32": "Float",
    "float64": "Float",
};
const typeInitializer$1 = {
    "string": '""',
    "number": "0",
    "boolean": "false",
    "int8": "0",
    "uint8": "0",
    "int16": "0",
    "uint16": "0",
    "int32": "0",
    "uint32": "0",
    "int64": "0",
    "uint64": "0",
    "float32": "0",
    "float64": "0",
};
const COMMON_IMPORTS$4 = `import io.colyseus.serializer.schema.Schema;
import io.colyseus.serializer.schema.types.*;`;
/**
 * Generate individual files for each class
 */
function generate$7(context, options) {
    return context.classes.map(klass => ({
        name: klass.name + ".hx",
        content: generateClass$6(klass, options.namespace, context.classes)
    }));
}
/**
 * Generate a single bundled file containing all classes
 */
function renderBundle$6(context, options) {
    const fileName = options.namespace ? `${options.namespace}.hx` : "Schema.hx";
    const classBodies = context.classes.map(klass => generateClassBody$6(klass));
    const content = `${getCommentHeader()}

${options.namespace ? `package ${options.namespace};` : ""}
${COMMON_IMPORTS$4}

${classBodies.join("\n\n")}
`;
    return { name: fileName, content };
}
/**
 * Generate just the class body (without package/imports) for bundling
 */
function generateClassBody$6(klass) {
    return `class ${klass.name} extends ${klass.extends} {
${klass.properties.map(prop => generateProperty$2(prop)).join("\n")}
}`;
}
/**
 * Generate a complete class file with package/imports (for individual file mode)
 */
function generateClass$6(klass, namespace, allClasses) {
    return `${getCommentHeader()}

${namespace ? `package ${namespace};` : ""}
${COMMON_IMPORTS$4}

${generateClassBody$6(klass)}
`;
}
function generateProperty$2(prop) {
    let langType;
    let initializer = "";
    let typeArgs = `"${prop.type}"`;
    if (prop.childType) {
        const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
        if (isUpcaseFirst) {
            typeArgs += `, ${prop.childType}`;
        }
        else {
            typeArgs += `, "${prop.childType}"`;
        }
        if (prop.type === "ref") {
            langType = `${prop.childType}`;
            initializer = `new ${prop.childType}()`;
        }
        else if (prop.type === "array") {
            langType = (isUpcaseFirst)
                ? `ArraySchema<${prop.childType}>`
                : `ArraySchema<${typeMaps$6[prop.childType]}>`;
            initializer = `new ${langType}()`;
        }
        else if (prop.type === "map") {
            langType = (isUpcaseFirst)
                ? `MapSchema<${prop.childType}>`
                : `MapSchema<${typeMaps$6[prop.childType]}>`;
            initializer = `new ${langType}()`;
        }
    }
    else {
        langType = typeMaps$6[prop.type];
        initializer = typeInitializer$1[prop.type];
    }
    // TODO: remove initializer. The callbacks at the Haxe decoder side have a
    // "FIXME" comment about this on Decoder.hx
    return `\t@:type(${typeArgs})\n\tpublic var ${prop.name}: ${langType} = ${initializer};\n`;
    // return `\t@:type(${typeArgs})\n\tpublic var ${prop.name}: ${langType};\n`
}

var haxe = /*#__PURE__*/Object.freeze({
    __proto__: null,
    generate: generate$7,
    name: name$6,
    renderBundle: renderBundle$6
});

const name$5 = "TypeScript";
const typeMaps$5 = {
    "string": "string",
    "number": "number",
    "boolean": "boolean",
    "int8": "number",
    "uint8": "number",
    "int16": "number",
    "uint16": "number",
    "int32": "number",
    "uint32": "number",
    "int64": "number",
    "uint64": "number",
    "float32": "number",
    "float64": "number",
};
const COMMON_IMPORTS$3 = `import { Schema, type, ArraySchema, MapSchema, SetSchema, DataChange } from '@colyseus/schema';`;
const distinct$4 = (value, index, self) => self.indexOf(value) === index;
/**
 * Generate individual files for each class/interface
 */
function generate$6(context, options) {
    return [
        ...context.classes.map(structure => ({
            name: structure.name + ".ts",
            content: generateClass$5(structure, options.namespace, context.classes)
        })),
        ...context.interfaces.map(structure => ({
            name: structure.name + ".ts",
            content: generateInterface(structure, options.namespace, context.classes),
        }))
    ];
}
/**
 * Generate a single bundled file containing all classes and interfaces
 */
function renderBundle$5(context, options) {
    const fileName = options.namespace ? `${options.namespace}.ts` : "schema.ts";
    // Collect all class bodies
    const classBodies = context.classes.map(klass => generateClassBody$5(klass));
    // Collect all interface bodies
    const interfaceBodies = context.interfaces.map(iface => generateInterfaceBody(iface));
    const content = `${getCommentHeader()}

${COMMON_IMPORTS$3}

${classBodies.join("\n\n")}
${interfaceBodies.length > 0 ? "\n" + interfaceBodies.join("\n\n") : ""}`;
    return { name: fileName, content };
}
/**
 * Generate just the class body (without imports) for bundling
 */
function generateClassBody$5(klass) {
    return `export class ${klass.name} extends ${klass.extends} {
${klass.properties.map(prop => `    ${generateProperty$1(prop)}`).join("\n")}
}`;
}
/**
 * Generate just the interface body (without imports) for bundling
 */
function generateInterfaceBody(iface) {
    return `export interface ${iface.name} {
${iface.properties.map(prop => `    ${prop.name}: ${prop.type};`).join("\n")}
}`;
}
/**
 * Generate a complete class file with imports (for individual file mode)
 */
function generateClass$5(klass, namespace, allClasses) {
    const allRefs = [];
    klass.properties.forEach(property => {
        let type = property.type;
        // keep all refs list
        if ((type === "ref" || type === "array" || type === "map" || type === "set")) {
            allRefs.push(property);
        }
    });
    const localImports = allRefs.
        filter(ref => ref.childType && typeMaps$5[ref.childType] === undefined).
        map(ref => ref.childType).
        concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name)).
        filter(distinct$4).
        map(childType => `import { ${childType} } from './${childType}'`).
        join("\n");
    return `${getCommentHeader()}

${COMMON_IMPORTS$3}
${localImports}

${generateClassBody$5(klass)}
`;
}
function generateProperty$1(prop) {
    let langType;
    let initializer = "";
    let typeArgs;
    if (prop.childType) {
        const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
        if (isUpcaseFirst) {
            typeArgs += `, ${prop.childType}`;
        }
        else {
            typeArgs += `, "${prop.childType}"`;
        }
        if (prop.type === "ref") {
            langType = `${prop.childType}`;
            initializer = `new ${prop.childType}()`;
            typeArgs = `${prop.childType}`;
        }
        else if (prop.type === "array") {
            langType = (isUpcaseFirst)
                ? `ArraySchema<${prop.childType}>`
                : `ArraySchema<${typeMaps$5[prop.childType]}>`;
            initializer = `new ${langType}()`;
            typeArgs = (isUpcaseFirst)
                ? `[ ${prop.childType} ]`
                : `[ "${prop.childType}" ]`;
        }
        else if (prop.type === "map") {
            langType = (isUpcaseFirst)
                ? `MapSchema<${prop.childType}>`
                : `MapSchema<${typeMaps$5[prop.childType]}>`;
            initializer = `new ${langType}()`;
            typeArgs = (isUpcaseFirst)
                ? `{ map: ${prop.childType} }`
                : `{ map: "${prop.childType}" }`;
        }
        else if (prop.type === "set") {
            langType = (isUpcaseFirst)
                ? `SetSchema<${prop.childType}>`
                : `SetSchema<${typeMaps$5[prop.childType]}>`;
            initializer = `new ${langType}()`;
            typeArgs = (isUpcaseFirst)
                ? `{ set: ${prop.childType} }`
                : `{ set: "${prop.childType}" }`;
        }
    }
    else {
        langType = typeMaps$5[prop.type];
        typeArgs = `"${prop.type}"`;
    }
    // TS1263: "Declarations with initializers cannot also have definite assignment assertions"
    const definiteAssertion = initializer ? "" : "!";
    return `@type(${typeArgs}) public ${prop.name}${definiteAssertion}: ${langType}${(initializer) ? ` = ${initializer}` : ""};`;
}
/**
 * Generate a complete interface file with header (for individual file mode)
 */
function generateInterface(structure, namespace, allClasses) {
    return `${getCommentHeader()}

${generateInterfaceBody(structure)}
`;
}

var ts = /*#__PURE__*/Object.freeze({
    __proto__: null,
    generate: generate$6,
    name: name$5,
    renderBundle: renderBundle$5
});

const name$4 = "JavaScript";
const typeMaps$4 = {
    "string": "string",
    "number": "number",
    "boolean": "boolean",
    "int8": "number",
    "uint8": "number",
    "int16": "number",
    "uint16": "number",
    "int32": "number",
    "uint32": "number",
    "int64": "number",
    "uint64": "number",
    "float32": "number",
    "float64": "number",
};
const COMMON_IMPORTS$2 = `const schema = require("@colyseus/schema");
const Schema = schema.Schema;
const type = schema.type;`;
const distinct$3 = (value, index, self) => self.indexOf(value) === index;
/**
 * Generate individual files for each class
 */
function generate$5(context, options) {
    return context.classes.map(klass => ({
        name: klass.name + ".js",
        content: generateClass$4(klass, options.namespace, context.classes)
    }));
}
/**
 * Generate a single bundled file containing all classes
 */
function renderBundle$4(context, options) {
    const fileName = options.namespace ? `${options.namespace}.js` : "schema.js";
    const classBodies = context.classes.map(klass => generateClassBody$4(klass));
    const classExports = context.classes.map(klass => `    ${klass.name},`).join("\n");
    const content = `${getCommentHeader()}

${COMMON_IMPORTS$2}

${classBodies.join("\n\n")}

module.exports = {
${classExports}
};
`;
    return { name: fileName, content };
}
/**
 * Generate just the class body (without imports) for bundling
 */
function generateClassBody$4(klass) {
    return `class ${klass.name} extends ${klass.extends} {
    constructor () {
        super();
${klass.properties.
        filter(prop => prop.childType !== undefined).
        map(prop => "        " + generatePropertyInitializer(prop)).join("\n")}
    }
}
${klass.properties.map(prop => generatePropertyDeclaration$1(klass.name, prop)).join("\n")}`;
}
/**
 * Generate a complete class file with imports (for individual file mode)
 */
function generateClass$4(klass, namespace, allClasses) {
    const allRefs = [];
    klass.properties.forEach(property => {
        let type = property.type;
        // keep all refs list
        if ((type === "ref" || type === "array" || type === "map")) {
            allRefs.push(property);
        }
    });
    const localImports = allRefs.
        filter(ref => ref.childType && typeMaps$4[ref.childType] === undefined).
        map(ref => ref.childType).
        concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name)).
        filter(distinct$3).
        map(childType => `const ${childType} = require("./${childType}");`).
        join("\n");
    return `${getCommentHeader()}

${COMMON_IMPORTS$2}
${localImports}

${generateClassBody$4(klass)}

export default ${klass.name};
`;
}
function generatePropertyDeclaration$1(className, prop) {
    let typeArgs;
    if (prop.childType) {
        const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
        if (isUpcaseFirst) {
            typeArgs += `, ${prop.childType}`;
        }
        else {
            typeArgs += `, "${prop.childType}"`;
        }
        if (prop.type === "ref") {
            typeArgs = `${prop.childType}`;
        }
        else if (prop.type === "array") {
            typeArgs = (isUpcaseFirst)
                ? `[ ${prop.childType} ]`
                : `[ "${prop.childType}" ]`;
        }
        else if (prop.type === "map") {
            typeArgs = (isUpcaseFirst)
                ? `{ map: ${prop.childType} }`
                : `{ map: "${prop.childType}" }`;
        }
    }
    else {
        typeArgs = `"${prop.type}"`;
    }
    return `type(${typeArgs})(${className}.prototype, "${prop.name}");`;
}
function generatePropertyInitializer(prop) {
    let initializer = "";
    if (prop.type === "ref") {
        initializer = `new ${prop.childType}()`;
    }
    else if (prop.type === "array") {
        initializer = `new schema.ArraySchema()`;
    }
    else if (prop.type === "map") {
        initializer = `new schema.MapSchema()`;
    }
    return `this.${prop.name} = ${initializer}`;
}

var js = /*#__PURE__*/Object.freeze({
    __proto__: null,
    generate: generate$5,
    name: name$4,
    renderBundle: renderBundle$4
});

const name$3 = "Java";
const typeMaps$3 = {
    "string": "String",
    "number": "float",
    "boolean": "boolean",
    "int8": "byte",
    "uint8": "short",
    "int16": "short",
    "uint16": "int",
    "int32": "int",
    "uint32": "long",
    "int64": "long",
    "uint64": "long",
    "float32": "float",
    "float64": "double",
};
const typeInitializer = {
    "string": '""',
    "number": "0",
    "boolean": "false",
    "int8": "0",
    "uint8": "0",
    "int16": "0",
    "uint16": "0",
    "int32": "0",
    "uint32": "0",
    "int64": "0",
    "uint64": "0",
    "float32": "0",
    "float64": "0",
};
const COMMON_IMPORTS$1 = `import io.colyseus.serializer.schema.Schema;
import io.colyseus.serializer.schema.annotations.SchemaClass;
import io.colyseus.serializer.schema.annotations.SchemaField;`;
/**
 * Java Code Generator
 */
/**
 * Generate individual files for each class
 */
function generate$4(context, options) {
    return context.classes.map(klass => ({
        name: klass.name + ".java",
        content: generateClass$3(klass, options.namespace)
    }));
}
/**
 * Generate a single bundled file containing all classes
 * Note: Java typically requires one public class per file, so bundled mode
 * generates all classes in a single file with package-private visibility
 */
function renderBundle$3(context, options) {
    const fileName = options.namespace ? `Schema.java` : "Schema.java";
    const classBodies = context.classes.map(klass => generateClassBody$3(klass));
    const content = `${getCommentHeader()}
${options.namespace ? `\npackage ${options.namespace};` : ""}

${COMMON_IMPORTS$1}

${classBodies.join("\n\n")}
`;
    return { name: fileName, content };
}
/**
 * Generate just the class body (without package/imports) for bundling
 */
function generateClassBody$3(klass) {
    return `@SchemaClass
class ${klass.name} extends ${klass.extends} {
${klass.properties.map(prop => generateProperty(prop, "")).join("\n\n")}
}`;
}
/**
 * Generate a complete class file with package/imports (for individual file mode)
 */
function generateClass$3(klass, namespace) {
    const indent = (namespace) ? "\t" : "";
    return `${getCommentHeader()}
${namespace ? `\npackage ${namespace};` : ""}

${COMMON_IMPORTS$1}

@SchemaClass
${indent}public class ${klass.name} extends ${klass.extends} {
${klass.properties.map(prop => generateProperty(prop, indent)).join("\n\n")}
${indent}}
${namespace ? "}" : ""}
`;
}
function generateProperty(prop, indent = "") {
    let typeArgs = `${prop.index}/${prop.type}`;
    let property = "public";
    let langType;
    let ctorArgs = "";
    let initializer = "";
    if (prop.childType) {
        const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
        if (prop.type !== "ref" && isUpcaseFirst) {
            ctorArgs = `${prop.childType}.class`;
        }
        if (prop.type === "ref") {
            langType = (isUpcaseFirst)
                ? prop.childType
                : typeMaps$3[prop.childType];
            initializer = `new ${langType}${(prop.type !== "ref" && isUpcaseFirst) ? "<>" : ""}(${ctorArgs})`;
        }
        else if (prop.type === "array") {
            langType = (isUpcaseFirst)
                ? `ArraySchema<${prop.childType}>`
                : `ArraySchema`;
            initializer = `new ArraySchema${(isUpcaseFirst) ? "<>" : ""}(${ctorArgs})`;
        }
        else if (prop.type === "map") {
            langType = (isUpcaseFirst)
                ? `MapSchema<${prop.childType}>`
                : `MapSchema`;
            initializer = `new MapSchema${(isUpcaseFirst) ? "<>" : ""}(${ctorArgs})`;
        }
        if (prop.type !== "ref") {
            typeArgs += (isUpcaseFirst)
                ? `/ref`
                : `/${prop.childType}`;
        }
    }
    else {
        langType = typeMaps$3[prop.type];
        initializer = typeInitializer[prop.type];
    }
    property += ` ${langType} ${prop.name}`;
    return `\t@SchemaField("${typeArgs}")\t${indent}
\t${indent}${property} = ${initializer};`;
}

var java = /*#__PURE__*/Object.freeze({
    __proto__: null,
    generate: generate$4,
    name: name$3,
    renderBundle: renderBundle$3
});

const name$2 = "LUA";
/**
    TODO:
    - Support inheritance
    - Support importing Schema dependencies
*/
const typeMaps$2 = {
    "string": "string",
    "number": "number",
    "boolean": "boolean",
    "int8": "number",
    "uint8": "number",
    "int16": "number",
    "uint16": "number",
    "int32": "number",
    "uint32": "number",
    "int64": "number",
    "uint64": "number",
    "float32": "number",
    "float64": "number",
};
const COMMON_IMPORTS = `local schema = require 'colyseus.serializer.schema.schema'`;
const distinct$2 = (value, index, self) => self.indexOf(value) === index;
/**
 * Generate individual files for each class
 */
function generate$3(context, options) {
    return context.classes.map(klass => ({
        name: klass.name + ".lua",
        content: generateClass$2(klass, options.namespace, context.classes)
    }));
}
/**
 * Generate a single bundled file containing all classes
 */
function renderBundle$2(context, options) {
    const fileName = options.namespace ? `${options.namespace}.lua` : "schema.lua";
    const classBodies = context.classes.map(klass => generateClassBody$2(klass));
    const classNames = context.classes.map(klass => `    ${klass.name} = ${klass.name},`).join("\n");
    const content = `${getCommentHeader().replace(/\/\//mg, "--")}

${COMMON_IMPORTS}

${classBodies.join("\n\n")}

return {
${classNames}
}
`;
    return { name: fileName, content };
}
/**
 * Generate just the class body (without requires) for bundling
 */
function generateClassBody$2(klass) {
    // Inheritance support
    const inherits = (klass.extends !== "Schema")
        ? `, ${klass.extends}`
        : "";
    return `---@class ${klass.name}: ${klass.extends}
${klass.properties.map(prop => `---@field ${prop.name} ${getLUATypeAnnotation(prop)}`).join("\n")}
local ${klass.name} = schema.define({
${klass.properties.map(prop => generatePropertyDeclaration(prop)).join(",\n")},
    ["_fields_by_index"] = { ${klass.properties.map(prop => `"${prop.name}"`).join(", ")} },
}${inherits})`;
}
/**
 * Generate a complete class file with requires (for individual file mode)
 */
function generateClass$2(klass, namespace, allClasses) {
    const allRefs = [];
    klass.properties.forEach(property => {
        let type = property.type;
        // keep all refs list
        if ((type === "ref" || type === "array" || type === "map")) {
            allRefs.push(property);
        }
    });
    const localRequires = allRefs.
        filter(ref => ref.childType && typeMaps$2[ref.childType] === undefined).
        map(ref => ref.childType).
        concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name)).
        filter(distinct$2).
        map(childType => `local ${childType} = require '${(namespace ? `${namespace}.` : '')}${childType}'`).
        join("\n");
    return `${getCommentHeader().replace(/\/\//mg, "--")}

${COMMON_IMPORTS}
${localRequires}

${generateClassBody$2(klass)}

return ${klass.name}
`;
}
function generatePropertyDeclaration(prop) {
    let typeArgs;
    if (prop.childType) {
        const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
        if (isUpcaseFirst) {
            typeArgs += `${prop.childType}`;
        }
        else {
            typeArgs += `"${prop.childType}"`;
        }
        if (prop.type === "ref") {
            typeArgs = (isUpcaseFirst)
                ? `${prop.childType}`
                : `"${prop.childType}"`;
        }
        else {
            typeArgs = (isUpcaseFirst)
                ? `{ ${prop.type} = ${prop.childType} }`
                : `{ ${prop.type} = "${prop.childType}" }`;
        }
    }
    else {
        typeArgs = `"${prop.type}"`;
    }
    return `    ["${prop.name}"] = ${typeArgs}`;
}
function getLUATypeAnnotation(prop) {
    if (prop.type === "ref") {
        return prop.childType;
    }
    else if (prop.type === "array") {
        return "ArraySchema";
    }
    else if (prop.type === "map") {
        return "MapSchema";
    }
    else {
        return typeMaps$2[prop.type];
    }
}

var lua = /*#__PURE__*/Object.freeze({
    __proto__: null,
    generate: generate$3,
    name: name$2,
    renderBundle: renderBundle$2
});

const name$1 = "C";
/**
 * Type mappings for C
 */
const typeMaps$1 = {
    "string": "char*",
    "number": "double",
    "boolean": "bool",
    "int8": "int8_t",
    "uint8": "uint8_t",
    "int16": "int16_t",
    "uint16": "uint16_t",
    "int32": "int32_t",
    "uint32": "uint32_t",
    "int64": "int64_t",
    "uint64": "uint64_t",
    "float32": "float",
    "float64": "double",
};
/**
 * Colyseus field type enum mappings
 */
const fieldTypeMaps = {
    "string": "COLYSEUS_FIELD_STRING",
    "number": "COLYSEUS_FIELD_NUMBER",
    "boolean": "COLYSEUS_FIELD_BOOLEAN",
    "int8": "COLYSEUS_FIELD_INT8",
    "uint8": "COLYSEUS_FIELD_UINT8",
    "int16": "COLYSEUS_FIELD_INT16",
    "uint16": "COLYSEUS_FIELD_UINT16",
    "int32": "COLYSEUS_FIELD_INT32",
    "uint32": "COLYSEUS_FIELD_UINT32",
    "int64": "COLYSEUS_FIELD_INT64",
    "uint64": "COLYSEUS_FIELD_UINT64",
    "float32": "COLYSEUS_FIELD_FLOAT32",
    "float64": "COLYSEUS_FIELD_FLOAT64",
    "ref": "COLYSEUS_FIELD_REF",
    "array": "COLYSEUS_FIELD_ARRAY",
    "map": "COLYSEUS_FIELD_MAP",
};
const COMMON_INCLUDES = `#include "colyseus/schema/types.h"
#include "colyseus/schema/collections.h"
#include <stdlib.h>
#include <stddef.h>
#include <stdbool.h>`;
/**
 * Native C Code Generator
 */
const toSnakeCase = (s) => {
    return s.replace(/([A-Z])/g, (match, p1, offset) => (offset > 0 ? '_' : '') + p1.toLowerCase());
};
const distinct$1 = (value, index, self) => self.indexOf(value) === index;
/**
 * Generate individual files for each class
 */
function generate$2(context, options) {
    return context.classes.map(klass => ({
        name: toSnakeCase(klass.name) + ".h",
        content: generateClass$1(klass, options.namespace, context.classes)
    }));
}
/**
 * Generate a single bundled header file containing all classes
 */
function renderBundle$1(context, options) {
    const fileName = options.namespace ? `${toSnakeCase(options.namespace)}.h` : "schema.h";
    const guardName = `__SCHEMA_CODEGEN_${(options.namespace || "SCHEMA").toUpperCase()}_H__`;
    const classBodies = context.classes.map(klass => generateClassBody$1(klass, context.classes)).join("\n\n");
    const content = `${getCommentHeader()}
#ifndef ${guardName}
#define ${guardName} 1

${COMMON_INCLUDES}

${classBodies}

#endif
`;
    return { name: fileName, content };
}
/**
 * Generate just the class body (without guards/includes) for bundling
 */
function generateClassBody$1(klass, allClasses) {
    const snakeName = toSnakeCase(klass.name);
    const typeName = `${snakeName}_t`;
    const allProperties = getAllProperties(klass, allClasses);
    return `${generateTypedef(klass, typeName, allClasses)}

${generateFieldsArray(klass, typeName, snakeName, allProperties)}

${generateCreateFunction(snakeName, typeName)}

${generateDestroyFunction(klass, snakeName, typeName, allProperties)}

${generateVtable(klass, snakeName, typeName, allProperties)}`;
}
/**
 * Generate a complete class file with guards/includes (for individual file mode)
 */
function generateClass$1(klass, namespace, allClasses) {
    toSnakeCase(klass.name);
    const guardName = `__SCHEMA_CODEGEN_${klass.name.toUpperCase()}_H__`;
    const allRefs = [];
    klass.properties.forEach(property => {
        if (property.type === "ref" || property.type === "array" || property.type === "map") {
            allRefs.push(property);
        }
    });
    // Generate includes for referenced schema types
    const refIncludes = allRefs
        .filter(ref => ref.childType && typeMaps$1[ref.childType] === undefined)
        .map(ref => ref.childType)
        .concat(getInheritanceTree(klass, allClasses, false).map(k => k.name))
        .filter(distinct$1)
        .map(childType => `#include "${toSnakeCase(childType)}.h"`)
        .join("\n");
    return `${getCommentHeader()}
#ifndef ${guardName}
#define ${guardName} 1

${COMMON_INCLUDES}
${refIncludes ? `\n${refIncludes}\n` : ""}
${generateClassBody$1(klass, allClasses)}

#endif
`;
}
function generateTypedef(klass, typeName, allClasses) {
    const allProperties = getAllProperties(klass, allClasses);
    const fields = allProperties.map(prop => {
        const cType = getCType(prop);
        return `    ${cType} ${prop.name};`;
    }).join("\n");
    return `typedef struct {
    colyseus_schema_t __base;
${fields}
} ${typeName};`;
}
function getCType(prop) {
    if (prop.type === "ref") {
        return `${toSnakeCase(prop.childType)}_t*`;
    }
    else if (prop.type === "array") {
        if (typeMaps$1[prop.childType]) {
            return `colyseus_array_schema_t*`;
        }
        else {
            return `colyseus_array_schema_t*`;
        }
    }
    else if (prop.type === "map") {
        if (typeMaps$1[prop.childType]) {
            return `colyseus_map_schema_t*`;
        }
        else {
            return `colyseus_map_schema_t*`;
        }
    }
    else {
        return typeMaps$1[prop.type] || `${toSnakeCase(prop.type)}_t*`;
    }
}
function getFieldType(prop) {
    return fieldTypeMaps[prop.type] || "COLYSEUS_FIELD_REF";
}
function getFieldTypeString(prop) {
    // Always return the type itself (ref, array, map, string, number, etc.)
    return prop.type;
}
function generateFieldsArray(klass, typeName, snakeName, allProperties) {
    if (allProperties.length === 0) {
        return `static const colyseus_field_t ${snakeName}_fields[] = {};`;
    }
    const fields = allProperties.map((prop, i) => {
        const fieldType = getFieldType(prop);
        const typeString = getFieldTypeString(prop);
        let vtableRef = "NULL";
        if (prop.type === "ref" && prop.childType && !typeMaps$1[prop.childType]) {
            const childSnake = toSnakeCase(prop.childType);
            vtableRef = `&${childSnake}_vtable`;
        }
        else if ((prop.type === "array" || prop.type === "map") && prop.childType && !typeMaps$1[prop.childType]) {
            const childSnake = toSnakeCase(prop.childType);
            vtableRef = `&${childSnake}_vtable`;
        }
        return `    {${prop.index}, "${prop.name}", ${fieldType}, "${typeString}", offsetof(${typeName}, ${prop.name}), ${vtableRef}, NULL}`;
    }).join(",\n");
    return `static const colyseus_field_t ${snakeName}_fields[] = {
${fields}
};`;
}
function generateCreateFunction(snakeName, typeName) {
    return `static ${typeName}* ${snakeName}_create(void) {
    ${typeName}* instance = calloc(1, sizeof(${typeName}));
    return instance;
}`;
}
function generateDestroyFunction(klass, snakeName, typeName, allProperties) {
    const freeStatements = [];
    allProperties.forEach(prop => {
        if (prop.type === "string") {
            freeStatements.push(`    if (instance->${prop.name}) free(instance->${prop.name});`);
        }
        else if (prop.type === "ref") {
            if (typeMaps$1[prop.childType]) {
                freeStatements.push(`    if (instance->${prop.name}) free(instance->${prop.name});`);
            }
            else {
                const childSnake = toSnakeCase(prop.childType);
                freeStatements.push(`    if (instance->${prop.name}) ${childSnake}_destroy((colyseus_schema_t*)instance->${prop.name});`);
            }
        }
        else if (prop.type === "array" || prop.type === "map") ;
    });
    const freeCode = freeStatements.length > 0 ? freeStatements.join("\n") + "\n" : "";
    return `static void ${snakeName}_destroy(colyseus_schema_t* schema) {
    ${typeName}* instance = (${typeName}*)schema;
${freeCode}    free(instance);
}`;
}
function generateVtable(klass, snakeName, typeName, allProperties) {
    const fieldCount = allProperties.length;
    return `static const colyseus_schema_vtable_t ${snakeName}_vtable = {
    "${klass.name}",
    sizeof(${typeName}),
    (colyseus_schema_t* (*)(void))${snakeName}_create,
    ${snakeName}_destroy,
    ${snakeName}_fields,
    ${fieldCount}
};`;
}
function getAllProperties(klass, allClasses) {
    let properties = [];
    getInheritanceTree(klass, allClasses).reverse().forEach((k) => {
        properties = properties.concat(k.properties);
    });
    return properties;
}

var c = /*#__PURE__*/Object.freeze({
    __proto__: null,
    generate: generate$2,
    name: name$1,
    renderBundle: renderBundle$1
});

const name = "GDScript";
/**
 * Type mappings from schema types to GDScript Colyseus.Schema type constants
 */
const typeMaps = {
    "string": "Colyseus.Schema.STRING",
    "number": "Colyseus.Schema.NUMBER",
    "boolean": "Colyseus.Schema.BOOLEAN",
    "int8": "Colyseus.Schema.INT8",
    "uint8": "Colyseus.Schema.UINT8",
    "int16": "Colyseus.Schema.INT16",
    "uint16": "Colyseus.Schema.UINT16",
    "int32": "Colyseus.Schema.INT32",
    "uint32": "Colyseus.Schema.UINT32",
    "int64": "Colyseus.Schema.INT64",
    "uint64": "Colyseus.Schema.UINT64",
    "float32": "Colyseus.Schema.FLOAT32",
    "float64": "Colyseus.Schema.FLOAT64",
};
const containerMaps = {
    "array": "Colyseus.Schema.ARRAY",
    "map": "Colyseus.Schema.MAP",
    "ref": "Colyseus.Schema.REF",
};
const distinct = (value, index, self) => self.indexOf(value) === index;
/**
 * GDScript Code Generator
 */
/**
 * Generate individual files for each class
 */
function generate$1(context, options) {
    // Enrich typeMaps with enums
    context.enums.forEach((structure) => {
        typeMaps[structure.name] = structure.name;
    });
    return [
        ...context.classes.map(klass => ({
            name: `${klass.name}.gd`,
            content: generateClass(klass, options.namespace, context.classes)
        })),
        ...context.enums.filter(structure => structure.name !== 'OPERATION').map((structure) => ({
            name: `${structure.name}.gd`,
            content: generateEnum(structure, options.namespace),
        })),
    ];
}
/**
 * Generate a single bundled file containing all classes and enums
 */
function renderBundle(context, options) {
    const fileName = options.namespace ? `${options.namespace}.gd` : "schema.gd";
    // Enrich typeMaps with enums
    context.enums.forEach((structure) => {
        typeMaps[structure.name] = structure.name;
    });
    const enumBodies = context.enums
        .filter(structure => structure.name !== 'OPERATION')
        .map(e => generateEnumBody(e));
    const classBodies = context.classes.map(klass => generateClassBody(klass));
    const content = `${getCommentHeader("#")}

${enumBodies.length > 0 ? enumBodies.join("\n\n") + "\n\n" : ""}${classBodies.join("\n\n")}
`;
    return { name: fileName, content };
}
/**
 * Generate just the class body (without preload) for bundling
 */
function generateClassBody(klass) {
    // Determine parent class
    const parentClass = (klass.extends !== "Schema")
        ? klass.extends
        : "Colyseus.Schema";
    const properties = klass.properties;
    const fieldsContent = properties.length > 0
        ? properties.map(prop => generateFieldDefinition(prop)).join(",\n") + ","
        : "";
    // Generate _to_string() method
    const toStringMethod = generateToStringMethod(klass.name, properties);
    return `class ${klass.name} extends ${parentClass}:
	static func definition():
		return [
${fieldsContent}
		]

${toStringMethod}`;
}
/**
 * Generate _to_string() method for the class
 */
function generateToStringMethod(className, properties) {
    const fieldNames = properties.map(prop => prop.name);
    const allFields = ["__ref_id", ...fieldNames];
    const formatParts = allFields.map(name => `${name}: %s`).join(", ");
    const formatString = `${className}(${formatParts})`;
    const selfReferences = allFields.map(name => `self.${name}`).join(", ");
    return `\tfunc _to_string() -> String:
		return "${formatString}" % [${selfReferences}]`;
}
/**
 * Generate a complete class file with preload (for individual file mode)
 */
function generateClass(klass, namespace, allClasses) {
    const allRefs = [];
    klass.properties.forEach(property => {
        let type = property.type;
        // Keep all refs list
        if ((type === "ref" || type === "array" || type === "map")) {
            allRefs.push(property);
        }
    });
    // Get required preloads for referenced types
    const preloads = allRefs
        .filter(ref => ref.childType && typeMaps[ref.childType] === undefined)
        .map(ref => ref.childType)
        .concat(getInheritanceTree(klass, allClasses, false).map(klass => klass.name))
        .filter(distinct)
        .map(childType => `const ${childType} = preload("${childType}.gd")`)
        .join("\n");
    return `${getCommentHeader("#")}

${preloads ? preloads + "\n\n" : ""}${generateClassBody(klass)}
`;
}
/**
 * Generate a field definition for the definition() array
 */
function generateFieldDefinition(prop) {
    let args;
    if (prop.childType) {
        const isUpcaseFirst = prop.childType.match(/^[A-Z]/);
        // Array or Map container
        const containerType = containerMaps[prop.type];
        const childTypeRef = isUpcaseFirst ? prop.childType : typeMaps[prop.childType] || `"${prop.childType}"`;
        args = [`"${prop.name}"`, containerType, childTypeRef];
    }
    else {
        // Primitive type
        const typeRef = typeMaps[prop.type] || `"${prop.type}"`;
        args = [`"${prop.name}"`, typeRef];
    }
    return `\t\t\tColyseus.Schema.Field.new(${args.join(", ")})`;
}
/**
 * Generate just the enum body for bundling
 */
function generateEnumBody(_enum) {
    const enumValues = _enum.properties.map((prop, index) => {
        let value;
        if (prop.type) {
            if (isNaN(Number(prop.type))) {
                value = `"${prop.type}"`;
            }
            else {
                value = Number(prop.type);
            }
        }
        else {
            value = index;
        }
        return `\t"${prop.name}": ${value},`;
    }).join("\n");
    return `const ${_enum.name} = {
${enumValues}
}`;
}
/**
 * Generate a complete enum file (for individual file mode)
 */
function generateEnum(_enum, _namespace) {
    return `${getCommentHeader("#")}

${generateEnumBody(_enum)}
`;
}

var gdscript = /*#__PURE__*/Object.freeze({
    __proto__: null,
    generate: generate$1,
    name: name,
    renderBundle: renderBundle
});

const generators = { csharp, cpp, haxe, ts, js, java, lua, c, gdscript, };
function generate(targetId, options) {
    const generator = generators[targetId];
    if (!generator) {
        throw new Error("You must provide a valid generator as argument, such as: --csharp, --haxe or --cpp");
    }
    if (!fs__namespace.existsSync(options.output)) {
        console.log("Creating", options.output, "directory");
        fs__namespace.mkdirSync(options.output);
    }
    /**
     * Default `@type()` decorator name
     */
    if (!options.decorator) {
        options.decorator = "type";
    }
    // resolve wildcard files
    options.files = options.files.reduce((acc, cur) => {
        if (cur.endsWith("*")) {
            acc.push(...recursiveFiles(cur.slice(0, -1)).filter(filename => /\.(js|ts|mjs)$/.test(filename)));
        }
        else {
            acc.push(cur);
        }
        return acc;
    }, []);
    const structures = parseFiles(options.files, options.decorator);
    // Post-process classes before generating
    structures.classes.forEach(klass => klass.postProcessing());
    if (options.bundle && generator.renderBundle) {
        // Bundle mode: generate all classes/interfaces/enums into a single file
        const bundled = generator.renderBundle(structures, options);
        const outputPath = path__namespace.resolve(options.output, bundled.name);
        fs__namespace.writeFileSync(outputPath, bundled.content);
        console.log("generated (bundled):", bundled.name);
    }
    else {
        // Standard mode: write individual files
        const generatedFiles = generator.generate(structures, options);
        generatedFiles.forEach((file) => {
            const outputPath = path__namespace.resolve(options.output, file.name);
            fs__namespace.writeFileSync(outputPath, file.content);
            console.log("generated:", file.name);
        });
    }
}
function recursiveFiles(dir) {
    const files = fs__namespace.readdirSync(dir, { withFileTypes: true });
    let collect = [];
    files.forEach(file => {
        const filename = path__namespace.resolve(dir, file.name);
        file.isDirectory() ? collect.push(...recursiveFiles(filename)) : collect.push(filename);
    });
    return collect;
}

function displayHelp(exitCode = 0) {
    console.log(`\nschema-codegen [path/to/Schema.ts]

Usage (C#/Unity)
    schema-codegen src/Schema.ts --output client-side/ --csharp --namespace MyGame.Schema

Valid options:
    --output: the output directory for generated client-side schema files
    --bundle: bundle all generated files into a single file

Generators:
${Object.
        keys(generators).
        map((targetId) => (`    --${targetId}: generate for ${generators[targetId].name}`)).
        join("\n")}

Optional:
    --namespace: generate namespace on output code
    --decorator: custom name for @type decorator to scan for`);
    process.exit(exitCode);
}
const args = argv(process.argv.slice(2));
if (args.help) {
    displayHelp();
}
let targetId;
for (let target in generators) {
    if (args[target]) {
        targetId = target;
    }
}
if (!args.output) {
    console.error("You must provide a valid --output directory.");
    displayHelp(1);
}
try {
    args.files = args._;
    generate(targetId, {
        files: args._,
        decorator: args.decorator,
        output: args.output,
        namespace: args.namespace,
        bundle: args.bundle
    });
}
catch (e) {
    console.error(e.message);
    console.error(e.stack);
    displayHelp(1);
}
//# sourceMappingURL=cli.cjs.map