LinkToolAddin/common/JsonSchemaGenerator.cs

150 lines
4.6 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections.ObjectModel;
namespace LinkToolAddin.common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.Json;
public static class JsonSchemaGenerator
{
public static string GenerateJsonSchema(MethodInfo methodInfo)
{
var parameters = methodInfo.GetParameters();
var properties = new Dictionary<string, object>();
var required = new List<string>();
foreach (var param in parameters)
{
var paramName = param.Name ?? throw new InvalidOperationException("参数没有名称。");
var paramSchema = GenerateSchemaForType(param.ParameterType);
properties[paramName] = paramSchema;
if (!param.IsOptional)
{
required.Add(paramName);
}
}
var schemaRoot = new Dictionary<string, object>
{
{ "$schema", "http://json-schema.org/draft-07/schema#" },
{ "type", "object" },
{ "properties", properties }
};
if (required.Count > 0)
{
schemaRoot["required"] = required;
}
var options = new JsonSerializerOptions { WriteIndented = true };
return JsonSerializer.Serialize(schemaRoot, options);
}
private static object GenerateSchemaForType(Type type)
{
// 处理可空类型
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
var underlyingType = Nullable.GetUnderlyingType(type);
return new[] { GenerateSchemaForType(underlyingType), "null" };
}
// 处理集合类型数组或IEnumerable<T>
if (IsCollectionType(type, out Type elementType))
{
return new Dictionary<string, object>
{
{ "type", "array" },
{ "items", GenerateSchemaForType(elementType) }
};
}
// 处理基本类型int, string, bool, etc.
if (IsPrimitiveType(type))
{
string jsonType = MapClrTypeToJsonType(type);
var schema = new Dictionary<string, object> { { "type", jsonType } };
if (type == typeof(DateTime))
schema["format"] = "date-time";
else if (type == typeof(Guid))
schema["format"] = "uuid";
return schema;
}
// 处理复杂类型(类、结构体)
if (type.IsClass || type.IsValueType)
{
var props = new Dictionary<string, object>();
foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
props[prop.Name] = GenerateSchemaForType(prop.PropertyType);
}
return new Dictionary<string, object>
{
{ "type", "object" },
{ "properties", props }
};
}
// 默认情况
return new Dictionary<string, object> { { "type", "any" } };
}
private static bool IsCollectionType(Type type, out Type elementType)
{
if (type == typeof(string))
{
elementType = null;
return false;
}
if (type.IsArray)
{
elementType = type.GetElementType();
return true;
}
if (type.IsGenericType)
{
var genericTypeDef = type.GetGenericTypeDefinition();
if (genericTypeDef == typeof(IEnumerable<>) ||
genericTypeDef == typeof(List<>) ||
genericTypeDef == typeof(Collection<>))
{
elementType = type.GetGenericArguments()[0];
return true;
}
}
elementType = null;
return false;
}
private static bool IsPrimitiveType(Type type)
{
return type.IsPrimitive || type == typeof(string) || type == typeof(decimal) || type == typeof(DateTime) || type == typeof(Guid);
}
private static string MapClrTypeToJsonType(Type type)
{
if (type == typeof(int) || type == typeof(short) || type == typeof(long) ||
type == typeof(uint) || type == typeof(ushort) || type == typeof(ulong))
return "integer";
if (type == typeof(float) || type == typeof(double) || type == typeof(decimal))
return "number";
if (type == typeof(bool))
return "boolean";
if (type == typeof(string))
return "string";
if (type == typeof(DateTime) || type == typeof(Guid))
return "string";
return "any";
}
}