private void AnalyzeToolDriver(ToolComponent toolComponent, string toolDriverPointer)
        {
            if (!string.IsNullOrEmpty(toolComponent.Name))
            {
                const int MaxWords  = 3;
                int       wordCount = toolComponent.Name.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Length;
                if (wordCount > MaxWords)
                {
                    string driverNamePointer = toolDriverPointer.AtProperty(SarifPropertyName.Name);

                    // {0}: The tool name '{1}' contains {2} words, which is more than the recommended
                    // maximum of {3} words. A short tool name is easy to remember and fits into a
                    // narrow column when displaying a list of results. If you need to provide more
                    // information about your tool, use the 'fullName' property.
                    LogResult(
                        driverNamePointer,
                        nameof(RuleResources.SARIF2005_ProvideToolProperties_Warning_ProvideConciseToolName_Text),
                        toolComponent.Name,
                        wordCount.ToString(),
                        MaxWords.ToString());
                }
            }

            if (string.IsNullOrWhiteSpace(toolComponent.Version) && string.IsNullOrWhiteSpace(toolComponent.SemanticVersion))
            {
                // {0}: The tool '{1}' provides neither a 'version' property nor a 'semanticVersion'
                // property. Providing a version enables the log file consumer to determine whether
                // the file was produced by an up to date version, and to avoid accidentally comparing
                // log files produced by different tool versions.
                LogResult(
                    toolDriverPointer,
                    nameof(RuleResources.SARIF2005_ProvideToolProperties_Warning_ProvideToolVersion_Text),
                    toolComponent.Name);
            }
            else
            {
                if (!string.IsNullOrWhiteSpace(toolComponent.Version))
                {
                    AnalyzeVersion(toolComponent.Name, toolComponent.Version, toolDriverPointer.AtProperty(SarifPropertyName.Version));
                }
            }
        }
        protected override void OnLoad(EventArgs e)
        {
            // startup init script
            WetControls.Extensions.ClientScript.InitScript(Page);

            // datepicker script
            if (IsDate)
            {
                WetControls.Extensions.ClientScript.InitDatePicker(this.Page);
            }
            // gouvernment email script
            if (IsGovernmentEmail)
            {
                WetControls.Extensions.ClientScript.InitFrmvldGovemail(this.Page, this.ErrorGovEmail);
            }
            // price script
            if (IsPrice)
            {
                WetControls.Extensions.ClientScript.InitFrmvldPrice(this.Page, this.ErrorPrice);
            }

            if (EnableClientValidation)
            {
                // attributes validation conflicts
                VerifyValidationConflicts();

                if (IsRequired)
                {
                    base.Attributes.Add("required", "required");
                }
                if (IsPhoneNumber)
                {
                    base.Attributes.Add("data-rule-phoneUS", "true");
                }
                if (IsPostalCode)
                {
                    base.Attributes.Add("size", "7");
                    base.Attributes.Add("data-rule-postalCodeCA", "true");
                }
                if (IsEmail)
                {
                    base.Attributes.Add("type", "email");
                }
                if (IsGovernmentEmail)
                {
                    base.Attributes.Add("data-rule-govemail", "true");
                }
                if (IsUrl)
                {
                    base.Attributes.Add("type", "url");
                }
                if (IsDate)
                {
                    base.Attributes.Add("type", "date");
                    base.Attributes.Add("data-rule-dateISO", "true");
                }
                if (IsTime)
                {
                    base.Attributes.Add("type", "time");
                }
                if (IsAlphanumeric)
                {
                    base.Attributes.Add("pattern", "[A-Za-z0-9_\\s]");
                    base.Attributes.Add("data-rule-alphanumeric", "true");
                }
                if (IsDigitsOnly)
                {
                    base.Attributes.Add("type", "number");
                    base.Attributes.Add("data-rule-digits", "true");
                }
                if (IsPrice)
                {
                    base.Attributes.Add("data-rule-price", "true");
                }
                if (IsLettersOnly)
                {
                    base.Attributes.Add("pattern", "[A-Za-z\\s]");
                    base.Attributes.Add("data-rule-lettersonly", "true");
                }
                if (IsLettersWithBasicPunc)
                {
                    base.Attributes.Add("pattern", "[A-Za-z-.,()'\"\\s]");
                    base.Attributes.Add("data-rule-letterswithbasicpunc", "true");
                }
                if (IsNoWhiteSpace)
                {
                    base.Attributes.Add("pattern", "[A-Za-z-.,()'\"\\s]");
                    base.Attributes.Add("data-rule-nowhitespace", "true");
                }
                if (IsNumber)
                {
                    base.Attributes.Add("type", "number");
                }
                if (MinNumber != 0 && MaxNumber != 0)
                {
                    base.Attributes.Add("data-rule-range", string.Format("[{0},{1}]", MinNumber, MaxNumber));
                }
                else if (MinNumber != 0)
                {
                    base.Attributes.Add("min", MinNumber.ToString());
                }
                else if (MaxNumber != 0)
                {
                    base.Attributes.Add("max", MaxNumber.ToString());
                }
                if (StepNumber != 0)
                {
                    base.Attributes.Add("step", StepNumber.ToString());
                }
                if (MinLength > 0 && MaxLength > 0)
                {
                    base.Attributes.Add("data-rule-rangelength", string.Format("[{0},{1}]", MinLength, MaxLength));
                }
                else if (MinLength > 0)
                {
                    base.Attributes.Add("data-rule-minlength", MinLength.ToString());
                }
                else if (MaxLength > 0)
                {
                    base.Attributes.Add("maxlength", MaxLength.ToString());
                }
                if (MinWords > 0 && MaxWords > 0)
                {
                    base.Attributes.Add("data-rule-rangeWords", string.Format("[{0},{1}]", MinWords, MaxWords));
                }
                else if (MinWords > 0)
                {
                    base.Attributes.Add("data-rule-minWords", MinWords.ToString());
                }
                else if (MaxWords > 0)
                {
                    base.Attributes.Add("data-rule-maxWords", MaxWords.ToString());
                }
                if (!string.IsNullOrEmpty(EqualTo))
                {
                    Control ctrl = Page.FindControlRecursive(EqualTo.TrimStart('#')); // prevent tag at beginning
                    base.Attributes.Add("data-rule-equalTo", (ctrl == null ? "#" + EqualTo : "#" + ctrl.ClientID));
                }
                if (!string.IsNullOrEmpty(ValidationErrorMsg))
                {
                    base.Attributes.Add("data-msg", ValidationErrorMsg);
                }
            }
            if (!string.IsNullOrEmpty(Placeholder))
            {
                base.Attributes.Add("placeholder", Placeholder);
            }

            base.OnLoad(e);
        }
        private void AnalyzeToolDriver(ToolComponent toolComponent, string toolDriverPointer)
        {
            if (!string.IsNullOrEmpty(toolComponent.Name))
            {
                const int MaxWords  = 3;
                int       wordCount = toolComponent.Name.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Length;
                if (wordCount > MaxWords)
                {
                    string driverNamePointer = toolDriverPointer.AtProperty(SarifPropertyName.Name);

                    // {0}: The tool name '{1}' contains {2} words, which is more than the recommended
                    // maximum of {3} words. A short tool name is easy to remember and fits into a
                    // narrow column when displaying a list of results. If you need to provide more
                    // information about your tool, use the 'fullName' property.
                    LogResult(
                        driverNamePointer,
                        nameof(RuleResources.SARIF2005_ProvideToolProperties_Warning_ProvideConciseToolName_Text),
                        toolComponent.Name,
                        wordCount.ToString(),
                        MaxWords.ToString());
                }
            }

            bool informationUriRequired = this.Context.Policy.GetProperty(InformationUriRequired);

            if (informationUriRequired && toolComponent.InformationUri == null)
            {
                // {0}: The tool '{1}' does not provide 'informationUri'. This property helps the
                // developer responsible for addessing a result by providing a way to learn more
                // about the tool.
                LogResult(
                    toolDriverPointer,
                    nameof(RuleResources.SARIF2005_ProvideToolProperties_Warning_ProvideToolnformationUri_Text),
                    toolComponent.Name);
            }

            StringSet acceptableVersionProperties = this.Context.Policy.GetProperty(AcceptableVersionProperties);
            bool      toolDriverProvidesVersion   = false;

            toolDriverProvidesVersion |= acceptableVersionProperties.Contains(nameof(toolComponent.Version)) && !string.IsNullOrWhiteSpace(toolComponent.Version);
            toolDriverProvidesVersion |= acceptableVersionProperties.Contains(nameof(toolComponent.SemanticVersion)) && !string.IsNullOrWhiteSpace(toolComponent.SemanticVersion);
            toolDriverProvidesVersion |= acceptableVersionProperties.Contains(nameof(toolComponent.DottedQuadFileVersion)) && !string.IsNullOrWhiteSpace(toolComponent.DottedQuadFileVersion);

            if (!toolDriverProvidesVersion)
            {
                // {0}: The tool '{1}' does not provide any of the version-related properties {2}.
                // Providing version information enables the log file consumer to determine whether
                // the file was produced by an up to date version, and to avoid accidentally
                // comparing log files produced by different tool versions.
                LogResult(
                    toolDriverPointer,
                    nameof(RuleResources.SARIF2005_ProvideToolProperties_Warning_ProvideToolVersion_Text),
                    toolComponent.Name,
                    $"'{string.Join("', '", acceptableVersionProperties.Select(ToCamelCase))}'");
            }
            else
            {
                if (!string.IsNullOrWhiteSpace(toolComponent.Version))
                {
                    AnalyzeVersion(toolComponent.Name, toolComponent.Version, toolDriverPointer.AtProperty(SarifPropertyName.Version));
                }
            }
        }