protected void OutputInterface(TypeScriptWriter writer, ApiInterfaceDesc i) { writer.Write($"interface {getName(i.TsName)}"); if (i.Extends.Any()) { writer.Write(" extends "); writer.Write(i.Extends.Select(e => getNamespace(e.TsName) == getNamespace(i.TsName) ? getName(e.TsName) : e.TsName).Order().JoinString(", ")); } writer.WriteLine(" {"); using (writer.Indent()) { foreach (var prop in i.Properties.OrderBy(p => p.TsName)) { writer.WriteLine($"{prop.TsName}: {prop.TsType.GetTypeScript()};"); } } writer.WriteLine("}"); }
protected void OutputService(TypeScriptWriter writer, ApiServiceDesc s) { _convertersUsedFrom = new HashSet <TypeConverter>(); _convertersUsedTo = new HashSet <TypeConverter>(); writer.WriteLine($"export class {s.Name}Service extends ApiServiceBase {{"); writer.WriteLine(); using (writer.Indent()) { writer.WriteLine("private _hostname: string;"); writer.WriteLine(); writer.WriteLine("public constructor(hostname: string) {"); using (writer.Indent()) { writer.WriteLine("super();"); writer.WriteLine("this._hostname = (hostname.substr(-1) == '/') ? hostname : hostname + '/';"); } writer.WriteLine("}"); writer.WriteLine(); foreach (var method in s.Methods.OrderBy(m => m.TsName)) { foreach (var httpMethod in method.HttpMethods.Order()) { bool canDirectReturn = getConverter(method.TsReturnType) == null; writer.Write($"public {(canDirectReturn ? "" : "async ")}{getMethodName(method, httpMethod)}("); bool first = true; foreach (var p in method.Parameters) { if (!first) { writer.Write(", "); } writer.Write($"{p.TsName}: {p.TsType.GetTypeScript()}"); first = false; } writer.WriteLine($"): {string.Format(ReturnTypeTemplate, method.TsReturnType.GetTypeScript())} {{"); using (writer.Indent()) { var url = method.UrlPath; bool first2 = true; foreach (var p in method.Parameters.Where(p => p.Location == ParameterLocation.QueryString).OrderBy(p => p.TsName)) { url += (first2 ? '?' : '&') + p.TsName + "=${encodeURIComponent('' + " + p.TsName + ")}"; first2 = false; } writer.WriteLine($"let url = this._hostname + `{url}`;"); // Output parameter type conversions foreach (var p in method.Parameters) { OutputTypeConversion(writer, p.TsName, p.TsType, toTypeScript: false); } // Build request body var bodyParams = method.Parameters.Where(p => p.Location == ParameterLocation.RequestBody).OrderBy(p => p.TsName).ToList(); if (bodyParams.Count > 0 && httpMethod == "GET") { throw new InvalidOperationException($"GET requests must not have any body parameters. Offending parameter: {bodyParams[0].TsName}, method {method.Method.Name}, controller {s.Controller.FullName}"); } if (bodyParams.Count > 1 && (method.BodyEncoding == BodyEncoding.Raw || method.BodyEncoding == BodyEncoding.Json)) { throw new InvalidOperationException($"The body encoding for this method allows for at most one body parameter. Offending parameters: [{bodyParams.Select(p => p.TsName).JoinString(", ")}], method {method.Method.Name}, controller {s.Controller.FullName}"); } var bodyCode = ""; if (bodyParams.Count > 0) { if (method.BodyEncoding == BodyEncoding.Raw) { bodyCode = $", body: {bodyParams[0].TsName}"; } else if (method.BodyEncoding == BodyEncoding.Json) { bodyCode = $", body: JSON.stringify({bodyParams[0].TsName}), headers: {{ 'Content-Type': 'application/json' }}"; } else if (method.BodyEncoding == BodyEncoding.FormUrlEncoded) { writer.WriteLine("let __body = new URLSearchParams();"); foreach (var bp in bodyParams) { writer.WriteLine($"__body.append('{bp.TsName}', '' + {bp.TsName});"); } bodyCode = ", body: __body"; } else if (method.BodyEncoding == BodyEncoding.MultipartFormData) { writer.WriteLine("let __body = new FormData();"); foreach (var bp in bodyParams) { writer.WriteLine($"__body.append('{bp.TsName}', '' + {bp.TsName});"); } bodyCode = ", body: __body"; throw new NotImplementedException("FormData encoding is not fully implemented."); // no support for file name, parameter is always stringified with no support for Blob } else { throw new Exception($"Unexpected {nameof(method.BodyEncoding)}: {method.BodyEncoding}"); } } // Output call var sendCookies = s.SendCookies == SendCookies.Always ? "include" : s.SendCookies == SendCookies.SameOriginOnly ? "same-origin" : s.SendCookies == SendCookies.Never ? "omit" : throw new Exception(); if (canDirectReturn) { writer.Write("return "); } else { writer.Write("let result = await "); } writer.WriteLine($"this.{httpMethod}<{method.TsReturnType.GetTypeScript()}>(url, {{ credentials: '{sendCookies}'{bodyCode} }});"); if (!canDirectReturn) { // Output return type conversion OutputTypeConversion(writer, "result", method.TsReturnType, toTypeScript: true); writer.WriteLine("return result;"); } } writer.WriteLine("}"); writer.WriteLine(); } } // Output type converters foreach (var tc in _typeConverters.Values.Where(c => c != null).OrderBy(c => c.ForType.GetHash())) { if (_convertersUsedFrom.Contains(tc)) { writer.WriteLine($"private {tc.FunctionName(toTypeScript: false)}(val: {tc.ForType.GetTypeScript()}): any {{"); using (writer.Indent()) tc.WriteFunctionBody(writer, false); writer.WriteLine("}"); writer.WriteLine(); } if (_convertersUsedTo.Contains(tc)) { writer.WriteLine($"private {tc.FunctionName(toTypeScript: true)}(val: any): {tc.ForType.GetTypeScript()} {{"); using (writer.Indent()) tc.WriteFunctionBody(writer, true); writer.WriteLine("}"); writer.WriteLine(); } } } writer.WriteLine("}"); }