string MapComplexType(Type type) { if (_processedTypes.TryGetValue(type, out var name)) { return(name); } name = _opts.DtoClassNamingPolicy(type); name = name.Split('`')[0]; if (_usedNames.Contains(name)) { throw new InvalidProgramException(name + " is already in use"); } _processedTypes[type] = name; var code = new TypescriptCodeBuilder(); var typeInfo = type.GetTypeInfo(); if (typeInfo.IsInterface || typeInfo.IsClass) { var tsName = name; if (typeInfo.IsGenericTypeDefinition) { tsName = name + "<" + string.Join(",", type.GetGenericArguments().Select(a => a.Name)) + ">"; } code.BeginInterface(tsName); foreach (var p in type.GetProperties()) { var typeName = MapType(p.PropertyType); code.AppendInterfaceProperty(_opts.DtoFieldNamingPolicy(p.Name), typeName); } code.End(); } else if (typeInfo.IsEnum) { code.BeginEnum(name); foreach (var en in Enum.GetNames(type)) { code.AppendEnumValue(en, en); } code.End(); } else { throw new InvalidProgramException($"Don't know how to convert {type.FullName} to typescript"); } _builder.AppendLine(code.ToString()); return(name); }
public static string GenerateGlueCode(TypescriptGenerationOptions opts, IEnumerable <Type> types) { var ctx = new TypescriptTypeMapping(opts); var code = new TypescriptCodeBuilder(); var ctor = new List <string>(); var fields = new List <string>(); var interfaceFields = new List <string>(); foreach (var type in types) { var proxyClassName = "CoreRpcProxyFor" + type.Name; var proxyFieldName = opts.ApiFieldNamingPolicy(type); var proxyInterfaceName = "I" + proxyClassName; foreach (var iface in new[] { true, false }) { if (iface) { code.BeginInterface(proxyInterfaceName); } else { code.BeginClass(proxyClassName + " implements " + proxyInterfaceName); code.AppendLines( $"private parent: {opts.ClassName};", $"constructor (parent: {opts.ClassName}){{this.parent = parent;}}" ); } var target = opts.TargetNameExtractor.GetTargetName(type); foreach (var m in type.GetMethods()) { if (m.DeclaringType == typeof(System.Object)) { continue; } var sig = Convert.ToBase64String(opts.Binder.GetMethodSignature(m)); code.BeginMethod(opts.ApiMethodNamingPolicy(m.Name), iface ? (bool?)null : true); var names = new List <string>(); foreach (var p in m.GetParameters()) { code.AppendMethodParameter(p.Name, ctx.MapType(p.ParameterType)); names.Add(p.Name); } var returnType = m.ReturnType; if (returnType == typeof(Task)) { returnType = typeof(void); } else if (returnType.IsConstructedGenericType && returnType.GetGenericTypeDefinition() == typeof(Task <>)) { returnType = returnType.GetGenericArguments()[0]; } var returnTypeName = ctx.MapType(returnType); code.AppendMethodReturnValue("Promise<" + returnTypeName + ">"); if (iface) { code.AppendSemicolon(); } else { code.BeginBody(); var req = $"{{Target: '{target}', MethodSignature: '{sig}', Arguments: [{string.Join(",", names)}] }}"; code.AppendLine($"return this.parent.send<{returnTypeName}>({req});"); code.End(); } } code.End(); } interfaceFields.Add($"{proxyFieldName} : " + proxyInterfaceName + ";"); fields.Add($"{proxyFieldName} : " + proxyClassName + ";"); ctor.Add($"this.{proxyFieldName} = new {proxyClassName}(this);"); } var resultFieldName = "Result"; var exceptionFieldName = "Exception"; code.BeginInterface("I" + opts.ClassName); code.AppendLines(interfaceFields.ToArray()); code.End(); code.BeginClass(opts.ClassName + " implements I" + opts.ClassName); code.AppendLines( "private baseUrl: string;", "private fetch: (url: string, init: RequestInit) => Promise<Response>;", "constructor(baseUrl : string, customFetch?: (url: string, init: RequestInit) => Promise<Response>) {", "this.baseUrl = baseUrl;", "if(customFetch) this.fetch = customFetch; else this.fetch = (r, i) => fetch(r, i);" ); code.AppendLines(ctor.ToArray()); code.AppendLine("}"); code.AppendLines( "public send<T>(request: any) : Promise<T>{", "return this.fetch(this.baseUrl, {method: 'post', body: JSON.stringify(request)})", " .then(response => {", " if (!response.ok)", " throw new Error(response.statusText);", " return response.json();", " }).then(jr => {", $" const r = <{{{resultFieldName}?: T, {exceptionFieldName}?: string}}>jr;", $" if(r.{exceptionFieldName}) throw r.{exceptionFieldName};", $" return r.{resultFieldName}!;", " });", "}" ); code.AppendLines(fields.ToArray()); code.End(); return((ctx + "\n" + code).Replace("\r\n", "\n")); }