Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
MamlCommandHelpInfo.cs451 linesDownload Raw Back to help
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Globalization;5using System.Text;6using System.Xml;7 8namespace System.Management.Automation9{10    /// <summary>11    /// Class MamlCommandHelpInfo keeps track of help information to be returned by12    /// command help provider.13    /// </summary>14    internal class MamlCommandHelpInfo : BaseCommandHelpInfo15    {16        /// <summary>17        /// Constructor for custom HelpInfo object construction18        ///19        /// This is used by the CommandHelpProvider class to generate the20        /// default help UX when no help content is present.21        /// </summary>22        /// <param name="helpObject"></param>23        /// <param name="helpCategory"></param>24        internal MamlCommandHelpInfo(PSObject helpObject, HelpCategory helpCategory)25            : base(helpCategory)26        {27            _fullHelpObject = helpObject;28 29            this.ForwardHelpCategory = HelpCategory.Provider;30 31            this.AddCommonHelpProperties();32            // set user defined data33            if (helpObject.Properties["Component"] != null)34            {35                _component = helpObject.Properties["Component"].Value as string;36            }37 38            if (helpObject.Properties["Role"] != null)39            {40                _role = helpObject.Properties["Role"].Value as string;41            }42 43            if (helpObject.Properties["Functionality"] != null)44            {45                _functionality = helpObject.Properties["Functionality"].Value as string;46            }47        }48 49        /// <summary>50        /// Constructor for MamlCommandHelpInfo. This constructor will call the corresponding51        /// constructor in CommandHelpInfo so that xmlNode will be converted a mamlNode.52        /// </summary>53        /// <remarks>54        /// This constructor is intentionally made private so that the only way to create55        /// MamlCommandHelpInfo is through static function56        ///     Load(XmlNode node)57        /// where some sanity check is done.58        /// </remarks>59        private MamlCommandHelpInfo(XmlNode xmlNode, HelpCategory helpCategory) : base(helpCategory)60        {61            MamlNode mamlNode = new MamlNode(xmlNode);62            _fullHelpObject = mamlNode.PSObject;63 64            this.Errors = mamlNode.Errors;65 66            // The type name hierarchy for mshObject doesn't necessary67            // reflect the hierarchy in source code. From display's point of68            // view MamlCommandHelpInfo is derived from HelpInfo.69 70            _fullHelpObject.TypeNames.Clear();71            if (helpCategory == HelpCategory.DscResource)72            {73                _fullHelpObject.TypeNames.Add("DscResourceHelpInfo");74            }75            else76            {77                _fullHelpObject.TypeNames.Add("MamlCommandHelpInfo");78                _fullHelpObject.TypeNames.Add("HelpInfo");79            }80 81            this.ForwardHelpCategory = HelpCategory.Provider;82        }83 84        /// <summary>85        /// Override the FullHelp PSObject of this provider-specific HelpInfo with generic help.86        /// </summary>87        internal void OverrideProviderSpecificHelpWithGenericHelp(HelpInfo genericHelpInfo)88        {89            PSObject genericHelpMaml = genericHelpInfo.FullHelp;90            MamlUtil.OverrideName(_fullHelpObject, genericHelpMaml);91            MamlUtil.OverridePSTypeNames(_fullHelpObject, genericHelpMaml);92            MamlUtil.PrependSyntax(_fullHelpObject, genericHelpMaml);93            MamlUtil.PrependDetailedDescription(_fullHelpObject, genericHelpMaml);94            MamlUtil.OverrideParameters(_fullHelpObject, genericHelpMaml);95            MamlUtil.PrependNotes(_fullHelpObject, genericHelpMaml);96            MamlUtil.AddCommonProperties(_fullHelpObject, genericHelpMaml);97        }98 99        #region Basic Help Properties100 101        private readonly PSObject _fullHelpObject;102 103        /// <summary>104        /// Full help object for this help item.105        /// </summary>106        /// <value>Full help object for this help item.</value>107        internal override PSObject FullHelp108        {109            get110            {111                return _fullHelpObject;112            }113        }114 115        /// <summary>116        /// Examples string of this cmdlet help info.117        /// </summary>118        private string Examples119        {120            get121            {122                return ExtractTextForHelpProperty(this.FullHelp, "Examples");123            }124        }125 126        /// <summary>127        /// Parameters string of this cmdlet help info.128        /// </summary>129        private string Parameters130        {131            get132            {133                return ExtractTextForHelpProperty(this.FullHelp, "Parameters");134            }135        }136 137        /// <summary>138        /// Notes string of this cmdlet help info.139        /// </summary>140        private string Notes141        {142            get143            {144                return ExtractTextForHelpProperty(this.FullHelp, "alertset");145            }146        }147 148        #endregion149 150        #region Component, Role, Features151 152        // Component, Role, Functionality are required by exchange for filtering153        // help contents to be returned from help system.154        //155        // Following is how this is going to work,156        //    1. Each command will optionally include component, role and functionality157        //       information. This information is discovered from help content158        //       from xml tags <component>, <role>, <functionality> respectively159        //       as part of command metadata.160        //    2. From command line, end user can request help for commands for161        //       particular component, role and functionality using parameters like162        //       -component, -role, -functionality.163        //    3. At runtime, help engine will match against component/role/functionality164        //       criteria before returning help results.165        //166 167        private string _component = null;168        /// <summary>169        /// Component for this command.170        /// </summary>171        /// <value></value>172        internal override string Component173        {174            get175            {176                return _component;177            }178        }179 180        private string _role = null;181        /// <summary>182        /// Role for this command.183        /// </summary>184        /// <value></value>185        internal override string Role186        {187            get188            {189                return _role;190            }191        }192 193        private string _functionality = null;194        /// <summary>195        /// Functionality for this command.196        /// </summary>197        /// <value></value>198        internal override string Functionality199        {200            get201            {202                return _functionality;203            }204        }205 206        internal void SetAdditionalDataFromHelpComment(string component, string functionality, string role)207        {208            _component = component;209            _functionality = functionality;210            _role = role;211 212            // component,role,functionality is part of common help..213            // Update these properties as we have new data now..214            this.UpdateUserDefinedDataProperties();215        }216 217        /// <summary>218        /// Add user-defined command help data to command help.219        /// </summary>220        /// <param name="userDefinedData">User defined data object.</param>221        internal void AddUserDefinedData(UserDefinedHelpData userDefinedData)222        {223            if (userDefinedData == null)224                return;225 226            string propertyValue;227            if (userDefinedData.Properties.TryGetValue("component", out propertyValue))228            {229                _component = propertyValue;230            }231 232            if (userDefinedData.Properties.TryGetValue("role", out propertyValue))233            {234                _role = propertyValue;235            }236 237            if (userDefinedData.Properties.TryGetValue("functionality", out propertyValue))238            {239                _functionality = propertyValue;240            }241 242            // component,role,functionality is part of common help..243            // Update these properties as we have new data now..244            this.UpdateUserDefinedDataProperties();245        }246 247        #endregion248 249        #region Load250 251        /// <summary>252        /// Create a MamlCommandHelpInfo object from an XmlNode.253        /// </summary>254        /// <param name="xmlNode">XmlNode that contains help info.</param>255        /// <param name="helpCategory">Help category this maml object fits into.</param>256        /// <returns>MamlCommandHelpInfo object created.</returns>257        internal static MamlCommandHelpInfo Load(XmlNode xmlNode, HelpCategory helpCategory)258        {259            MamlCommandHelpInfo mamlCommandHelpInfo = new MamlCommandHelpInfo(xmlNode, helpCategory);260 261            if (string.IsNullOrEmpty(mamlCommandHelpInfo.Name))262                return null;263 264            mamlCommandHelpInfo.AddCommonHelpProperties();265 266            return mamlCommandHelpInfo;267        }268 269        #endregion270 271        #region Provider specific help272 273#if V2274        /// <summary>275        /// Merge the provider specific help with current command help.276        ///277        /// The cmdletHelp and dynamicParameterHelp is normally retrieved from ProviderHelpProvider.278        /// </summary>279        /// <remarks>280        /// A new MamlCommandHelpInfo is created to avoid polluting the provider help cache.281        /// </remarks>282        /// <param name="cmdletHelp">Provider-specific cmdletHelp to merge into current MamlCommandHelpInfo object.</param>283        /// <param name="dynamicParameterHelp">Provider-specific dynamic parameter help to merge into current MamlCommandHelpInfo object.</param>284        /// <returns>Merged command help info object.</returns>285        internal MamlCommandHelpInfo MergeProviderSpecificHelp(PSObject cmdletHelp, PSObject[] dynamicParameterHelp)286        {287            if (this._fullHelpObject == null)288                return null;289 290            MamlCommandHelpInfo result = (MamlCommandHelpInfo)this.MemberwiseClone();291 292            // We will need to use a deep clone of _fullHelpObject293            // to avoid _fullHelpObject being get terminated.294            result._fullHelpObject = this._fullHelpObject.Copy();295 296            if (cmdletHelp != null)297                result._fullHelpObject.Properties.Add(new PSNoteProperty("PS_Cmdlet", cmdletHelp));298 299            if (dynamicParameterHelp != null)300                result._fullHelpObject.Properties.Add(new PSNoteProperty("PS_DynamicParameters", dynamicParameterHelp));301 302            return result;303        }304#endif305 306        #endregion307 308        #region Helper Methods and Overloads309 310        /// <summary>311        /// Extracts text for a given property from the full help object.312        /// </summary>313        /// <param name="psObject">FullHelp object.</param>314        /// <param name="propertyName">315        /// Name of the property for which text needs to be extracted.316        /// </param>317        /// <returns></returns>318        private static string ExtractTextForHelpProperty(PSObject psObject, string propertyName)319        {320            if (psObject == null)321                return string.Empty;322 323            if (psObject.Properties[propertyName] == null ||324                psObject.Properties[propertyName].Value == null)325            {326                return string.Empty;327            }328 329            return ExtractText(PSObject.AsPSObject(psObject.Properties[propertyName].Value));330        }331 332        /// <summary>333        /// Given a PSObject, this method will traverse through the objects properties,334        /// extracts content from properties that are of type System.String, appends them335        /// together and returns.336        /// </summary>337        /// <param name="psObject"></param>338        /// <returns></returns>339        private static string ExtractText(PSObject psObject)340        {341            if (psObject == null)342            {343                return string.Empty;344            }345 346            // I think every cmdlet description should at least have 400 characters...347            // so starting with this assumption..I did an average of all the cmdlet348            // help content available at the time of writing this code and came up349            // with this number.350            StringBuilder result = new StringBuilder(400);351            foreach (PSPropertyInfo propertyInfo in psObject.Properties)352            {353                string typeNameOfValue = propertyInfo.TypeNameOfValue;354                switch (typeNameOfValue.ToLowerInvariant())355                {356                    case "system.boolean":357                    case "system.int32":358                    case "system.object":359                    case "system.object[]":360                        continue;361                    case "system.string":362                        result.Append((string)LanguagePrimitives.ConvertTo(propertyInfo.Value,363                            typeof(string), CultureInfo.InvariantCulture));364                        break;365                    case "system.management.automation.psobject[]":366                        PSObject[] items = (PSObject[])LanguagePrimitives.ConvertTo(367                                propertyInfo.Value,368                                typeof(PSObject[]),369                                CultureInfo.InvariantCulture);370                        foreach (PSObject item in items)371                        {372                            result.Append(ExtractText(item));373                        }374 375                        break;376                    case "system.management.automation.psobject":377                        result.Append(ExtractText(PSObject.AsPSObject(propertyInfo.Value)));378                        break;379                    default:380                        result.Append(ExtractText(PSObject.AsPSObject(propertyInfo.Value)));381                        break;382                }383            }384 385            return result.ToString();386        }387 388        /// <summary>389        /// Returns true if help content in help info matches the390        /// pattern contained in <paramref name="pattern"/>.391        /// The underlying code will usually run pattern.IsMatch() on392        /// content it wants to search.393        /// Cmdlet help info looks for pattern in Synopsis and394        /// DetailedDescription.395        /// </summary>396        /// <param name="pattern"></param>397        /// <returns></returns>398        internal override bool MatchPatternInContent(WildcardPattern pattern)399        {400            System.Management.Automation.Diagnostics.Assert(pattern != null, "pattern cannot be null");401 402            string synopsis = Synopsis;403            if ((!string.IsNullOrEmpty(synopsis)) && (pattern.IsMatch(synopsis)))404            {405                return true;406            }407 408            string detailedDescription = DetailedDescription;409            if ((!string.IsNullOrEmpty(detailedDescription)) && (pattern.IsMatch(detailedDescription)))410            {411                return true;412            }413 414            string examples = Examples;415            if ((!string.IsNullOrEmpty(examples)) && (pattern.IsMatch(examples)))416            {417                return true;418            }419 420            string notes = Notes;421            if ((!string.IsNullOrEmpty(notes)) && (pattern.IsMatch(notes)))422            {423                return true;424            }425 426            string parameters = Parameters;427            if ((!string.IsNullOrEmpty(parameters)) && (pattern.IsMatch(parameters)))428            {429                return true;430            }431 432            return false;433        }434 435        internal MamlCommandHelpInfo Copy()436        {437            MamlCommandHelpInfo result = new MamlCommandHelpInfo(_fullHelpObject.Copy(), this.HelpCategory);438            return result;439        }440 441        internal MamlCommandHelpInfo Copy(HelpCategory newCategoryToUse)442        {443            MamlCommandHelpInfo result = new MamlCommandHelpInfo(_fullHelpObject.Copy(), newCategoryToUse);444            result.FullHelp.Properties["Category"].Value = newCategoryToUse.ToString();445            return result;446        }447 448        #endregion449    }450}451