using System.Text.RegularExpressions; using CTA.Rules.Models; using CTA.WebForms.Metrics; using CTA.WebForms.Services; namespace CTA.WebForms.Helpers.ControlHelpers { public static class EmbeddedCodeReplacers { public const string BoundAttrNameGroupName = "boundAttrName"; public const string EmbeddedExpressionRegexGroupName = "expr"; public const string AspExpressionTypeGroupName = "exprType"; public const string DirectiveNameRegexGroupName = "directiveName"; /// /// Regular expression to identify data binding syntax, matches start and end /// tags (<%# or <%#: and %>) with content that does not contain the end tag /// public static Regex DataBindRegex = new Regex(@"<%#:?\s*(?[^:](?:(?!%>).)*)\s*%>", RegexOptions.Singleline); /// /// Regular expression to identify raw expression syntax, matches start and end /// tags (<%= and %>) with content that does not contain the end tag /// public static Regex RawExprRegex = new Regex(@"<%=\s*(?(?:(?!%>).)*)\s*%>", RegexOptions.Singleline); /// /// Regular expression to identify html encoded expression syntax, matches start /// and end tags (<%: and %>) with content that does not contain the end tag /// public static Regex HTMLEncodedExprRegex = new Regex(@"<%:\s*(?(?:(?!%>).)*)\s*%>", RegexOptions.Singleline); /// /// Regular expression to identify directive syntax, matches start and end /// tags (<%@ and %>) with content that does not contain the end tag /// public static Regex DirectiveRegex = new Regex(@"<%@\s*(?(?:(?!%>).)*)\s*%>", RegexOptions.Singleline); /// /// Regular expression to identify asp expression syntax, matches start and end /// tags (<%$ and %>) with content that does not contain the end tag /// public static Regex AspExpRegex = new Regex(@"<%\$\s*(?[^*]+):\s*(?(?:(?!%>).)+)\s*%>", RegexOptions.Singleline); /// /// Regular expression to identify asp comment syntax, matches start and end tags /// (<%-- and --%>) with content that does not contain the end tag /// public static Regex AspCommentRegex = new Regex(@"<%--\s*(?(?:(?!--%>).)*)\s*--%>", RegexOptions.Singleline); /// /// Regular expression to identify code block syntax, matches start and end /// tags (<%# and %>) with content that does not contain the end tag and has /// extra conditions to ensure other embedding syntaxes aren't matched accidentally /// public static Regex EmbeddedCodeBlockRegex = new Regex(@"<%(?!(?:--)|[#=:@\$]).\s*(?(?:(?!%>).)*)\s*%>", RegexOptions.Singleline); /// /// Regular expression to identify directive name within directive syntax content, /// maps directive name attribute to the first string of consecutive non-space characters /// public static Regex DirectiveNameRegex = new Regex(@"(?[\S]+)"); public static string ReplaceOneWayDataBinds(string htmlString) { return DataBindRegex.Replace(htmlString, match => string.Format( Constants.RazorExplicitEmbeddingTemplate, match.Groups[EmbeddedExpressionRegexGroupName].Value.Trim())); } public static string ReplaceRawExprs(string htmlString) { return RawExprRegex.Replace(htmlString, match => string.Format( Constants.RazorExplicitRawEmbeddingTemplate, match.Groups[EmbeddedExpressionRegexGroupName].Value.Trim())); } public static string ReplaceHTMLEncodedExprs(string htmlString) { return HTMLEncodedExprRegex.Replace(htmlString, match => string.Format( Constants.RazorExplicitEmbeddingTemplate, match.Groups[EmbeddedExpressionRegexGroupName].Value.Trim())); } public static string ReplaceDirectives(string htmlString, string originalFilePath, string projectName, ViewImportService viewImportService, WebFormMetricContext metricContext) { return DirectiveRegex.Replace(htmlString, match => ConstructBlazorDirectives( match.Groups[EmbeddedExpressionRegexGroupName].Value, originalFilePath, projectName, viewImportService, metricContext)); } public static string ReplaceAspExprs(string htmlString) { return AspExpRegex.Replace(htmlString, match => { var exprType = match.Groups[AspExpressionTypeGroupName].Value; var expr = match.Groups[EmbeddedExpressionRegexGroupName].Value; return SupportedControls.AspExpressionRulesMap.ContainsKey(exprType) ? SupportedControls.AspExpressionRulesMap[exprType](expr.Trim()) : SupportedControls.DefaultAspExpressionConverter(exprType, expr.Trim()); }); } public static string ReplaceAspComments(string htmlString) { return AspCommentRegex.Replace(htmlString, match => string.Format( Constants.RazorServerSideCommentTemplate, match.Groups[EmbeddedExpressionRegexGroupName].Value.Trim())); } public static string ReplaceEmbeddedCodeBlocks(string htmlString) { // TODO: Insert @for, @if, etc. if embedded code contains a conditional // or loop statement. This is difficult to do because separation of the // statements from each other and the normal statements in the block may // cause issues especially considering that multiple embedded blocks can // contain different parts of the same loop or condition return EmbeddedCodeBlockRegex.Replace(htmlString, match => string.Format( Constants.RazorCodeBlockEmbeddingTemplate, match.Groups[EmbeddedExpressionRegexGroupName].Value.Trim())); } public static string ConstructBlazorDirectives(string content, string originalFilePath, string projectName, ViewImportService viewImportService, WebFormMetricContext metricContext) { var directiveName = DirectiveNameRegex.Match(content).Groups[DirectiveNameRegexGroupName].Value; var directiveConverter = SupportedControls.DirectiveRulesMap.ContainsKey(directiveName) ? SupportedControls.DirectiveRulesMap[directiveName] : SupportedControls.DefaultDirectiveConverter; metricContext.CollectActionMetrics(WebFormsActionType.DirectiveConversion, directiveName+ "DirectiveConverter"); return directiveConverter.ConvertDirective(directiveName, content.Trim(), originalFilePath, projectName, viewImportService); } } }