feat: generate definition for complex types
This commit is contained in:
@@ -46,7 +46,6 @@ static class JsonSchemaGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
var attribute = parameter.GetCustomAttribute<FunctionParameterAttribute>();
|
var attribute = parameter.GetCustomAttribute<FunctionParameterAttribute>();
|
||||||
|
|
||||||
var paramName = attribute?.Name ?? parameter.Name;
|
var paramName = attribute?.Name ?? parameter.Name;
|
||||||
var paramDescription = attribute?.Description ?? string.Empty;
|
var paramDescription = attribute?.Description ?? string.Empty;
|
||||||
var paramRequired = attribute?.Required ?? !parameter.HasDefaultValue;
|
var paramRequired = attribute?.Required ?? !parameter.HasDefaultValue;
|
||||||
@@ -78,7 +77,7 @@ static class JsonSchemaGenerator
|
|||||||
{
|
{
|
||||||
return new JsonObject()
|
return new JsonObject()
|
||||||
{
|
{
|
||||||
[RefKey] = $"#/definitions/{type.FullName}"
|
[RefKey] = GetDefinitionPath(type)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,14 +150,65 @@ static class JsonSchemaGenerator
|
|||||||
private static JsonObject GenerateTypeDefinitionSchema(Type type, JsonObject inputSchema)
|
private static JsonObject GenerateTypeDefinitionSchema(Type type, JsonObject inputSchema)
|
||||||
{
|
{
|
||||||
var definitions = inputSchema[DefinitionsKey] ?? new JsonObject();
|
var definitions = inputSchema[DefinitionsKey] ?? new JsonObject();
|
||||||
var typeSchema = new JsonObject();
|
var typeSchema = new JsonObject()
|
||||||
|
{
|
||||||
|
[TypeKey] = ObjectType
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: Implement schema generation for complex types
|
List<MemberInfo> members = [];
|
||||||
|
var bindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
|
||||||
|
members.AddRange(type.GetProperties(bindingFlags));
|
||||||
|
members.AddRange(type.GetFields(bindingFlags));
|
||||||
|
|
||||||
|
var memberProperties = new JsonObject();
|
||||||
|
var memberRequiredProperties = new JsonArray();
|
||||||
|
|
||||||
|
foreach (var member in members)
|
||||||
|
{
|
||||||
|
JsonObject memberProperty;
|
||||||
|
|
||||||
|
var memberType = member switch
|
||||||
|
{
|
||||||
|
PropertyInfo property => property.PropertyType,
|
||||||
|
FieldInfo field => field.FieldType,
|
||||||
|
_ => throw new InvalidOperationException("Member is not a property or field")
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Provide attribute to allow specifying...
|
||||||
|
// 1. Name
|
||||||
|
// 2. Description
|
||||||
|
// 3. Required
|
||||||
|
// 4. Default values
|
||||||
|
// 5. Possible values
|
||||||
|
var memberPropertyName = memberType.Name;
|
||||||
|
var memberDescription = string.Empty;
|
||||||
|
var memberRequired = Nullable.GetUnderlyingType(memberType) is null;
|
||||||
|
|
||||||
|
memberProperty = definitions.AsObject().ContainsKey(memberType.FullName)
|
||||||
|
? new JsonObject()
|
||||||
|
{
|
||||||
|
[RefKey] = GetDefinitionPath(memberType)
|
||||||
|
}
|
||||||
|
: GenerateParameterTypeSchema(memberType, inputSchema);
|
||||||
|
|
||||||
|
if (memberRequired)
|
||||||
|
{
|
||||||
|
memberRequiredProperties.Add(memberPropertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
memberProperty[DescriptionKey] = memberDescription;
|
||||||
|
memberProperties[memberPropertyName] = memberProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
typeSchema[PropertiesKey] = memberProperties;
|
||||||
|
typeSchema[RequiredPropertiesKey] = memberRequiredProperties;
|
||||||
definitions[type.FullName] = typeSchema;
|
definitions[type.FullName] = typeSchema;
|
||||||
|
inputSchema[DefinitionsKey] = definitions;
|
||||||
return new JsonObject()
|
return new JsonObject()
|
||||||
{
|
{
|
||||||
[RefKey] = $"#/definitions/{type.FullName}"
|
[RefKey] = GetDefinitionPath(type)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetDefinitionPath(Type type) => $"#/definitions/{type.FullName}";
|
||||||
}
|
}
|
||||||
@@ -447,7 +447,61 @@ public class JsonSchemaGeneratorTestData : IEnumerable<object[]>
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// class parameter type with no attributes
|
||||||
|
yield return new object[]
|
||||||
|
{
|
||||||
|
Tool.CreateFromFunction(TestToolName,TestToolDescription,(Person person) => person),
|
||||||
|
new JsonObject()
|
||||||
|
{
|
||||||
|
["type"] = "object",
|
||||||
|
["definitions"] = new JsonObject()
|
||||||
|
{
|
||||||
|
[$"{typeof(Person).FullName}"] = new JsonObject()
|
||||||
|
{
|
||||||
|
["type"] = "object",
|
||||||
|
["properties"] = new JsonObject()
|
||||||
|
{
|
||||||
|
["String"] = new JsonObject()
|
||||||
|
{
|
||||||
|
["type"] = "string",
|
||||||
|
["description"] = string.Empty
|
||||||
|
},
|
||||||
|
["Int32"] = new JsonObject()
|
||||||
|
{
|
||||||
|
["type"] = "integer",
|
||||||
|
["description"] = string.Empty
|
||||||
|
}
|
||||||
|
},
|
||||||
|
["required"] = new JsonArray()
|
||||||
|
{
|
||||||
|
"String",
|
||||||
|
"Int32"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
["properties"] = new JsonObject()
|
||||||
|
{
|
||||||
|
["person"] = new JsonObject()
|
||||||
|
{
|
||||||
|
["$ref"] = $"#/definitions/{typeof(Person).FullName}",
|
||||||
|
["description"] = string.Empty
|
||||||
|
}
|
||||||
|
},
|
||||||
|
["required"] = new JsonArray()
|
||||||
|
{
|
||||||
|
"person",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Person
|
||||||
|
{
|
||||||
|
public string Name { get; } = string.Empty;
|
||||||
|
public int Age { get; }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user