private static string getApiErrors(GenSdkOptions opts, TypescriptGenerator tsGen) { IEnumerable <Type> apiErrors = typeof(ApiError).GetTypeInfo().Assembly .GetTypes() .Where(t => typeof(ApiError).IsAssignableFrom(t) && !t.GetTypeInfo().IsAbstract) .Select(t => t); var errorDefinitions = new List <ErrorDefinition>(); foreach (var t in apiErrors) { var bt = t.GetTypeInfo().BaseType; if (bt == typeof(ApiError)) { errorDefinitions.Add(new ErrorDefinition() { Error = t.Name, DataType = null }); continue; } else if (bt.IsConstructedGenericType && bt.GetTypeInfo().GetGenericTypeDefinition() == typeof(ApiError <>)) { var dataType = bt.GenericTypeArguments[0]; tsGen.Generate(dataType); errorDefinitions.Add(new ErrorDefinition() { Error = t.Name, DataType = dataType }); continue; } } var errs = new List <string>(); foreach (var def in errorDefinitions) { errs.Add(opts.GetApiPromiseErrorFormat(def.Error, def.DataType != null ? tsGen.Generate(def.DataType) : "null")); } return(opts.GetApiPromiseFormat(apiErrors: indentAllButFirstLine(string.Join("\r\n", errs)))); }
/// <summary> /// Generates structurally typed TypeScript API /// /// <param name="opts">Options for the generation</param> /// </summary> public bool Generate(GenSdkOptions opts) { var allDefinitions = new DictItem() as IItem; foreach (var grp in _apiDescriptionsProvider.ApiDescriptionGroups.Items) { foreach (var act in grp.Items) { var apiFunction = new ApiFunctionItem(); apiFunction.HttpMethod = act.HttpMethod; apiFunction.RelativePath = act.RelativePath; // [FromBody] or [FromForm] act.ParameterDescriptions.ToList().ForEach(p => { if (p.Source.Id.ToLower() == "body") { _tsGen.Generate(p.Type); apiFunction.InputBodyType = p.Type; } else if (p.Source.Id.ToLower() == "form") { // Not tested since ASP.NET Core 1.0 _tsGen.Generate(p.Type); apiFunction.InputFormType = p.Type; } else if (p.Source.Id.ToLower() == "path") { apiFunction.InputPathTypes.Add((p.Name, p.Type)); } else { _logger.LogWarning($"Unhandled type of method {p.Name} with source {p.Source.Id}, ignoring."); } }); // Get result type if (act.SupportedResponseTypes.Count >= 1) { var responseType = act.SupportedResponseTypes.First(); _tsGen.Generate(responseType.Type); // registry.GetOrRegister(responseType.Type); apiFunction.ResultType = responseType.Type; } var currDef = allDefinitions; // Namespaced controllers E.g. // AccountController.LoggedIn -> // Account.LoggedIn() var groupName = opts.GroupActionsBy(act); if (groupName != null) { var groups = groupName.Split('.'); // Step in to the nesting given in groups foreach (var g in groups) { if (!currDef.Children.ContainsKey(g)) { currDef.Children[g] = new DictItem(); } currDef = currDef.Children[g]; } } var nameRegex = new Regex(@".([^.]+) "); var nameMatch = nameRegex.Match(act.ActionDescriptor.DisplayName); if (!nameMatch.Success) { break; } var name = nameMatch.Groups[1].Value; currDef.Children[name] = apiFunction; } } // var apiObject = allDefinitions.GenTypescript(opts, registry); var apiObject = allDefinitions.GenTypescript(opts, _tsGen); var output = new List <string>(); output.AddRange(opts.Headers); output.AddRange(opts.Imports); output.Add(getApiErrors(opts, _tsGen)); output.Add(opts.GetApiRootFormat(apiObject)); output.AddRange(opts.Footers); // Write only if changed or does not exist var outputText = string.Join("\r\n", output); var write = true; if (File.Exists(opts.OutputFile)) { var fileContents = File.ReadAllText(opts.OutputFile); write = fileContents != outputText; } if (write) { File.WriteAllText(opts.OutputFile, outputText); return(true); } return(false); }