using System; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Text; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using PokeApiDefinitionGenerator; using QuickType; namespace PokeApiDefinitionGenerator { internal static class Program { /// /// Url template for raw json data. /// private const string UrlBase = @"https://raw.githubusercontent.com/PokeAPI/pokeapi.co/master/src/docs/{0}.json"; /// /// Order made to be the same as mudkipme/pokeapi-v2-typescript /// private static readonly string[] DocEntries = { "resource-lists", "berries", "contests", "encounters", "evolution", "games", "items", "machines", "moves", "locations", "pokemon", "utility" }; private static void Main(string[] args) { var sb = new StringBuilder(); sb.AppendLine("interface APIResourceURL extends String {}"); sb.AppendLine(); foreach (string url in DocEntries.Select(x => string.Format(UrlBase, x))) { string json = new WebClient().DownloadString(url); var allData = JsonConvert.DeserializeObject(json, Converter.Settings); foreach (DocData data in allData) { bool isFirst = true; foreach (ResponseModel model in data.ResponseModels) { if (isFirst) { if (!string.IsNullOrWhiteSpace(data.Description)) sb.AppendLine($"/** {data.Description} */"); isFirst = false; } sb.AppendLine($"interface {FixType(model.Name, true)} {{"); foreach (Field field in model.Fields) { if (!string.IsNullOrWhiteSpace(field.Description)) sb.AppendLine($" /** {field.Description} */"); sb.AppendLine($" {field.Name}: {field.Type.ToString()};"); } sb.AppendLine("}"); sb.AppendLine(); } } } Console.WriteLine(sb.ToString()); File.WriteAllText("poke-api.d.ts", sb.ToString()); } public static string FixType(string s, bool allowGeneric = false) { var apiResourceNames = new [] { "APIResource", "APIResourceList", "NamedAPIResource", "NamedAPIResourceList" }; s = s .Replace('é', 'e') .Replace("integer", "number"); if (s.Contains(" ")) s = s.Replace(" ", string.Empty); if (apiResourceNames.Contains(s) && allowGeneric) s += ""; return s; } } } namespace QuickType { public class DocData { [JsonProperty("name")] public string Name { get; set; } [JsonProperty("description")] public string Description { get; set; } [JsonProperty("exampleRequest")] public string ExampleRequest { get; set; } [JsonProperty("exampleResponse")] public object ExampleResponse { get; set; } [JsonProperty("responseModels")] public ResponseModel[] ResponseModels { get; set; } } public class ResponseModel { [JsonProperty("name")] public string Name { get; set; } [JsonProperty("fields")] public Field[] Fields { get; set; } } public class Field { [JsonProperty("name")] public string Name { get; set; } [JsonProperty("description")] public string Description { get; set; } [JsonProperty("type")] public TypeUnion Type { get; set; } } public class TypeClass { [JsonProperty("type")] public string Type { get; set; } [JsonProperty("of")] public TypeUnion Of { get; set; } } public struct TypeUnion { public string String; public TypeClass TypeClass; public override string ToString() { if (!(String is null)) return Program.FixType(String); if (!(TypeClass is null)) return TypeClass.Type == "list" ? $"{Program.FixType(TypeClass.Of.ToString(), true)}[]" : $"{Program.FixType(TypeClass.Type)}<{Program.FixType(TypeClass.Of.ToString(), true)}>"; throw new Exception("Bad tuple?"); } } internal static class Converter { public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings { MetadataPropertyHandling = MetadataPropertyHandling.Ignore, DateParseHandling = DateParseHandling.None, Converters = { TypeUnionConverter.Singleton, new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal } }, }; } internal class TypeUnionConverter : JsonConverter { public override bool CanConvert(Type t) => t == typeof(TypeUnion) || t == typeof(TypeUnion?); public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer) { switch (reader.TokenType) { case JsonToken.String: case JsonToken.Date: var stringValue = serializer.Deserialize(reader); return new TypeUnion { String = stringValue }; case JsonToken.StartObject: var objectValue = serializer.Deserialize(reader); return new TypeUnion { TypeClass = objectValue }; } throw new Exception("Cannot unmarshal type TypeUnion"); } public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer) { var value = (TypeUnion)untypedValue; if (value.String != null) { serializer.Serialize(writer, value.String); return; } if (value.TypeClass != null) { serializer.Serialize(writer, value.TypeClass); return; } throw new Exception("Cannot marshal type TypeUnion"); } public static readonly TypeUnionConverter Singleton = new TypeUnionConverter(); } }