using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using CTA.WebForms.Helpers.ControlHelpers;
using CTA.WebForms.Services;
namespace CTA.WebForms.DirectiveConverters
{
public class DirectiveConverter
{
protected const string AttributeNameRegexGroupName = "AttributeName";
protected const string AttributeValueRegexGroupName = "AttributeValue";
protected const string AttributeMigrationNotSupportedTemplate = "";
protected const string DirectiveMigrationNotSupportedTemplate = "";
///
/// Each match of this regular expression represents an attribute of the Web Forms directive it is being
/// applied to, the first named capture group, AttributeName, is the name of the attribute while the second,
/// AttributeValue, is the value
///
protected static Regex AttributeSplitRegex { get { return new Regex(@"(?[^\s=]+)\s*=\s*(?[""'][^""']*[""'])"); } }
private protected virtual IEnumerable AttributeAllowList { get { return Enumerable.Empty(); } }
public string ConvertDirective(string directiveName, string directiveString, string originalFilePath, string projectName, ViewImportService viewImportService)
{
// TODO: We want to make sure that certain directives only occur once (i.e. layout,
// inherits, etc.) Need to find a better way to detect and deal with those or perhaps
// just leave it up the the developer given that detecting which layout or base class
// to choose is difficult
var migrationResults = GetMigratedAttributes(directiveString, directiveName, projectName);
// Want to ensure that the general directive conversion stays at the front if it exists
migrationResults = GetMigratedDirectives(directiveName, originalFilePath).Concat(migrationResults);
// Remove any using directive results and send them to the viewImports service
migrationResults = migrationResults.Where(migrationResult => {
if (migrationResult.MigrationResultType == DirectiveMigrationResultType.UsingDirective)
{
viewImportService.AddViewImport(migrationResult.Content);
return false;
}
return true;
});
return string.Join(Environment.NewLine, migrationResults.Select(migrationResult => migrationResult.Content));
}
// We want to allow this to be overridden in case some specialized functionality is required to
// perform the conversion, similar to the reasoning behind using Func<> in the attribute map
private protected virtual IEnumerable GetMigratedDirectives(string directiveName, string originalFilePath)
{
return new[] { new DirectiveMigrationResult(DirectiveMigrationResultType.Comment, string.Format(DirectiveMigrationNotSupportedTemplate, directiveName)) };
}
private protected virtual IEnumerable GetMigratedAttributes(string directiveString, string directiveName, string projectName)
{
return AttributeSplitRegex
.Matches(directiveString)
.SelectMany(match => {
var attrName = match.Groups[AttributeNameRegexGroupName].Value;
var attrValue = match.Groups[AttributeValueRegexGroupName].Value;
return AttributeAllowList.Contains(attrName, StringComparer.InvariantCultureIgnoreCase)
? UniversalDirectiveAttributeMap.AttributeMap[attrName](new[] {attrValue})
: new[] { new DirectiveMigrationResult(
DirectiveMigrationResultType.Comment,
string.Format(AttributeMigrationNotSupportedTemplate, attrName, attrValue, directiveName)) };
})
// Keep the order of results as Directives -> Comments -> New HTML nodes
.OrderBy(migrationResult => (int)migrationResult.MigrationResultType)
// Eliminate any duplicate statements
.Distinct();
}
}
}