Skip to content

Instantly share code, notes, and snippets.

@sonygod
Forked from nadako/SchemaTypeBuilder.hx
Created October 31, 2020 03:34
Show Gist options
  • Save sonygod/c801cee637ac04e64b13c04aafe92c00 to your computer and use it in GitHub Desktop.
Save sonygod/c801cee637ac04e64b13c04aafe92c00 to your computer and use it in GitHub Desktop.
JSON-schema type builder prototype.
{
"type": "object",
"required": ["intProp", "boolProp"],
"properties": {
"intProp": {"type": "integer"},
"numProp": {"type": "number"},
"strProp": {"type": "string"},
"boolProp": {"type": "boolean"},
"arrayProp": {
"type": "array",
"items": {
"type": "object",
"properties": {
"dynObj": {"type": "object"},
"dynArr": {"type": "array"}
}
}
}
}
}
#if macro
import haxe.macro.Context;
import haxe.macro.Expr;
class SchemaTypeBuilder
{
public static function build(ref:String):haxe.macro.Type
{
var schema = haxe.Json.parse(sys.io.File.getContent(ref));
var type:ComplexType = parseType(schema);
return haxe.macro.ComplexTypeTools.toType(type);
}
static function parseType(schema:Dynamic):ComplexType
{
return switch (schema.type)
{
case "integer":
return macro : Int;
case "number":
return macro : Float;
case "string":
return macro : String;
case "boolean":
return macro : Bool;
case "array":
parseArrayType(schema);
case "object":
parseObjectType(schema);
case unknown:
throw "Unsupported JSON-schema type: " + unknown;
};
}
static function parseArrayType(schema:Dynamic):ComplexType
{
var type = if (Reflect.hasField(schema, "items"))
parseType(schema.items);
else
macro : Dynamic;
return macro : Array<$type>;
}
static function parseObjectType(schema:Dynamic):ComplexType
{
if (Reflect.hasField(schema, "properties"))
{
var required:Array<String> = Reflect.hasField(schema, "required") ? schema.required : [];
var fields:Array<Field> = [];
var props = schema.properties;
for (field in Reflect.fields(props))
{
var meta = [];
if (!Lambda.has(required, field))
meta.push({name: ":optional", params: [], pos: Context.currentPos()});
var subschema = Reflect.field(props, field);
fields.push({
name: field,
pos: Context.currentPos(),
kind: FVar(parseType(subschema)),
meta: meta
});
}
return TAnonymous(fields);
}
return macro : Dynamic<Dynamic>;
}
}
#end
class Sample
{
static function main()
{
var a:MyType = {
intProp: 10,
boolProp: true
};
}
}
typedef MyType = haxe.macro.MacroType<[SchemaTypeBuilder.build("mytype.json")]>;
@sonygod
Copy link
Author

sonygod commented Oct 31, 2020

old version 


#if macro
import haxe.macro.Context;
import haxe.macro.Expr;

class SchemaTypeBuilder
{
    public static function build(ref:String):haxe.macro.Type
    {
        var schema = haxe.Json.parse(sys.io.File.getContent(ref));
        var type:ComplexType = parseType(schema);
        return haxe.macro.ComplexTypeTools.toType(type);
    }

    static function parseType(schema:Dynamic):ComplexType
    {
        return switch (schema.type)
        {
            case "integer":
                TPath({pack: [], name: "Int", params: []});
            case "number":
                TPath({pack: [], name: "Float", params: []});
            case "string":
                TPath({pack: [], name: "String", params: []});
            case "boolean":
                TPath({pack: [], name: "Bool", params: []});
            case "array":
                parseArrayType(schema);
            case "object":
                parseObjectType(schema);
            case unknown:
                throw "Unsupported JSON-schema type: " + unknown;
        };
    }

    static function parseArrayType(schema:Dynamic):ComplexType
    {
        var type = if (Reflect.hasField(schema, "items"))
            parseType(schema.items);
        else
            TPath({pack: [], name: "Dynamic", params: []});

        return TPath({pack: [], name: "Array", params: [TPType(type)]});
    }

    static function parseObjectType(schema:Dynamic):ComplexType
    {
        if (Reflect.hasField(schema, "properties"))
        {
            var required:Array<String> = Reflect.hasField(schema, "required") ? schema.required : [];
            var fields:Array<Field> = [];
            var props = schema.properties;
            for (field in Reflect.fields(props))
            {
                var meta = [];
                if (!Lambda.has(required, field))
                    meta.push({name: ":optional", params: [], pos: Context.currentPos()});
                var subschema = Reflect.field(props, field);
                fields.push({
                    name: field,
                    pos: Context.currentPos(),
                    kind: FVar(parseType(subschema)),
                    meta: meta
                });
            }
            return TAnonymous(fields);
        }

        return TPath({pack: [], name: "Dynamic", params: [TPType(TPath({pack: [], name: "Dynamic", params: []}))]});
    }
}
#end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment