/// <summary> /// Obtains a <em><command:examples></em> element for a cmdlet's examples. /// </summary> /// <param name="commentReader">The comment reader.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Used to log any warnings.</param> /// <returns>An examples element for the cmdlet.</returns> public static XElement GetCommandExamplesElement(this ICommentReader commentReader, Command command, ReportWarning reportWarning) { var cmdletType = command.CmdletType; var comments = commentReader.GetComments(cmdletType); if (comments == null) { reportWarning(cmdletType, "No XML doc comment found."); return null; } var xmlDocExamples = comments.XPathSelectElements("//example").ToList(); if (!xmlDocExamples.Any()) { reportWarning(cmdletType, "No examples found."); return null; } var examples = new XElement(commandNs + "examples"); int exampleNumber = 1; foreach (var xmlDocExample in xmlDocExamples) { var example = GetCommandExampleElement(xmlDocExample, exampleNumber, warningText => reportWarning(cmdletType, warningText)); if (example != null) { examples.Add(example); exampleNumber++; } } return exampleNumber == 1 ? null : examples; }
/// <summary> /// Creates a new instance that decorates the specified <paramref name="proxy"/>. /// </summary> /// <param name="proxy">The decorated proxy.</param> /// <param name="reportWarning">Used to report failed comment lookups.</param> public LoggingCommentReader(ICommentReader proxy, ReportWarning reportWarning) { if (proxy == null) throw new ArgumentNullException(nameof(proxy)); if (reportWarning == null) throw new ArgumentNullException(nameof(reportWarning)); _proxy = proxy; _reportWarning = reportWarning; }
/// <summary> /// Obtains a <em><maml:alertSet></em> element for a cmdlet's notes. /// </summary> /// <param name="commentReader">The comment reader.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Used to log any warnings.</param> /// <returns>A <em><maml:alertSet></em> element for the cmdlet's notes.</returns> public static XElement GetCommandAlertSetElement(this ICommentReader commentReader, Command command, ReportWarning reportWarning) { var cmdletType = command.CmdletType; var comments = commentReader.GetComments(cmdletType); if (comments == null) { return null; } // First see if there's an alertSet element in the comments var alertSet = comments.XPathSelectElement("//maml:alertSet", Resolver); if (alertSet != null) { return alertSet; } // Next, search for a list element of type <em>alertSet</em>. var list = comments.XPathSelectElement("//list[@type='alertSet']"); if (list == null) { return null; } alertSet = new XElement(MamlNs + "alertSet"); foreach (var item in list.XPathSelectElements("item")) { var term = item.XPathSelectElement("term"); var description = item.XPathSelectElement("description"); if (term != null && description != null) { var alertTitle = new XElement(MamlNs + "title", Tidy(term.Value)); var alert = new XElement(MamlNs + "alert"); var paras = description.XPathSelectElements("para").ToList(); if (paras.Any()) { paras.ForEach(para => alert.Add(new XElement(MamlNs + "para", Tidy(para.Value)))); } else { alert.Add(new XElement(MamlNs + "para", Tidy(description.Value))); } alertSet.Add(alertTitle, alert); } } return alertSet; }
/// <summary> /// Obtains a <em><maml:description></em> element for a cmdlet's synopsis. /// </summary> /// <param name="commentReader">The comment reader.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Used to record warnings.</param> /// <returns>A description element for the cmdlet's synopsis.</returns> public static XElement GetCommandSynopsisElement(this ICommentReader commentReader, Command command, ReportWarning reportWarning) { var cmdletType = command.CmdletType; var commentsElement = commentReader.GetComments(cmdletType); return GetMamlDescriptionElementFromXmlDocComment(commentsElement, "synopsis", warningText => reportWarning(cmdletType, warningText)); }
/// <summary> /// The default value of the parameter. This is obtained by instantiating the cmdlet and accessing the parameter /// property or field to determine its initial value. /// </summary> public object GetDefaultValue(ReportWarning reportWarning) { var cmdlet = Activator.CreateInstance(_cmdletType); switch (MemberInfo.MemberType) { case MemberTypes.Property: var propertyInfo = ((PropertyInfo) MemberInfo); if (!propertyInfo.CanRead) { reportWarning(MemberInfo, "Parameter does not have a getter. Unable to determine its default value"); return null; } return propertyInfo.GetValue(cmdlet); case MemberTypes.Field: return ((FieldInfo) MemberInfo).GetValue(cmdlet); default: throw new NotSupportedException("Unsupported type: " + MemberInfo); } }
/// <summary> /// Generates the <em><maml:alertSet></em> element for a command. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><maml:alertSet></em> element for the <paramref name="command"/>.</returns> private XElement GenerateAlertSetElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { return commentReader.GetCommandAlertSetElement(command, reportWarning); }
/// <summary> /// Fetch the description from the ICommentReader. /// If the parameter is an Enum, add to the description a list of its legal values. /// </summary> private static XElement GenerateDescriptionElement(ICommentReader commentReader, Parameter parameter, ReportWarning reportWarning) { var descriptionElement = commentReader.GetParameterDescriptionElement(parameter, reportWarning); if (parameter.EnumValues.Any()) { if (descriptionElement == null) { descriptionElement = new XElement(mamlNs + "description"); } descriptionElement.Add( new XElement(mamlNs + "para", "Possible values: " + string.Join(", ", parameter.EnumValues))); } return descriptionElement; }
/// <summary> /// Generates the <em><command:syntaxItem></em> element for a specific parameter set of a command. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="command">The command.</param> /// <param name="parameterSetName">The parameter set name.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:syntaxItem></em> element for the specific <paramref name="parameterSetName"/> of the <paramref name="command"/>.</returns> private XElement GenerateSyntaxItemElement(ICommentReader commentReader, Command command, string parameterSetName, ReportWarning reportWarning) { var syntaxItemElement = new XElement(commandNs + "syntaxItem", new XElement(mamlNs + "name", command.Name)); foreach (var parameter in command.GetParameters(parameterSetName)) { syntaxItemElement.Add(GenerateComment("Parameter: " + parameter.Name)); syntaxItemElement.Add(GenerateParameterElement(commentReader, parameter, parameterSetName, reportWarning)); } return syntaxItemElement; }
/// <summary> /// Generates a <em><command:command></em> element for the specified command. /// </summary> /// <param name="commentReader"></param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:command></em> element that represents the <paramref name="command"/>.</returns> private XElement GenerateCommandElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { return new XElement(commandNs + "command", new XAttribute(XNamespace.Xmlns + "maml", mamlNs), new XAttribute(XNamespace.Xmlns + "command", commandNs), new XAttribute(XNamespace.Xmlns + "dev", devNs), GenerateDetailsElement(commentReader, command, reportWarning), GenerateDescriptionElement(commentReader, command, reportWarning), GenerateSyntaxElement(commentReader, command, reportWarning), GenerateParametersElement(commentReader, command, reportWarning), GenerateInputTypesElement(commentReader, command, reportWarning), GenerateReturnValuesElement(commentReader, command, reportWarning), GenerateAlertSetElement(commentReader, command, reportWarning), GenerateExamplesElement(commentReader, command, reportWarning), GenerateRelatedLinksElement(commentReader, command, reportWarning)); }
/// <summary> /// Obtains a <em><maml:description></em> element for a type. /// </summary> /// <param name="commentReader">The comment reader.</param> /// <param name="type">The type for which a description is required.</param> /// <param name="reportWarning">Used to log any warnings.</param> /// <returns>A description for the type, or null if no description is available.</returns> public static XElement GetTypeDescriptionElement(this ICommentReader commentReader, Type type, ReportWarning reportWarning) { var commentsElement = commentReader.GetComments(type); return GetMamlDescriptionElementFromXmlDocComment(commentsElement, "description", warningText => reportWarning(type, warningText)); }
/// <summary> /// Obtains a <em><maml:description></em> element for a cmdlet's full description. /// </summary> /// <param name="commentReader">The comment reader.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Used to record warnings.</param> /// <returns>A description element for the cmdlet's full description.</returns> public static XElement GetCommandDescriptionElement(this ICommentReader commentReader, Command command, ReportWarning reportWarning) { var cmdletType = command.CmdletType; var commentsElement = commentReader.GetComments(cmdletType); return(GetMamlDescriptionElementFromXmlDocComment(commentsElement, "description", warningText => reportWarning(cmdletType, warningText))); }
/// <summary> /// Obtains a <em><dev:defaultValue></em> element for a parameter. /// </summary> /// <param name="commentReader">The comment reader.</param> /// <param name="parameter">The parameter.</param> /// <param name="reportWarning">Used to record warnings.</param> /// <returns>A default value element for the parameter's default value, or <em>null</em> if a default value could not be obtained.</returns> public static XElement GetParameterDefaultValueElement(this ICommentReader commentReader, Parameter parameter, ReportWarning reportWarning) { var defaultValue = parameter.GetDefaultValue(reportWarning); // TODO: Get the default value from the doc comments? if (defaultValue != null) { if (defaultValue is IEnumerable enumerable && !(defaultValue is string)) { var content = string.Join(", ", enumerable.Cast <object>().Select(element => element.ToString())); if (content != "") { return(new XElement(DevNs + "defaultValue", content)); } } else { return(new XElement(DevNs + "defaultValue", defaultValue.ToString())); } }
/// <summary> /// /// </summary> /// <param name="commentReader">The comment reader.</param> /// <param name="parameter">The parameter.</param> /// <param name="reportWarning">Used to record warnings.</param> /// <returns>A description element for the parameter.</returns> public static XElement GetParameterValueElement(this ICommentReader commentReader, Parameter parameter, ReportWarning reportWarning) { return(new XElement(CommandNs + "parameterValue", new XAttribute("required", true), GetSimpleTypeName(parameter.ParameterType))); }
/// <summary> /// Obtains a <em><maml:description></em> element for a parameter. /// </summary> /// <param name="commentReader">The comment reader.</param> /// <param name="parameter">The parameter.</param> /// <param name="reportWarning">Used to record warnings.</param> /// <returns>A description element for the parameter.</returns> public static XElement GetParameterDescriptionElement(this ICommentReader commentReader, Parameter parameter, ReportWarning reportWarning) { var reflectionParameter = parameter as ReflectionParameter; if (reflectionParameter != null) { var memberInfo = reflectionParameter.MemberInfo; var commentsElement = commentReader.GetComments(memberInfo); return(GetMamlDescriptionElementFromXmlDocComment(commentsElement, "description", warningText => reportWarning(memberInfo, warningText))); } //Other parameter types do not support XML comments. return(null); }
/// <summary> /// Obtains a <em><maml:alertSet></em> element for a cmdlet's notes. /// </summary> /// <param name="commentReader">The comment reader.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Used to log any warnings.</param> /// <returns>A <em><maml:alertSet></em> element for the cmdlet's notes.</returns> public static XElement GetCommandAlertSetElement(this ICommentReader commentReader, Command command, ReportWarning reportWarning) { var cmdletType = command.CmdletType; var comments = commentReader.GetComments(cmdletType); if (comments == null) { return(null); } // First see if there's an alertSet element in the comments var alertSet = comments.XPathSelectElement("//maml:alertSet", Resolver); if (alertSet != null) { return(alertSet); } // Next, search for a list element of type <em>alertSet</em>. var list = comments.XPathSelectElement("//list[@type='alertSet']"); if (list == null) { return(null); } alertSet = new XElement(MamlNs + "alertSet"); foreach (var item in list.XPathSelectElements("item")) { var term = item.XPathSelectElement("term"); var description = item.XPathSelectElement("description"); if (term != null && description != null) { var alertTitle = new XElement(MamlNs + "title", Tidy(term.Value)); var alert = new XElement(MamlNs + "alert"); var paras = description.XPathSelectElements("para").ToList(); if (paras.Any()) { paras.ForEach(para => alert.Add(new XElement(MamlNs + "para", Tidy(para.Value)))); } else { alert.Add(new XElement(MamlNs + "para", Tidy(description.Value))); } alertSet.Add(alertTitle, alert); } } return(alertSet); }
/// <summary> /// Obtains a <em><command:relatedLinks></em> element for a cmdlet's related links. /// </summary> /// <param name="commentReader">The comment reader.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Used to log any warnings.</param> /// <returns>An relatedLinks element for the cmdlet.</returns> public static XElement GetCommandRelatedLinksElement(this ICommentReader commentReader, Command command, ReportWarning reportWarning) { var cmdletType = command.CmdletType; var comments = commentReader.GetComments(cmdletType); if (comments == null) { return(null); } var paras = comments.XPathSelectElements("//para[@type='link']").ToList(); if (!paras.Any()) { return(null); } var relatedLinks = new XElement(MamlNs + "relatedLinks"); foreach (var para in paras) { var navigationLink = new XElement(MamlNs + "navigationLink", new XElement(MamlNs + "linkText", para.Value)); var uri = para.Attribute("uri"); if (uri != null) { navigationLink.Add(new XElement(MamlNs + "uri", uri.Value)); } relatedLinks.Add(navigationLink); } return(relatedLinks); }
/// <summary> /// Obtains a <em><maml:description></em> for a command's output type. /// </summary> /// <param name="commentReader">The comment reader.</param> /// <param name="command">The command.</param> /// <param name="outputType">The output type of the command.</param> /// <param name="reportWarning">Used to log any warnings.</param> /// <returns>A <em><maml:description></em> for the command's output type, /// or null if no explicit description is available for the output type.</returns> public static XElement GetOutputTypeDescriptionElement(this ICommentReader commentReader, Command command, Type outputType, ReportWarning reportWarning) { // TODO: Get the description from the <remarks type="outputType" cref="<type>"> element return commentReader.GetTypeDescriptionElement(outputType, reportWarning); }
/// <summary> /// Obtains a <em><maml:description></em> element for a parameter. /// </summary> /// <param name="commentReader">The comment reader.</param> /// <param name="parameter">The parameter.</param> /// <param name="reportWarning">Used to record warnings.</param> /// <returns>A description element for the parameter.</returns> public static XElement GetParameterDescriptionElement(this ICommentReader commentReader, Parameter parameter, ReportWarning reportWarning) { var memberInfo = parameter.MemberInfo; var commentsElement = commentReader.GetComments(memberInfo); return GetMamlDescriptionElementFromXmlDocComment(commentsElement, "description", warningText => reportWarning(memberInfo, warningText)); }
/// <summary> /// Obtains a <em><command:examples></em> element for a cmdlet's examples. /// </summary> /// <param name="commentReader">The comment reader.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Used to log any warnings.</param> /// <returns>An examples element for the cmdlet.</returns> public static XElement GetCommandExamplesElement(this ICommentReader commentReader, Command command, ReportWarning reportWarning) { var cmdletType = command.CmdletType; var comments = commentReader.GetComments(cmdletType); if (comments == null) { reportWarning(cmdletType, "No XML doc comment found."); return(null); } var xmlDocExamples = comments.XPathSelectElements("//example").ToList(); if (!xmlDocExamples.Any()) { reportWarning(cmdletType, "No examples found."); return(null); } var examples = new XElement(CommandNs + "examples"); int exampleNumber = 1; foreach (var xmlDocExample in xmlDocExamples) { var example = GetCommandExampleElement(xmlDocExample, exampleNumber, warningText => reportWarning(cmdletType, warningText)); if (example != null) { examples.Add(example); exampleNumber++; } } return(exampleNumber == 1 ? null : examples); }
/// <summary> /// Obtains an XML Doc comment reader for the assembly in the specified <paramref name="options"/>. /// </summary> /// <param name="options">The options.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A comment reader for the assembly in the <paramref name="options"/>.</returns> private ICommentReader LoadComments(Options options, ReportWarning reportWarning) { var docCommentsPath = options.DocCommentsPath; if (!File.Exists(docCommentsPath)) { throw new EngineException(EngineExitCode.AssemblyCommentsNotFound, "Assembly comments file not found: " + docCommentsPath); } try { return new CachingCommentReader( new RewritingCommentReader( new LoggingCommentReader( new JoltCommentReader(docCommentsPath), reportWarning))); } catch (Exception exception) { throw new EngineException(EngineExitCode.DocCommentsLoadError, "Failed to load XML Doc comments from file: " + docCommentsPath, exception); } }
/// <summary> /// Generates the <em><command:details></em> element for a command. /// </summary> /// <param name="commentReader"></param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:details></em> element for the <paramref name="command"/>.</returns> private XElement GenerateDetailsElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { return(new XElement(CommandNs + "details", new XElement(CommandNs + "name", command.Name), new XElement(CommandNs + "verb", command.Verb), new XElement(CommandNs + "noun", command.Noun), commentReader.GetCommandSynopsisElement(command, reportWarning))); }
/// <summary> /// Generates the <em><maml:description></em> element for a command. /// </summary> /// <param name="commentReader"></param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><maml:description></em> element for the <paramref name="command"/>.</returns> private XElement GenerateDescriptionElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { return commentReader.GetCommandDescriptionElement(command, reportWarning); }
/// <summary> /// Generates the <em><maml:description></em> element for a command. /// </summary> /// <param name="commentReader"></param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><maml:description></em> element for the <paramref name="command"/>.</returns> private XElement GenerateDescriptionElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { return(commentReader.GetCommandDescriptionElement(command, reportWarning)); }
// Because the proper aliases generated in GenerateParameterElement are not manifested by Get-Help, // this simply duplicates parameters that have aliases, substituting in the alias name. // Thus, one could do Get-Help xyz -param actualName or Get-Help xyz -param aliasName private void GenerateAliasElements(ICommentReader commentReader, ReportWarning reportWarning, Parameter parameter, XElement parametersElement) { foreach (var alias in parameter.Aliases) { var parameterElement = GenerateParameterElement(commentReader, parameter, ParameterAttribute.AllParameterSets, reportWarning); parametersElement.Add(parameterElement); var nameElement = (XElement) (parameterElement.Nodes().First(n => ((XElement) n).Name == mamlNs + "name")); nameElement.Value = alias; var descriptionElement = (XElement) (parameterElement.Nodes().FirstOrDefault(n => ((XElement) n).Name == mamlNs + "description")); if (descriptionElement == null) { descriptionElement = new XElement(mamlNs + "description"); parameterElement.Add(descriptionElement); } descriptionElement.Add(new XElement(mamlNs + "para", string.Format("This is an alias of the {0} parameter.", parameter.Name))); } }
/// <summary> /// Generates the <em><command:syntax></em> element for a command. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:syntax></em> element for the <paramref name="command"/>.</returns> private XElement GenerateSyntaxElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { var syntaxElement = new XElement(CommandNs + "syntax"); IEnumerable <string> parameterSetNames = command.ParameterSetNames.ToList(); if (parameterSetNames.Count() > 1) { parameterSetNames = parameterSetNames.Where(name => name != ParameterAttribute.AllParameterSets); } foreach (var parameterSetName in parameterSetNames) { syntaxElement.Add(GenerateComment("Parameter set: " + parameterSetName)); syntaxElement.Add(GenerateSyntaxItemElement(commentReader, command, parameterSetName, reportWarning)); } return(syntaxElement); }
/// <summary> /// Generates the <em><command:inputType></em> element for a pipeline parameter. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="parameter">The parameter.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:inputType></em> element for the <paramref name="parameter"/>'s type.</returns> private XElement GenerateInputTypeElement(ICommentReader commentReader, Parameter parameter, ReportWarning reportWarning) { var inputTypeDescription = commentReader.GetInputTypeDescriptionElement(parameter, reportWarning); return new XElement(commandNs + "inputType", GenerateTypeElement(commentReader, parameter.ParameterType, inputTypeDescription == null, reportWarning), inputTypeDescription); }
/// <summary> /// Generates the <em><command:syntaxItem></em> element for a specific parameter set of a command. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="command">The command.</param> /// <param name="parameterSetName">The parameter set name.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:syntaxItem></em> element for the specific <paramref name="parameterSetName"/> of the <paramref name="command"/>.</returns> private XElement GenerateSyntaxItemElement(ICommentReader commentReader, Command command, string parameterSetName, ReportWarning reportWarning) { var syntaxItemElement = new XElement(CommandNs + "syntaxItem", new XElement(MamlNs + "name", command.Name)); foreach (var parameter in command.GetParameters(parameterSetName).OrderBy(p => p.GetPosition(parameterSetName)). ThenBy(p => p.IsRequired(parameterSetName) ? "0" : "1"). ThenBy(p => p.Name)) { syntaxItemElement.Add(GenerateComment("Parameter: " + parameter.Name)); syntaxItemElement.Add(GenerateParameterElement(commentReader, parameter, parameterSetName, reportWarning)); } return(syntaxItemElement); }
/// <summary> /// Generates the <em><command:syntaxItem></em> element for a specific parameter set of a command. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="command">The command.</param> /// <param name="parameterSetName">The parameter set name.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:syntaxItem></em> element for the specific <paramref name="parameterSetName"/> of the <paramref name="command"/>.</returns> private XElement GenerateSyntaxItemElement(ICommentReader commentReader, Command command, string parameterSetName, ReportWarning reportWarning) { var syntaxItemElement = new XElement(commandNs + "syntaxItem", new XElement(mamlNs + "name", command.Name)); foreach (var parameter in command.GetParameters(parameterSetName)) { syntaxItemElement.Add(GenerateComment("Parameter: " + parameter.Name)); syntaxItemElement.Add(GenerateParameterElement(commentReader, parameter, parameterSetName, reportWarning)); } return(syntaxItemElement); }
/// <summary> /// Generates the <em><command:parameters></em> element for a command. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:parameters></em> element for the <paramref name="command"/>.</returns> private XElement GenerateParametersElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { var parametersElement = new XElement(CommandNs + "parameters"); foreach (var parameter in command.Parameters) { parametersElement.Add(GenerateComment("Parameter: " + parameter.Name)); parametersElement.Add(GenerateParameterElement(commentReader, parameter, ParameterAttribute.AllParameterSets, reportWarning)); GenerateAliasElements(commentReader, reportWarning, parameter, parametersElement); } return(parametersElement); }
/// <summary> /// Obtains a <em><command:relatedLinks></em> element for a cmdlet's related links. /// </summary> /// <param name="commentReader">The comment reader.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Used to log any warnings.</param> /// <returns>An relatedLinks element for the cmdlet.</returns> public static XElement GetCommandRelatedLinksElement(this ICommentReader commentReader, Command command, ReportWarning reportWarning) { var cmdletType = command.CmdletType; var comments = commentReader.GetComments(cmdletType); if (comments == null) { return null; } var paras = comments.XPathSelectElements("//para[@type='link']").ToList(); if (!paras.Any()) return null; var relatedLinks = new XElement(MamlNs + "relatedLinks"); foreach (var para in paras) { var navigationLink = new XElement(MamlNs + "navigationLink", new XElement(MamlNs + "linkText", para.Value)); var uri = para.Attribute("uri"); if (uri != null) { navigationLink.Add(new XElement(MamlNs + "uri", uri.Value)); } relatedLinks.Add(navigationLink); } return relatedLinks; }
/// <summary> /// Generates a <em><command:parameter></em> element for a single parameter. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="parameter">The parameter.</param> /// <param name="parameterSetName">The specific parameter set name, or <see cref="ParameterAttribute.AllParameterSets"/>.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:parameter></em> element for the <paramref name="parameter"/>.</returns> private XElement GenerateParameterElement(ICommentReader commentReader, Parameter parameter, string parameterSetName, ReportWarning reportWarning) { var element = new XElement(CommandNs + "parameter", new XAttribute("required", parameter.IsRequired(parameterSetName)), new XAttribute("globbing", parameter.SupportsGlobbing(parameterSetName)), new XAttribute("pipelineInput", parameter.GetIsPipelineAttribute(parameterSetName)), new XAttribute("position", parameter.GetPosition(parameterSetName)), new XElement(MamlNs + "name", parameter.Name), GenerateDescriptionElement(commentReader, parameter, reportWarning), commentReader.GetParameterValueElement(parameter, reportWarning), GenerateTypeElement(commentReader, parameter.ParameterType, true, reportWarning), commentReader.GetParameterDefaultValueElement(parameter, reportWarning), GetParameterEnumeratedValuesElement(parameter)); var aliasNames = parameter.Aliases.ToList(); if (aliasNames.Count > 0) { element.Add(new XAttribute("aliases", string.Join(",", aliasNames))); } return(element); }
/// <summary> /// Obtains a <em><maml:description></em> for an <em><command:inputType></em> coresponding to a specified parameter that accepts pipeline input. /// </summary> /// <param name="commentReader">The comment reader.</param> /// <param name="parameter">The parameter.</param> /// <param name="reportWarning">Used to log any warnings.</param> /// <returns>A <em><maml:description></em> for an <em><command:inputType></em> for the parameter, or null if no explicit description is available /// for the input type.</returns> public static XElement GetInputTypeDescriptionElement(this ICommentReader commentReader, Parameter parameter, ReportWarning reportWarning) { var parameterMemberInfo = parameter.MemberInfo; var commentsElement = commentReader.GetComments(parameterMemberInfo); // First try to read the explicit inputType description. var inputTypeDescription = GetMamlDescriptionElementFromXmlDocComment(commentsElement, "inputType", _ => { }); if (inputTypeDescription != null) { return inputTypeDescription; } // Then fall back to using the parameter description. var parameterDescription = commentReader.GetParameterDescriptionElement(parameter, reportWarning); if (parameterDescription == null) { reportWarning(parameterMemberInfo, "No inputType comment found and no fallback description comment found."); } return parameterDescription; }
/// <summary> /// Fetch the description from the ICommentReader. /// If the parameter is an Enum, add to the description a list of its legal values. /// </summary> private static XElement GenerateDescriptionElement(ICommentReader commentReader, Parameter parameter, ReportWarning reportWarning) { var descriptionElement = commentReader.GetParameterDescriptionElement(parameter, reportWarning); if (parameter.EnumValues.Any()) { if (descriptionElement == null) { descriptionElement = new XElement(MamlNs + "description"); } descriptionElement.Add( new XElement(MamlNs + "para", "Possible values: " + string.Join(", ", parameter.EnumValues))); } return(descriptionElement); }
/// <summary> /// Obtains a <em><dev:defaultValue></em> element for a parameter. /// </summary> /// <param name="commentReader">The comment reader.</param> /// <param name="parameter">The parameter.</param> /// <param name="reportWarning">Used to record warnings.</param> /// <returns>A default value element for the parameter's default value, or <em>null</em> if a default value could not be obtained.</returns> public static XElement GetParameterDefaultValueElement(this ICommentReader commentReader, Parameter parameter, ReportWarning reportWarning) { var defaultValue = parameter.GetDefaultValue(reportWarning); // TODO: Get the default value from the doc comments? if (defaultValue != null) { return new XElement(DevNs + "defaultValue", defaultValue.ToString()); } return null; }
/// <summary> /// Generates the <em><command:inputTypes></em> element for a command. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:inputTypes></em> element for the <paramref name="command"/>.</returns> private XElement GenerateInputTypesElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { var inputTypesElement = new XElement(CommandNs + "inputTypes"); var pipelineParameters = command.GetParameters(ParameterAttribute.AllParameterSets) .Where(p => p.IsPipeline(ParameterAttribute.AllParameterSets)); foreach (var parameter in pipelineParameters) { inputTypesElement.Add(GenerateInputTypeElement(commentReader, parameter, reportWarning)); } return(inputTypesElement); }
/// <summary> /// /// </summary> /// <param name="commentReader">The comment reader.</param> /// <param name="parameter">The parameter.</param> /// <param name="reportWarning">Used to record warnings.</param> /// <returns>A description element for the parameter.</returns> public static XElement GetParameterValueElement(this ICommentReader commentReader, Parameter parameter, ReportWarning reportWarning) { return new XElement(CommandNs + "parameterValue", new XAttribute("required", true), GetSimpleTypeName(parameter.ParameterType)); }
/// <summary> /// Generates the <em><command:inputType></em> element for a pipeline parameter. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="parameter">The parameter.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:inputType></em> element for the <paramref name="parameter"/>'s type.</returns> private XElement GenerateInputTypeElement(ICommentReader commentReader, Parameter parameter, ReportWarning reportWarning) { var inputTypeDescription = commentReader.GetInputTypeDescriptionElement(parameter, reportWarning); return(new XElement(CommandNs + "inputType", GenerateTypeElement(commentReader, parameter.ParameterType, inputTypeDescription == null, reportWarning), inputTypeDescription)); }
/// <summary> /// Generates the <em><command:returnValues></em> element for a command. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:returnValues></em> element for the <paramref name="command"/>.</returns> private XElement GenerateReturnValuesElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { var returnValueElement = new XElement(CommandNs + "returnValues"); foreach (var type in command.OutputTypes) { returnValueElement.Add(GenerateComment("OutputType: " + (type == typeof(void) ? "None" : type.Name))); var returnValueDescription = commentReader.GetOutputTypeDescriptionElement(command, type, reportWarning); returnValueElement.Add(new XElement(CommandNs + "returnValue", GenerateTypeElement(commentReader, type, returnValueDescription == null, reportWarning), returnValueDescription)); } return(returnValueElement); }
/// <summary> /// Generates the <em><maml:alertSet></em> element for a command. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><maml:alertSet></em> element for the <paramref name="command"/>.</returns> private XElement GenerateAlertSetElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { return(commentReader.GetCommandAlertSetElement(command, reportWarning)); }
/// <summary> /// Generates the root-level <em><helpItems></em> element. /// </summary> /// <param name="commentReader"></param> /// <param name="commands">All of the commands in the module being documented.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>The root-level <em>helpItems</em> element.</returns> private XElement GenerateHelpItemsElement(ICommentReader commentReader, IEnumerable<Command> commands, ReportWarning reportWarning) { var helpItemsElement = new XElement(mshNs + "helpItems", new XAttribute("schema", "maml")); foreach (var command in commands) { helpItemsElement.Add(GenerateComment("Cmdlet: " + command.Name)); helpItemsElement.Add(GenerateCommandElement(commentReader, command, reportWarning)); } return helpItemsElement; }
/// <summary> /// Generates the <em><command:examples></em> element for a command. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:examples></em> element for the <paramref name="command"/>.</returns> private XElement GenerateExamplesElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { return(commentReader.GetCommandExamplesElement(command, reportWarning)); }
/// <summary> /// Generates the <em><command:details></em> element for a command. /// </summary> /// <param name="commentReader"></param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:details></em> element for the <paramref name="command"/>.</returns> private XElement GenerateDetailsElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { return new XElement(commandNs + "details", new XElement(commandNs + "name", command.Name), new XElement(commandNs + "verb", command.Verb), new XElement(commandNs + "noun", command.Noun), commentReader.GetCommandSynopsisElement(command, reportWarning)); }
/// <summary> /// Generates the <em><maml:relatedLinks></em> element for a command. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><maml:relatedLinks></em> element for the <paramref name="command"/>.</returns> private XElement GenerateRelatedLinksElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { return(commentReader.GetCommandRelatedLinksElement(command, reportWarning)); }
/// <summary> /// Generates the <em><command:syntax></em> element for a command. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:syntax></em> element for the <paramref name="command"/>.</returns> private XElement GenerateSyntaxElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { var syntaxElement = new XElement(commandNs + "syntax"); IEnumerable<string> parameterSetNames = command.ParameterSetNames.ToList(); if (parameterSetNames.Count() > 1) { parameterSetNames = parameterSetNames.Where(name => name != ParameterAttribute.AllParameterSets); } foreach (var parameterSetName in parameterSetNames) { syntaxElement.Add(GenerateComment("Parameter set: " + parameterSetName)); syntaxElement.Add(GenerateSyntaxItemElement(commentReader, command, parameterSetName, reportWarning)); } return syntaxElement; }
/// <summary> /// Generates a <em><dev:type></em> element for a type. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="type">The type for which a corresopnding <em><dev:type></em> element is required.</param> /// <param name="includeMamlDescription">Indicates whether or not a <em><maml:description></em> element should be /// included for the type. A description can be obtained from the type's XML Doc comment, but it is useful to suppress it if /// a more context-specific description is available where the <em><dev:type></em> element is actually used.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><dev:type></em> element for the specified <paramref name="type"/>.</returns> private XElement GenerateTypeElement(ICommentReader commentReader, Type type, bool includeMamlDescription, ReportWarning reportWarning) { return(new XElement(DevNs + "type", new XElement(MamlNs + "name", type == typeof(void) ? "None" : type.FullName), new XElement(MamlNs + "uri"), includeMamlDescription ? commentReader.GetTypeDescriptionElement(type, reportWarning) : null)); }
/// <summary> /// Generates the <em><command:parameters></em> element for a command. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:parameters></em> element for the <paramref name="command"/>.</returns> private XElement GenerateParametersElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { var parametersElement = new XElement(commandNs + "parameters"); foreach (var parameter in command.Parameters) { parametersElement.Add(GenerateComment("Parameter: " + parameter.Name)); parametersElement.Add(GenerateParameterElement(commentReader, parameter, ParameterAttribute.AllParameterSets, reportWarning)); GenerateAliasElements(commentReader, reportWarning, parameter, parametersElement); } return parametersElement; }
/// <summary> /// Generates the root-level <em><helpItems></em> element. /// </summary> /// <param name="commentReader"></param> /// <param name="commands">All of the commands in the module being documented.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>The root-level <em>helpItems</em> element.</returns> private XElement GenerateHelpItemsElement(ICommentReader commentReader, IEnumerable <Command> commands, ReportWarning reportWarning) { var helpItemsElement = new XElement(mshNs + "helpItems", new XAttribute("schema", "maml")); foreach (var command in commands) { helpItemsElement.Add(GenerateComment("Cmdlet: " + command.Name)); helpItemsElement.Add(GenerateCommandElement(commentReader, command, reportWarning)); } return(helpItemsElement); }
/// <summary> /// Generates a <em><command:parameter></em> element for a single parameter. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="parameter">The parameter.</param> /// <param name="parameterSetName">The specific parameter set name, or <see cref="ParameterAttribute.AllParameterSets"/>.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:parameter></em> element for the <paramref name="parameter"/>.</returns> private XElement GenerateParameterElement(ICommentReader commentReader, Parameter parameter, string parameterSetName, ReportWarning reportWarning) { var element = new XElement(commandNs + "parameter", new XAttribute("required", parameter.IsRequired(parameterSetName)), new XAttribute("globbing", parameter.SupportsGlobbing(parameterSetName)), new XAttribute("pipelineInput", parameter.GetIsPipelineAttribute(parameterSetName)), new XAttribute("position", parameter.GetPosition(parameterSetName)), new XElement(mamlNs + "name", parameter.Name), GenerateDescriptionElement(commentReader, parameter, reportWarning), commentReader.GetParameterValueElement(parameter, reportWarning), GenerateTypeElement(commentReader, parameter.ParameterType, true, reportWarning), commentReader.GetParameterDefaultValueElement(parameter), GetParameterEnumeratedValuesElement(parameter)); var aliasNames = parameter.Aliases.ToList(); if (aliasNames.Count > 0) { element.Add(new XAttribute("aliases", string.Join(",", aliasNames))); } return element; }
/// <summary> /// Generates a <em><command:command></em> element for the specified command. /// </summary> /// <param name="commentReader"></param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:command></em> element that represents the <paramref name="command"/>.</returns> private XElement GenerateCommandElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { return(new XElement(commandNs + "command", new XAttribute(XNamespace.Xmlns + "maml", mamlNs), new XAttribute(XNamespace.Xmlns + "command", commandNs), new XAttribute(XNamespace.Xmlns + "dev", devNs), GenerateDetailsElement(commentReader, command, reportWarning), GenerateDescriptionElement(commentReader, command, reportWarning), GenerateSyntaxElement(commentReader, command, reportWarning), GenerateParametersElement(commentReader, command, reportWarning), GenerateInputTypesElement(commentReader, command, reportWarning), GenerateReturnValuesElement(commentReader, command, reportWarning), GenerateAlertSetElement(commentReader, command, reportWarning), GenerateExamplesElement(commentReader, command, reportWarning), GenerateRelatedLinksElement(commentReader, command, reportWarning))); }
/// <summary> /// Generates the <em><command:inputTypes></em> element for a command. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:inputTypes></em> element for the <paramref name="command"/>.</returns> private XElement GenerateInputTypesElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { var inputTypesElement = new XElement(commandNs + "inputTypes"); var pipelineParameters = command.GetParameters(ParameterAttribute.AllParameterSets) .Where(p => p.IsPipeline(ParameterAttribute.AllParameterSets)); foreach (var parameter in pipelineParameters) { inputTypesElement.Add(GenerateInputTypeElement(commentReader, parameter, reportWarning)); } return inputTypesElement; }
/// <summary> /// Generates the <em><maml:relatedLinks></em> element for a command. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><maml:relatedLinks></em> element for the <paramref name="command"/>.</returns> private XElement GenerateRelatedLinksElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { return commentReader.GetCommandRelatedLinksElement(command, reportWarning); }
/// <summary> /// Generates the <em><command:returnValues></em> element for a command. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:returnValues></em> element for the <paramref name="command"/>.</returns> private XElement GenerateReturnValuesElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { var returnValueElement = new XElement(commandNs + "returnValues"); foreach (var type in command.OutputTypes) { returnValueElement.Add(GenerateComment("OutputType: " + type.Name)); var returnValueDescription = commentReader.GetOutputTypeDescriptionElement(command, type, reportWarning); returnValueElement.Add(new XElement(commandNs + "returnValue", GenerateTypeElement(commentReader, type, returnValueDescription == null, reportWarning), returnValueDescription)); } return returnValueElement; }
/// <summary> /// The default value of the parameter. This may be obtained by instantiating the cmdlet and accessing the parameter /// property or field to determine its initial value. /// </summary> public abstract object GetDefaultValue(ReportWarning reportWarning);
/// <summary> /// Generates the <em><command:examples></em> element for a command. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="command">The command.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><command:examples></em> element for the <paramref name="command"/>.</returns> private XElement GenerateExamplesElement(ICommentReader commentReader, Command command, ReportWarning reportWarning) { return commentReader.GetCommandExamplesElement(command, reportWarning); }
/// <summary> /// This is used to raise the <see cref="ReportWarning" /> event /// </summary> /// <param name="args">The event arguments</param> protected virtual void OnReportWarning(CommentsCacheEventArgs args) { ReportWarning?.Invoke(this, args); }
/// <summary> /// Generates a <em><dev:type></em> element for a type. /// </summary> /// <param name="commentReader">Provides access to the XML Doc comments.</param> /// <param name="type">The type for which a corresopnding <em><dev:type></em> element is required.</param> /// <param name="includeMamlDescription">Indicates whether or not a <em><maml:description></em> element should be /// included for the type. A description can be obtained from the type's XML Doc comment, but it is useful to suppress it if /// a more context-specific description is available where the <em><dev:type></em> element is actually used.</param> /// <param name="reportWarning">Function used to log warnings.</param> /// <returns>A <em><dev:type></em> element for the specified <paramref name="type"/>.</returns> private XElement GenerateTypeElement(ICommentReader commentReader, Type type, bool includeMamlDescription, ReportWarning reportWarning) { return new XElement(devNs + "type", new XElement(mamlNs + "name", type.FullName), new XElement(mamlNs + "uri"), includeMamlDescription ? commentReader.GetTypeDescriptionElement(type, reportWarning) : null); }
/// <summary> /// Creates a new instance that decorates the specified <paramref name="proxy"/>. /// </summary> /// <param name="proxy">The decorated proxy.</param> /// <param name="reportWarning">Used to report failed comment lookups.</param> public LoggingCommentReader(ICommentReader proxy, ReportWarning reportWarning) { _proxy = proxy ?? throw new ArgumentNullException(nameof(proxy)); _reportWarning = reportWarning ?? throw new ArgumentNullException(nameof(reportWarning)); }