private bool TryPromptParam(DocsParam oldDParam, TripleSlashMember tsMember, out TripleSlashParam?newTsParam) { newTsParam = null; if (Config.DisablePrompts) { Log.Error($"Prompts disabled. Will not process the '{oldDParam.Name}' param."); return(false); } bool created = false; int option = -1; while (option == -1) { Log.Error($"Problem in param '{oldDParam.Name}' in member '{tsMember.Name}' in file '{oldDParam.ParentAPI.FilePath}'"); Log.Error($"The param probably exists in code, but the exact name was not found in Docs. What would you like to do?"); Log.Warning(" 0 - Exit program."); Log.Info(" 1 - Select the correct triple slash param from the existing ones."); Log.Info(" 2 - Ignore this param."); Log.Warning(" Note:Make sure to double check the affected Docs file after the tool finishes executing."); Log.Cyan(false, "Your answer [0,1,2]: "); if (!int.TryParse(Console.ReadLine(), out option)) { Log.Error("Not a number. Try again."); option = -1; } else { switch (option) { case 0: { Log.Info("Goodbye!"); Environment.Exit(0); break; } case 1: { int paramSelection = -1; while (paramSelection == -1) { Log.Info($"Triple slash params found in member '{tsMember.Name}':"); Log.Warning(" 0 - Exit program."); int paramCounter = 1; foreach (TripleSlashParam param in tsMember.Params) { Log.Info($" {paramCounter} - {param.Name}"); paramCounter++; } Log.Cyan(false, $"Your answer to match param '{oldDParam.Name}'? [0..{paramCounter - 1}]: "); if (!int.TryParse(Console.ReadLine(), out paramSelection)) { Log.Error("Not a number. Try again."); paramSelection = -1; } else if (paramSelection < 0 || paramSelection >= paramCounter) { Log.Error("Invalid selection. Try again."); paramSelection = -1; } else if (paramSelection == 0) { Log.Info("Goodbye!"); Environment.Exit(0); } else { newTsParam = tsMember.Params[paramSelection - 1]; Log.Success($"Selected: {newTsParam.Name}"); } } break; } case 2: { Log.Info("Skipping this param."); break; } default: { Log.Error("Invalid selection. Try again."); option = -1; break; } } } } return(created); }
/// <summary> /// If a Param is found in the DocsMember that did not exist in the Triple Slash member, it's possible the param was unexpectedly saved in the triple slash comments with a different name, so the user gets prompted to look for it. /// </summary> /// <param name="tsParam">The problematic triple slash param object.</param> /// <param name="dMember">The docs member where the param lives.</param> /// <param name="dParam">The docs param that was found to not match the triple slash param.</param> /// <returns></returns> private static bool TryPromptParam(TripleSlashParam tsParam, DocsMember dMember, out DocsParam dParam) { dParam = null; bool created = false; int option = -1; while (option == -1) { Log.Error("Problem in member {0} in file {1}!", dMember.DocId, dMember.FilePath); Log.Warning("The param from triple slash called '{0}' probably exists in code, but the name was not found in Docs. What would you like to do?", tsParam.Name); Log.Warning(" 1 - Type the correct name as it shows up in Docs."); Log.Warning(" 2 - Add the newly detected param to the Docs file (not recommended)."); Log.Warning(" Note: Whatever your choice, make sure to double check the affected Docs file after the tool finishes executing."); Log.Info(false, "Your answer [1,2]: "); if (!int.TryParse(Console.ReadLine(), out option)) { Log.Error("Invalid selection. Try again."); option = -1; } else { switch (option) { case 1: { string newName = string.Empty; while (string.IsNullOrWhiteSpace(newName)) { Log.Info(false, "Type the new name: "); newName = Console.ReadLine().Trim(); if (string.IsNullOrWhiteSpace(newName)) { Log.Error("Invalid selection. Try again."); } else if (newName == tsParam.Name) { Log.Error("You specified the same name. Try again."); newName = string.Empty; } else { dParam = dMember.Params.FirstOrDefault(x => x.Name == newName); if (dParam == null) { Log.Error("Could not find the param with the selected name. Try again."); newName = string.Empty; } else { Log.Success("Found the param with the selected name!"); } } } break; } case 2: { dParam = dMember.SaveParam(tsParam.XEParam); created = true; break; } default: { Log.Error("Invalid selection. Try again."); option = -1; break; } } } } return(created); }
private void TryPortMissingParamsForAPI(IDocsAPI dApiToUpdate, TripleSlashMember?tsMemberToPort, DocsMember?interfacedMember) { bool created; bool isEII; string name; string value; string prefix = dApiToUpdate.Prefix; if (tsMemberToPort != null) { foreach (DocsParam dParam in dApiToUpdate.Params) { if (IsEmpty(dParam.Value)) { created = false; isEII = false; name = string.Empty; value = string.Empty; TripleSlashParam tsParam = tsMemberToPort.Params.FirstOrDefault(x => x.Name == dParam.Name); // When not found, it's a bug in Docs (param name not the same as source/ref), so need to ask the user to indicate correct name if (tsParam == null) { ProblematicAPIs.AddIfNotExists($"Param=[{dParam.Name}] in Member DocId=[{dApiToUpdate.DocId}]"); if (tsMemberToPort.Params.Count() == 0) { ProblematicAPIs.AddIfNotExists($"Param=[{dParam.Name}] in Member DocId=[{dApiToUpdate.DocId}]"); Log.Warning($" There were no triple slash comments for param '{dParam.Name}' in {dApiToUpdate.DocId}"); } else { created = TryPromptParam(dParam, tsMemberToPort, out TripleSlashParam? newTsParam); if (newTsParam == null) { Log.Error($" There param '{dParam.Name}' was not found in triple slash for {dApiToUpdate.DocId}"); } else { // Now attempt to document it if (!IsEmpty(newTsParam.Value)) { // try to port triple slash comments dParam.Value = newTsParam.Value; name = newTsParam.Name; value = newTsParam.Value; } // or try to find if it implements a documented interface else if (interfacedMember != null) { DocsParam interfacedParam = interfacedMember.Params.FirstOrDefault(x => x.Name == newTsParam.Name || x.Name == dParam.Name); if (interfacedParam != null) { dParam.Value = interfacedParam.Value; name = interfacedParam.Name; value = interfacedParam.Value; isEII = true; } } } } } // Attempt to port else if (!IsEmpty(tsParam.Value)) { // try to port triple slash comments dParam.Value = tsParam.Value; name = tsParam.Name; value = tsParam.Value; } // or try to find if it implements a documented interface else if (interfacedMember != null) { DocsParam interfacedParam = interfacedMember.Params.FirstOrDefault(x => x.Name == dParam.Name); if (interfacedParam != null) { dParam.Value = interfacedParam.Value; name = interfacedParam.Name; value = interfacedParam.Value; isEII = true; } } if (!IsEmpty(value)) { string message = $"{prefix} {GetIsEII(isEII)} PARAM '{dParam.Name}' ({GetIsCreated(created)})"; PrintModifiedMember(message, dApiToUpdate.FilePath, dApiToUpdate.DocId); TotalModifiedIndividualElements++; } } } } else if (interfacedMember != null) { foreach (DocsParam dParam in dApiToUpdate.Params) { if (IsEmpty(dParam.Value)) { DocsParam interfacedParam = interfacedMember.Params.FirstOrDefault(x => x.Name == dParam.Name); if (interfacedParam != null && !IsEmpty(interfacedParam.Value)) { dParam.Value = interfacedParam.Value; string message = $"{prefix} EII PARAM '{dParam.Name}' ({GetIsCreated(false)})"; PrintModifiedMember(message, dApiToUpdate.FilePath, dApiToUpdate.DocId); TotalModifiedIndividualElements++; } } } } }
private static bool TryPortMissingCommentsForMember(TripleSlashMember tsMember, DocsMember dMember) { bool modified = false; if (!IsEmpty(tsMember.Summary) && IsEmpty(dMember.Summary)) { // Any member can have an empty summary PrintModifiedMember("MEMBER SUMMARY", dMember.FilePath, tsMember.Name, dMember.DocId, tsMember.Summary, dMember.Summary); dMember.Summary = tsMember.Summary; TotalModifiedIndividualElements++; modified = true; } if (!IsEmpty(tsMember.Remarks) && IsEmpty(dMember.Remarks)) { // Any member can have an empty remark PrintModifiedMember("MEMBER REMARKS", dMember.FilePath, tsMember.Name, dMember.DocId, tsMember.Remarks, dMember.Remarks); dMember.Remarks = tsMember.Remarks; TotalModifiedIndividualElements++; modified = true; } // Properties and method returns save their values in different locations if (dMember.MemberType == "Property") { if (!IsEmpty(tsMember.Returns) && IsEmpty(dMember.Value)) { PrintModifiedMember("PROPERTY", dMember.FilePath, tsMember.Name, dMember.DocId, tsMember.Returns, dMember.Value); dMember.Value = tsMember.Returns; TotalModifiedIndividualElements++; modified = true; } } else if (dMember.MemberType == "Method") { if (!IsEmpty(tsMember.Returns) && IsEmpty(dMember.Returns)) { if (tsMember.Returns != null && dMember.ReturnType == "System.Void") { ProblematicAPIs.AddIfNotExists($"Returns=[{tsMember.Returns}] in Method=[{dMember.DocId}]"); } else { PrintModifiedMember("METHOD RETURN", dMember.FilePath, tsMember.Name, dMember.DocId, tsMember.Returns, dMember.Returns); dMember.Returns = tsMember.Returns; TotalModifiedIndividualElements++; modified = true; } } } // Triple slash params may cause errors if they are missing in the code side foreach (TripleSlashParam tsParam in tsMember.Params) { DocsParam dParam = dMember.Params.FirstOrDefault(x => x.Name == tsParam.Name); bool created = false; if (dParam == null) { ProblematicAPIs.AddIfNotExists($"Param=[{tsParam.Name}] in Member DocId=[{dMember.DocId}]"); created = TryPromptParam(tsParam, dMember, out dParam); } if (created || (!IsEmpty(tsParam.Value) && IsEmpty(dParam.Value))) { PrintModifiedMember(string.Format("PARAM ({0})", created ? "CREATED" : "MODIFIED"), dParam.FilePath, tsParam.Name, dParam.Name, tsParam.Value, dParam.Value); if (!created) { dParam.Value = tsParam.Value; } TotalModifiedIndividualElements++; modified = true; } } // Exceptions are a special case: If a new one is found in code, but does not exist in docs, the whole element needs to be added foreach (TripleSlashException tsException in tsMember.Exceptions) { DocsException dException = dMember.Exceptions.FirstOrDefault(x => x.Cref.EndsWith(tsException.Cref)); bool created = false; if (dException == null) { dException = dMember.SaveException(tsException.XEException); AddedExceptions.AddIfNotExists($"{dException.Cref} in {dMember.DocId}"); created = true; } if (created || (!IsEmpty(tsException.Value) && IsEmpty(dException.Value))) { PrintModifiedMember(string.Format("EXCEPTION ({0})", created ? "CREATED" : "MODIFIED"), dException.FilePath, tsException.Cref, dException.Cref, tsException.Value, dException.Value); if (!created) { dException.Value = tsException.Value; } TotalModifiedIndividualElements++; modified = true; } } foreach (TripleSlashTypeParam tsTypeParam in tsMember.TypeParams) { DocsTypeParam dTypeParam = dMember.TypeParams.FirstOrDefault(x => x.Name == tsTypeParam.Name); bool created = false; if (dTypeParam == null) { ProblematicAPIs.AddIfNotExists($"TypeParam=[{tsTypeParam.Name}] in Member=[{dMember.DocId}]"); dTypeParam = dMember.SaveTypeParam(tsTypeParam.XETypeParam); created = true; } if (created || (!IsEmpty(tsTypeParam.Value) && IsEmpty(dTypeParam.Value))) { PrintModifiedMember(string.Format("TYPE PARAM ({0})", created ? "CREATED" : "MODIFIED"), dTypeParam.FilePath, tsTypeParam.Name, dTypeParam.Name, tsTypeParam.Value, dTypeParam.Value); if (!created) { dTypeParam.Value = tsTypeParam.Value; } TotalModifiedIndividualElements++; modified = true; } } if (modified) { ModifiedAPIs.AddIfNotExists(dMember.DocId); } return(modified); }