private void WriteRouteMethodBody(IndentedTextWriter classWriter, RouteCodeGeneration cg, string verb) { classWriter.Indent++; var customAttribute = cg.RouteType.GetCustomAttribute <TypescriptCodeGeneratorAttribute>(); var cacheResult = (customAttribute != null && customAttribute.CacheResult); if (cacheResult) { classWriter.WriteLine("if (this._" + cg.RouteType.Name + "Cached == null) {"); classWriter.Indent++; classWriter.WriteLine("this._" + cg.RouteType.Name + "Cached = this.$http<" + cg.ReturnTsType + ">({"); } else { classWriter.WriteLine("return this.$http<" + cg.ReturnTsType + ">({"); } classWriter.Indent++; // Write out the url array classWriter.Write("url: ["); for (int i = 0; i < cg.UrlPath.Count; i++) { if (i > 0) { classWriter.Write(", "); } classWriter.Write(cg.UrlPath[i]); } classWriter.WriteLine("].join('/'),"); classWriter.WriteLine("method: '" + verb.ToUpper() + "',"); if (cg.RouteInputPropertyLines.Count > cg.MethodParameters.Count) { if (verb.ToUpper() == "GET") { classWriter.WriteLine("params: routeParams"); } else { classWriter.WriteLine("data: routeParams"); } } classWriter.Indent--; classWriter.WriteLine("});"); if (cacheResult) { classWriter.Indent--; classWriter.WriteLine("}"); classWriter.WriteLine("return this._" + cg.RouteType.Name + "Cached;"); } // Close the method classWriter.Indent--; classWriter.WriteLine("}"); classWriter.WriteLine(); }
private void WriteTypescriptMethod(IndentedTextWriter classWriter, IndentedTextWriter routeDtoWriter, RouteCodeGeneration cg, string verb, bool includeVerbNameInMethod, bool writeInputDto) { classWriter.Write(cg.RouteType.Name + (includeVerbNameInMethod ? "_" + verb : string.Empty)); classWriter.Write(" = ("); // Optional parameters must come last in typescript for (int i = 0; i < cg.MethodParameters.Count; i++) { if (i > 0) { classWriter.Write(", "); } classWriter.Write(cg.MethodParameters[i]); } if (cg.RouteInputPropertyLines.Count > 0) { if (cg.MethodParameters.Count > 0) { classWriter.Write(", "); } classWriter.Write("routeParams "); if (cg.RouteInputHasOnlyOptionalParams) { classWriter.Write("?"); } classWriter.Write(": " + cg.RouteInputDtoName); if (writeInputDto) { //GenerateJsDoc(routeDtoWriter, cg.RouteType, ); routeDtoWriter.WriteLine("export interface " + cg.RouteInputDtoName + " {"); routeDtoWriter.Indent++; foreach (string line in cg.RouteInputPropertyLines) { if (!string.IsNullOrEmpty(line)) { routeDtoWriter.WriteLine(line); } } routeDtoWriter.Indent--; routeDtoWriter.WriteLine("}"); } } classWriter.Write(")"); /* * for (int i = 0; i < cg.MethodParametersOptional.Count; i++) * { * if (i > 0 || cg.MethodParameters.Count > 0) * { * classWriter.Write(", "); * } * * classWriter.Write(cg.MethodParametersOptional[i]); * } * classWriter.Write("); */ classWriter.WriteLine(" => {"); WriteRouteMethodBody(classWriter, cg, verb); }
/// <summary> /// Responsible for transforming our .NET ServiceStack Routes into TypeScript code capable of calling those routes /// /// Here's a sample: /// C#: /// [Route("/Dashboard/SalesGrossVsNet", "POST")] /// public class GetSalesGrossVsNet : IReturn<List<GrossVsNetSales>> { /// [ApiMember()] /// public string StartDate { get; set; } /// [ApiMember] /// public string EndDate { get; set; } /// } /// /// public class GrossVsNetSales { /// public DateTime Date { get; set; } /// public double GrossSales {get; set;} /// public double NetSales {get; set;} /// } /// /// Typescript: /// export interface GrossVsNetSales { /// Date: Date; /// GrossSales: number; /// NetSales: number; /// } /// /// /** /// * Route: /Dashboard/SalesGrossVsNet /// * Source: Clarity.Ecommerce.Framework.Dashboards.GetSalesGrossVsNet /// */ /// GetSalesGrossVsNet = (routeParams ?: GetSalesGrossVsNetDto) => { /// return this.$http<Array<GrossVsNetSales>>({ /// url: [this.rootUrl, "Dashboard", "SalesGrossVsNet"].join('/'), /// method: 'POST', /// data: routeParams /// }); /// } /// </summary> /// <param name="writer"></param> private void WriteRouteClasses(IndentedTextWriter writer) { writer.WriteLine(@" // ----- Routes ----- /** * Base class for service stack routes */ export class ServiceStackRoute { public service : " + _ServiceName + @"; // The root URL for making RESTful calls get rootUrl() : string { return this.service.rootUrl; } get $http() : ng.IHttpService { return this.service.$http; } constructor(service: " + _ServiceName + @") { this.service = service; } } "); foreach (var routeRoot in _ServiceStackRoutes) { var routeClassWriter = new IndentedTextWriter(new StringWriter(), TAB) { Indent = 1 }; var routeDtosWriter = new IndentedTextWriter(new StringWriter(), TAB) { Indent = 1 }; routeClassWriter.WriteLine("export class " + routeRoot.Key + " extends ServiceStackRoute {"); routeClassWriter.Indent++; foreach (Type type in routeRoot.Value.Keys.OrderBy(t => t.Name)) { try { string returnTsType = DetermineTsType(type); if (routeRoot.Value[type].Count > 1) { routeClassWriter.WriteLine( "// " + type + "/ exports multiple routes. Typescript does not support operator overloading and this operation is not supported. Make seperate routes instead."); } var customAttribute = type.GetCustomAttribute <TypescriptCodeGeneratorAttribute>(); if (customAttribute != null && customAttribute.CacheResult) { routeClassWriter.WriteLine("private _" + type.Name + "Cached: ng.IHttpPromise<" + returnTsType + ">;"); } foreach (RouteAttribute route in routeRoot.Value[type]) { WriteMethodHeader(routeClassWriter, type, route); var cg = new RouteCodeGeneration(this, route, type, returnTsType); // Translate the path into a coded URL // We may have tokens like {ID} in the route cg.ParseRoutePath(); // Generate code for route properties cg.ProcessRouteProperties(); foreach (string verb in cg.Verbs) { WriteTypescriptMethod(routeClassWriter, routeDtosWriter, cg, verb, cg.Verbs.Length > 1, verb == cg.Verbs[0]); } } } catch (Exception e) { writer.WriteLine("// ERROR Processing " + routeRoot.Key + " - " + type.Name); writer.WriteLine("// " + e.Message); } } routeClassWriter.Indent--; routeClassWriter.WriteLine("}"); writer.WriteLine(routeDtosWriter.InnerWriter); writer.WriteLine(routeClassWriter.InnerWriter); } }