public bool IsMetadataEqual(MamlParameter other) { return(StringComparer.OrdinalIgnoreCase.Equals(this.Name, other.Name) && this.Required == other.Required && StringComparer.OrdinalIgnoreCase.Equals(this.Position, other.Position) && StringComparer.OrdinalIgnoreCase.Equals(this.PipelineInput, other.PipelineInput) && this.Globbing == other.Globbing); }
public void RendererProduceSyntaxAndParameter() { MamlRenderer renderer = new MamlRenderer(); MamlCommand command = new MamlCommand() { Name = "Get-Foo", }; var param1 = new MamlParameter() { Type = "String", Name = "Param1", Position = "Named" }; var param2 = new MamlParameter() { Type = "System.Int32", Name = "Param2", Position = "Named" }; command.Parameters.Add(param1); command.Parameters.Add(param2); var syntax = new MamlSyntax(); syntax.Parameters.Add(param1); syntax.Parameters.Add(param2); command.Syntax.Add(syntax); string maml = renderer.MamlModelToString(new[] { command }); string[] syntaxItemName = EndToEndTests.GetXmlContent(maml, "/helpItems/command:command/command:syntax/command:syntaxItem/maml:name"); Assert.Equal(1, syntaxItemName.Length); Assert.Equal("Get-Foo", syntaxItemName[0]); string[] nameSyntax = EndToEndTests.GetXmlContent(maml, "/helpItems/command:command/command:syntax/command:syntaxItem/command:parameter/maml:name"); Assert.Equal(2, nameSyntax.Length); Assert.Equal("Param1", nameSyntax[0]); Assert.Equal("Param2", nameSyntax[1]); string[] nameParam = EndToEndTests.GetXmlContent(maml, "/helpItems/command:command/command:parameters/command:parameter/maml:name"); Assert.Equal(2, nameParam.Length); Assert.Equal("Param1", nameParam[0]); Assert.Equal("Param2", nameParam[1]); }
/// <summary> /// /// </summary> /// <param name="command"></param> /// <returns>true if Parameter was found</returns> private bool ParameterRule(MamlCommand command) { // grammar: // #### Name [TypeName] - mandatory // ```powershell - optional // [Parameter(...)] // ``` // Description - optional var node = GetNextNode(); var headingNode = GetHeadingWithExpectedLevel(node, PARAMETER_NAME_HEADING_LEVEL); if (headingNode == null) { return false; } var name = headingNode.Text.Split()[0]; MamlParameter parameter = new MamlParameter() { Name = name, Extent = headingNode.SourceExtent }; int equalIndex = headingNode.Text.IndexOf('='); string headingNodeText; if (equalIndex >= 0) { parameter.DefaultValue = headingNode.Text.Substring(equalIndex + 1).Trim(); // trim it for this case from PSReadLine: // #### WordDelimiters [Int32] = ;:,.[]{}()/\|^&*-=+ // We need to make sure that closing ] corresponds to [Int32], so it's the last ] before first = sign. headingNodeText = headingNode.Text.Substring(0, equalIndex); } else { headingNodeText = headingNode.Text; } int typeBeginIndex = headingNodeText.IndexOf('['); int typeEndIndex = headingNodeText.LastIndexOf(']'); if (typeBeginIndex >= 0 && typeEndIndex > 0) { parameter.Type = headingNodeText.Substring(typeBeginIndex + 1, typeEndIndex - typeBeginIndex - 1); } node = GetNextNode(); ParagraphNode descriptionNode = null; CodeBlockNode attributesNode = null; // it can be the end if (node != null) { switch (node.NodeType) { case MarkdownNodeType.Unknown: break; case MarkdownNodeType.Document: break; case MarkdownNodeType.Paragraph: descriptionNode = node as ParagraphNode; break; case MarkdownNodeType.Heading: // next parameter started UngetNode(node); break; case MarkdownNodeType.CodeBlock: attributesNode = node as CodeBlockNode; break; default: throw new ArgumentOutOfRangeException(); } if (descriptionNode == null) { descriptionNode = ParagraphNodeRule(); } } parameter.Description = GetTextFromParagraphNode(descriptionNode); parameter.AttributesText = attributesNode != null ? attributesNode.Text : string.Empty; if (parameter.AttributesText.Contains(@"[SupportsWildCards()]")) { parameter.Globbing = true; } command.Parameters.Add(parameter); return true; }
private static void FillUpParameterFromPSObject(MamlParameter parameter, PSObject parameterDetails) { // TODO: What about if null? // parameter.Type = (string)((PSObject)parameterDetails.Properties["type"].Value).Properties["name"].Value; parameter.Position = (string) parameterDetails.Properties["position"].Value; parameter.Required = ((string) parameterDetails.Properties["required"].Value).Equals("true"); string pipelineInput = (string) parameterDetails.Properties["pipelineInput"].Value; if (pipelineInput.StartsWith("t")) { // for some reason convention is: // false // True (ByValue) // True (ByPropertyName) pipelineInput = 'T' + pipelineInput.Substring(1); } parameter.PipelineInput = pipelineInput; // TODO: Still need to determine how to get these //parameter.VariableLength = ((string)parameterDetails.Properties["variableLength"].Value).Equals("true"); //parameter.ValueVariableLength = false; // it turns to work very well on all real-world examples, but in theory it can be orbitrary parameter.ValueRequired = parameter.Type == "switch" ? false : true; var parameterValueGroup = parameterDetails.Properties["parameterValueGroup"]; if (parameterValueGroup != null) { var validateSet = (parameterValueGroup.Value as PSObject).Properties["parameterValue"].Value as object[]; parameter.ParameterValueGroup.AddRange(validateSet.Select(x => x.ToString())); } // $h.Syntax.syntaxItem[0].parameter[0].parameterValueGroup.parameterValue // The 'aliases' property will contain either 'None' or a // comma-separated list of aliases. string aliasesString = ((string) parameterDetails.Properties["aliases"].Value); if (!string.Equals(aliasesString, "None")) { parameter.Aliases = aliasesString.Split( new string[] {", "}, StringSplitOptions.RemoveEmptyEntries); } }
private void GatherParameterDetails(MamlCommand command) { const string parameterFormatString = @" {0} ${1}"; const string docFunctionFormatString = @" function Get-AttributeDocFunction {{ param( {0} ) }} $h = Get-Help Get-AttributeDocFunction $h.parameters.parameter "; // Create the Runspace on demand if (this.runspace == null) { this.runspace = RunspaceFactory.CreateRunspace(); this.runspace.Open(); } using (PowerShell powerShell = PowerShell.Create()) { var parameterBlocks = command .Parameters .Select(p => string.Format(parameterFormatString, p.AttributesText, ShiftName(p.Name))); var functionScript = string.Format( docFunctionFormatString, string.Join(",\r\n", parameterBlocks)); // TODO: There could be some security concerns with executing arbitrary // text here, need to investigate safer ways to do it. JEA? powerShell.Runspace = this.runspace; powerShell.AddScript(functionScript); var parameterDetailses = powerShell.Invoke<PSObject>(); if (powerShell.Streams.Error.Any()) { throw new HelpSchemaException(command.Extent, "Errors when processing command " + command.Name + ":\n" + string.Join(";\n", powerShell.Streams.Error)); } foreach (PSObject parameterDetailsPsObject in parameterDetailses) { var parameter = command.Parameters.FirstOrDefault( p => string.Equals(p.Name, UndoShiftName((string)parameterDetailsPsObject.Properties["name"].Value))); FillUpParameterFromPSObject(parameter, parameterDetailsPsObject); } powerShell.Commands.Clear(); powerShell.Commands.AddScript("$h.Syntax.syntaxItem"); var syntaxDetailses = powerShell.Invoke<PSObject>(); if (powerShell.Streams.Error.Any()) { throw new HelpSchemaException(command.Extent, "Errors when processing command " + command.Name + ":\n" + string.Join(";\n", powerShell.Streams.Error)); } var sortedSyntaxItems = syntaxDetailses.ToList(); sortedSyntaxItems.Sort((si1, si2) => String.CompareOrdinal(GetParameterSetNameFromSyntaxItem(si1), GetParameterSetNameFromSyntaxItem(si2))); foreach (var syntaxDetails in sortedSyntaxItems) { MamlSyntax syntax = new MamlSyntax(); var syntaxParams = (object[])syntaxDetails.Properties["parameter"].Value; foreach (PSObject syntaxParamPsObject in syntaxParams.OfType<PSObject>()) { string paramName = UndoShiftName((string) syntaxParamPsObject.Properties["name"].Value); MamlParameter parametersParameter = command.Parameters.FirstOrDefault(p => string.Equals(p.Name, paramName)); if (parametersParameter == null) { throw new HelpSchemaException(command.Extent, "Cannot find corresponding parameter for syntax item " + paramName); } MamlParameter syntaxParameter = new MamlParameter() { Name = parametersParameter.Name, Type = parametersParameter.Type }; FillUpParameterFromPSObject(syntaxParameter, syntaxParamPsObject); syntax.Parameters.Add(syntaxParameter); } command.Syntax.Add(syntax); } } }
private void AddParameter(MamlCommand command, MamlParameter parameter, bool inSyntax) { var attributes = "required=\"" + parameter.Required.ToString().ToLower() + "\" " + "variableLength=\"" + parameter.VariableLength.ToString().ToLower() + "\" " + "globbing=\"" + parameter.Globbing.ToString().ToLower() + "\" " + "pipelineInput=\"" + parameter.PipelineInput + "\" " + "position=\"" + parameter.Position.ToLower() + "\" " + "aliases=\""; attributes += parameter.Aliases.Length > 0 ? string.Join(", ", parameter.Aliases) : "none"; attributes += "\""; PushTag("command:parameter", attributes); PushTag("maml:name"); _stringBuilder.Append(XmlEscape(parameter.Name)); PopTag("maml:name"); PushTag("maml:Description"); AddParas(parameter.Description); PopTag("maml:Description"); if (inSyntax && parameter.ParameterValueGroup.Count > 0) { AddParameterValueGroup(parameter.ParameterValueGroup); } attributes = "required=\"" + parameter.ValueRequired.ToString().ToLower() + "\" " + "variableLength=\"" + parameter.ValueVariableLength.ToString().ToLower(); attributes += "\""; string mamlType = ConvertPSTypeToMamlType(parameter.Type); // this is weired quirk inside <syntax>: // we don't add [switch] info to make it appear good. if (!inSyntax || mamlType != "SwitchParameter") { PushTag("command:parameterValue", attributes); _stringBuilder.Append(XmlEscape(mamlType)); PopTag("command:parameterValue"); } PushTag("dev:type"); PushTag("maml:name"); _stringBuilder.Append(XmlEscape(mamlType)); PopTag("maml:name"); _stringBuilder.Append("<maml:uri />"); PopTag("dev:type"); // Region defaultValue PushTag("dev:defaultValue"); if (mamlType == "SwitchParameter" && parameter.DefaultValue == null) { _stringBuilder.Append("False"); } else { if (parameter.DefaultValue != null) { _stringBuilder.Append(XmlEscape(parameter.DefaultValue)); } else { // sometimes default is none, but empty makes more sense. // _stringBuilder.Append("none"); } } PopTag("dev:defaultValue"); // closing tag PopTag("command:parameter"); }