/Web/T4MVC.tt
Unknown | 2473 lines | 2129 code | 344 blank | 0 comment | 0 complexity | 04e577062b8954c3c566f7e74749498f MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- <#
- /*
- T4MVC Version 3.8.2
- Find latest version and documentation at http://mvccontrib.codeplex.com/wikipage?title=T4MVC
- Discuss on StackOverflow or on Codeplex (https://t4mvc.codeplex.com/discussions)
-
- T4MVC is part of the MvcContrib project, but in a different Codeplex location (http://t4mvc.codeplex.com)
- Maintained by David Ebbo, with much feedback from the MVC community (thanks all!)
- david.ebbo@microsoft.com
- http://twitter.com/davidebbo
- http://blog.davidebbo.com/ (previously: http://blogs.msdn.com/davidebb)
-
- Related blog posts: http://blogs.msdn.com/davidebb/archive/tags/T4MVC/default.aspx
-
- Please use in accordance to the MvcContrib license (http://mvccontrib.codeplex.com/license)
- */
- #>
- <#@ template language="C#" debug="true" hostspecific="true" #>
- <#@ assembly name="System.Core" #>
- <#@ assembly name="Microsoft.VisualStudio.Shell.Interop" #>
- <#@ assembly name="EnvDTE" #>
- <#@ assembly name="EnvDTE80" #>
- <#@ assembly name="VSLangProj" #>
- <#@ assembly name="System.Xml" #>
- <#@ assembly name="System.Xml.Linq" #>
- <#@ import namespace="System.Collections.Generic" #>
- <#@ import namespace="System.IO" #>
- <#@ import namespace="System.Linq" #>
- <#@ import namespace="System.Text" #>
- <#@ import namespace="System.Text.RegularExpressions" #>
- <#@ import namespace="Microsoft.VisualStudio.Shell.Interop" #>
- <#@ import namespace="EnvDTE" #>
- <#@ import namespace="EnvDTE80" #>
- <#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
- <# // To debug, uncomment the next two lines !!
- // System.Diagnostics.Debugger.Launch();
- // System.Diagnostics.Debugger.Break();
- #>
- <#settings=MvcSettings.Load(Host);#>
- <#PrepareDataToRender(this); #>
- <#var manager = Manager.Create(Host, GenerationEnvironment); #>
- <#manager.StartHeader(); #>// <auto-generated />
- // This file was generated by a T4 template.
- // Don't change it directly as your change would get overwritten. Instead, make changes
- // to the .tt file (i.e. the T4 template) and save it to regenerate this file.
-
- // Make sure the compiler doesn't complain about missing Xml comments
- #pragma warning disable 1591
- #region T4MVC
-
- using System;
- using System.Diagnostics;
- using System.CodeDom.Compiler;
- using System.Collections.Generic;
- using System.Linq;
- using System.Runtime.CompilerServices;
- using System.Threading.Tasks;
- using System.Web;
- using System.Web.Hosting;
- using System.Web.Mvc;
- using System.Web.Mvc.Ajax;
- using System.Web.Mvc.Html;
- using System.Web.Routing;
- using <#=settings.T4MVCNamespace #>;
- <#foreach (var referencedNamespace in settings.ReferencedNamespaces) { #>
- using <#=referencedNamespace #>;
- <#} #>
- <#manager.EndBlock(); #>
-
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public static partial class <#=settings.HelpersPrefix #>
- {
- <#if (settings.IncludeAreasToken) { #>
- public static class Areas
- {
- <#} #>
- <#foreach (var area in Areas.Where(a => !string.IsNullOrEmpty(a.Name))) { #>
- static readonly <#=area.Name #>Class s_<#=area.Name #> = new <#=area.Name #>Class();
- public static <#=area.Name #>Class <#=EscapeID(area.Namespace) #> { get { return s_<#=area.Name #>; } }
- <#} #>
- <#if (settings.IncludeAreasToken) { #>
- }
- <#} #>
- <#foreach (var controller in DefaultArea.GetControllers()) { #>
- public static <#=controller.FullClassName #> <#=controller.Name #> = new <#=controller.FullDerivedClassName #>();
- <#} #>
- }
-
- namespace <#=settings.T4MVCNamespace #>
- {
- <#foreach (var area in Areas.Where(a => !string.IsNullOrEmpty(a.Name))) { #>
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public class <#=area.Name #>Class
- {
- public readonly string Name = "<#=ProcessAreaOrControllerName(area.Name) #>";
- <#foreach (var controller in area.GetControllers()) { #>
- public <#=controller.FullClassName #> <#=controller.Name #> = new <#=controller.FullDerivedClassName #>();
- <#} #>
- }
- <#} #>
- }
-
- namespace <#=settings.T4MVCNamespace #>
- {
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public class Dummy
- {
- private Dummy() { }
- public static Dummy Instance = new Dummy();
- }
- }
-
- <#foreach (var resultType in ResultTypes.Values) { #>
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- internal partial class T4MVC_<#=resultType.UniqueName #> : <#=resultType.FullName #>, IT4MVCActionResult
- {
- public T4MVC_<#=resultType.UniqueName #>(string area, string controller, string action, string protocol = null): base(<#resultType.Constructor.WriteNonEmptyParameterValues(true); #>)
- {
- this.InitMVCT4Result(area, controller, action, protocol);
- }
- <#foreach (var method in resultType.AbstractMethods) { #>
- <#=method.IsPublic ? "public" : "protected" #> override <#=method.ReturnType#> <#=method.Name #>(<#method.WriteFormalParameters(true); #>) {<# if(method.ReturnType != "void") {#> return default(<#=method.ReturnType#>); <#} #> }
- <#} #>
-
- public string Controller { get; set; }
- public string Action { get; set; }
- public string Protocol { get; set; }
- public RouteValueDictionary RouteValueDictionary { get; set; }
- }
- <#} #>
-
-
-
- namespace <#=settings.LinksNamespace #>
- {
- <#
- foreach (string folder in settings.StaticFilesFolders.Concat(GetStaticFilesViewFolders())) {
- ProcessStaticFiles(Project, folder);
- }
- #>
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public static partial class Bundles
- {
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public static partial class Scripts {}
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public static partial class Styles {}
- }
- }
-
- <#
- RenderAdditionalCode();
- #>
- <#foreach (var controller in GetAbstractControllers().Where(c => !c.HasDefaultConstructor)) { #>
- <#manager.StartNewFile(controller.GeneratedFileName); #>
- namespace <#=controller.Namespace #>
- {
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public partial class <#=controller.ClassName #>
- {
- protected <#=controller.ClassName #>() { }
- }
- }
- <#manager.EndBlock(); #>
- <#} #>
-
- <#foreach (var controller in GetControllers()) { #>
- <#
- // Don't generate the file at all if the existing one is up to date
- // NOTE: disable this optimization since it doesn't catch view changes! It can be re-enabled later if smarter change detection is added
- //if (controller.GeneratedCodeIsUpToDate) {
- // manager.KeepGeneratedFile(controller.GeneratedFileName);
- // continue;
- //}
- #>
- <#manager.StartNewFile(controller.GeneratedFileName); #>
- <#if (!String.IsNullOrEmpty(controller.Namespace)) { #>
- namespace <#=controller.Namespace #>
- {
- <#} #>
- public <#if (!controller.NotRealController) { #>partial <#} #>class <#=controller.ClassName #>
- {
- <#if (!controller.NotRealController) { #>
- <#if (!controller.HasExplicitConstructor) { #>
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public <#=controller.ClassName #>() { }
-
- <#} #>
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- protected <#=controller.ClassName #>(Dummy d) { }
-
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- protected RedirectToRouteResult RedirectToAction(ActionResult result)
- {
- var callInfo = result.GetT4MVCResult();
- return RedirectToRoute(callInfo.RouteValueDictionary);
- }
-
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- protected RedirectToRouteResult RedirectToAction(Task<ActionResult> taskResult)
- {
- return RedirectToAction(taskResult.Result);
- }
-
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- protected RedirectToRouteResult RedirectToActionPermanent(ActionResult result)
- {
- var callInfo = result.GetT4MVCResult();
- return RedirectToRoutePermanent(callInfo.RouteValueDictionary);
- }
-
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- protected RedirectToRouteResult RedirectToActionPermanent(Task<ActionResult> taskResult)
- {
- return RedirectToActionPermanent(taskResult.Result);
- }
-
- <#foreach (var method in controller.ActionMethodsUniqueWithoutParameterlessOverload) { #>
- [NonAction]
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public virtual <#=method.ReturnTypeFullName #> <#=method.Name #>()
- {
- <#if (method.ReturnTypeFullName == "System.Threading.Tasks.Task<System.Web.Mvc.ActionResult>") { #>
- var callInfo = new T4MVC_<#=method.ReturnTypeUniqueName #>(Area, Name, ActionNames.<#=method.ActionName #><# if (method.ActionUrlHttps) {#>, "https"<#}#>);
- return System.Threading.Tasks.Task.FromResult(callInfo as ActionResult);
- <#} else { #>
- return new T4MVC_<#=method.ReturnTypeUniqueName #>(Area, Name, ActionNames.<#=method.ActionName #><# if (method.ActionUrlHttps) {#>, "https"<#}#>);
- <#} #>
- }
- <#} #>
- <#foreach (var method in controller.CustomActionMethodsUniqueWithoutParameterlessOverload) { #>
- [NonAction]
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public virtual <#=method.ReturnTypeFullName #> <#=method.ActionName #>()
- {
- return new T4MVC_<#=method.ReturnTypeUniqueName #>(Area, Name, ActionNames.<#=method.ActionName #><# if (method.ActionUrlHttps) {#>, "https"<#}#>);
- }
- <#} #>
- <#foreach (var method in controller.CustomActionMethods) { #>
- [NonAction]
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public virtual <#=method.ReturnTypeFullName #> <#=method.ActionName #>(<#method.WriteFormalParameters(true, true); #>)
- {
- var callInfo = new T4MVC_<#=method.ReturnTypeUniqueName #>(Area, Name, ActionNames.<#=method.ActionName #><# if (method.ActionUrlHttps) {#>, "https"<#}#>);
- <#if (method.Parameters.Count > 0) { #>
- <#foreach (var p in method.Parameters) { #>
- ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, <#=p.RouteNameExpression #>, <#=p.Name #>);
- <#} #>
- <#}#>
- <#if (method.ReturnTypeFullName == "System.Threading.Tasks.Task<System.Web.Mvc.ActionResult>") { #>
- return System.Threading.Tasks.Task.FromResult(callInfo as ActionResult);
- <#} else { #>
- return callInfo;
- <#} #>
- }
- <#} #>
-
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public <#=controller.ClassName #> Actions { get { return <#=controller.T4MVCControllerFullName #>; } }
- [<#= GeneratedCode #>]
- public readonly string Area = "<#=ProcessAreaOrControllerName(controller.AreaName) #>";
- [<#= GeneratedCode #>]
- public readonly string Name = "<#=ProcessAreaOrControllerName(controller.Name) #>";
- [<#= GeneratedCode #>]
- public const string NameConst = "<#=ProcessAreaOrControllerName(controller.Name) #>";
-
- static readonly ActionNamesClass s_actions = new ActionNamesClass();
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public ActionNamesClass ActionNames { get { return s_actions; } }
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public class ActionNamesClass
- {
- <#foreach (var method in controller.ActionMethodsWithUniqueNames) { #>
- <# if (settings.UseLowercaseRoutes) { #>
- public readonly string <#=method.ActionName #> = (<#=method.ActionNameValueExpression #>).ToLowerInvariant();
- <# } else { #>
- public readonly string <#=method.ActionName #> = <#=method.ActionNameValueExpression #>;
- <# }
- } #>
- }
-
- <#
- // Issue: we can't honor UseLowercaseRoutes here because ToLowerInvariant() is not valid in constants!
- if (!settings.UseLowercaseRoutes) { #>
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public class ActionNameConstants
- {
- <#foreach (var method in controller.ActionMethodsWithUniqueNames) { #>
- public const string <#=method.ActionName #> = <#=method.ActionNameValueExpression #>;
- <#
- } #>
- }
-
- <#}
- } #>
-
- <#if (settings.GenerateParamsForActionMethods && !settings.GenerateParamsAsConstantsForActionMethods){
- foreach (var group in controller.UniqueParameterNamesGroupedByActionName) if (group.Any()) { #>
- static readonly ActionParamsClass_<#=group.Key #> s_params_<#=group.Key #> = new ActionParamsClass_<#=group.Key #>();
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public ActionParamsClass_<#=group.Key #> <#=group.Key + settings.ParamsPropertySuffix #> { get { return s_params_<#=group.Key #>; } }
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public class ActionParamsClass_<#=group.Key #>
- {
- <#foreach (var param in group) { #>
- <# if (settings.UseLowercaseRoutes) { #>
- public readonly string <#=param.Name #> = (<#=param.RouteNameExpression #>).ToLowerInvariant();
- <# } else { #>
- public readonly string <#=param.Name #> = <#=param.RouteNameExpression #>;
- <# }
- } #>
- }
- <# } #>
- <#} #>
- <#if (settings.GenerateParamsAsConstantsForActionMethods){
-
- foreach (var group in controller.UniqueParameterNamesGroupedByActionName) if (group.Any()) { #>
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public class <#=group.Key + settings.ParamsPropertySuffix#>
- {
- <#foreach (var param in group) { #>
- <# if (settings.UseLowercaseRoutes) { #>
- public const string <#=param.Name #> = (<#=param.RouteNameExpression #>).ToLowerInvariant();
- <# } else { #>
- public const string <#=param.Name #> = <#=param.RouteNameExpression #>;
- <# }
- } #>
- }
- <# } #>
- <#} #>
- static readonly ViewsClass s_views = new ViewsClass();
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public ViewsClass Views { get { return s_views; } }
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public class ViewsClass
- {
- <#RenderControllerViews(controller);#>
- }
- }
-
- <#if (!controller.NotRealController) { #>
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public partial class <#=controller.DerivedClassName #> : <#=controller.FullClassName #>
- {
- public <#=controller.DerivedClassName #>() : base(Dummy.Instance) { }
-
- <#foreach (var method in controller.ActionMethods.Where(m => !m.IsCustomReturnType)) { #>
- [NonAction]
- partial void <#=method.Name #>Override(T4MVC_<#=method.ReturnTypeUniqueName #> callInfo<#if (method.Parameters.Count > 0) { #>, <#method.WriteFormalParameters(true); #><#}#>);
-
- [NonAction]
- public override <#=method.ReturnTypeFullName #> <#=method.Name #>(<#method.WriteFormalParameters(true); #>)
- {
- var callInfo = new T4MVC_<#=method.ReturnTypeUniqueName #>(Area, Name, ActionNames.<#=method.ActionName #><# if (method.ActionUrlHttps) {#>, "https"<#}#>);
- <#if (method.Parameters.Count > 0) { #>
- <#foreach (var p in method.Parameters) { #>
- ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, <#=p.RouteNameExpression #>, <#=p.Name #>);
- <#} #>
- <#}#>
- <#=method.Name #>Override(callInfo<#if (method.Parameters.Count > 0) { #><#foreach (var p in method.Parameters) { #>, <#=p.Name #><#}}#>);
- <#if (method.ReturnTypeFullName == "System.Threading.Tasks.Task<System.Web.Mvc.ActionResult>") { #>
- return System.Threading.Tasks.Task.FromResult(callInfo as ActionResult);
- <#} else { #>
- return callInfo;
- <#} #>
- }
-
- <#} #>
- }
- <#} #>
- <#if (!String.IsNullOrEmpty(controller.Namespace)) { #>
- }
- <#} #>
-
- <#manager.EndBlock(); #>
- <#} #>
-
-
- <# if (settings.ExplicitHtmlHelpersForPartials) {
- manager.StartNewFile("T4MVC.ExplicitExtensions.cs"); #>
-
- namespace System.Web.Mvc {
- [<#= GeneratedCode #>]
- public static class HtmlHelpersForExplicitPartials
- {
- <#
- foreach(var partialView in GetPartials()) {
- string partialName = partialView.Key;
- string partialPath = partialView.Value;
- string partialRenderMethod = string.Format(settings.ExplicitHtmlHelpersForPartialsFormat, partialName);
- #>
- ///<summary>
- ///Render the <b><#= partialName #></b> partial.
- ///</summary>
- public static void <#= partialRenderMethod #>(this HtmlHelper html) {
- html.RenderPartial("<#= partialPath #>");
- }
-
- ///<summary>
- ///Render the <b><#= partialName #></b> partial.
- ///</summary>
- public static void <#= partialRenderMethod #>(this HtmlHelper html, object model) {
- html.RenderPartial("<#= partialPath #>", model);
- }
- <# } #>
- }
- }
- <# manager.EndBlock(); #>
- <# } #>
-
- <#manager.StartFooter(); #>
- #endregion T4MVC
- #pragma warning restore 1591
- <#manager.EndBlock(); #>
- <#settings.SaveChanges(manager); #>
- <#manager.Process(settings.SplitIntoMultipleFiles); #>
-
- <#@ Include File="T4MVC.tt.hooks.t4" #>
-
- <#+
- static MvcSettings settings;
- const string ControllerSuffix = "Controller";
-
- static DTE Dte;
- static Project Project;
- static string AppRoot;
- static HashSet<AreaInfo> Areas;
- static AreaInfo DefaultArea;
- static Dictionary<string, ResultTypeInfo> ResultTypes;
- static TextTransformation TT;
- static string T4FileName;
- static string T4Folder;
- static string GeneratedCode = @"GeneratedCode(""T4MVC"", ""2.0"")";
- static Microsoft.CSharp.CSharpCodeProvider codeProvider = new Microsoft.CSharp.CSharpCodeProvider();
- List<string> virtualPathesForStaticFiles = new List<string>();
-
- IEnumerable<ControllerInfo> GetControllers()
- {
- var controllers = new List<ControllerInfo>();
-
- foreach (var area in Areas)
- {
- controllers.AddRange(area.GetControllers());
- }
-
- return controllers;
- }
-
- IEnumerable<ControllerInfo> GetAbstractControllers()
- {
- var controllers = new List<ControllerInfo>();
-
- foreach (var area in Areas)
- {
- controllers.AddRange(area.GetAbstractControllers());
- }
-
- return controllers;
- }
-
- IDictionary<string, string> GetPartials()
- {
- var parts = GetControllers()
- .Select(m => m.ViewsFolder)
- .SelectMany(m => m.Views)
- .Where(m => IsPartialView(m.Value));
-
- var partsDic = new Dictionary<string, KeyValuePair<string, string>>();
-
- foreach(var part in parts)
- {
- string viewName = Sanitize(part.Key);
-
- // Check if we already have a partial view by that name (e.g. if two Views folders have the same ascx)
- int keyCollisionCount = partsDic.Where(m => m.Key == viewName || m.Value.Key == viewName).Count();
-
- if (keyCollisionCount > 0)
- {
- // Append a numbered suffix to avoid the conflict
- partsDic.Add(viewName + keyCollisionCount.ToString(), part);
- }
- else
- {
- partsDic.Add(viewName, part);
- }
- }
-
- return partsDic.ToDictionary(k => k.Key, v => v.Value.Value);
- }
-
- bool IsPartialView(string viewFilePath)
- {
- string viewFileName = Path.GetFileName(viewFilePath);
-
- if (viewFileName.EndsWith(".ascx")) return true;
-
- if ((viewFileName.EndsWith(".cshtml") || viewFileName.EndsWith(".vbhtml")) && viewFileName.StartsWith("_"))
- {
- return true;
- }
-
- return false;
- }
-
- void PrepareDataToRender(TextTransformation tt)
- {
- TT = tt;
- T4FileName = Path.GetFileName(Host.TemplateFile);
- T4Folder = Path.GetDirectoryName(Host.TemplateFile);
- Areas = new HashSet<AreaInfo>();
- ResultTypes = new Dictionary<string, ResultTypeInfo>();
-
- // Get the DTE service from the host
- var serviceProvider = Host as IServiceProvider;
- if (serviceProvider != null)
- {
- Dte = (EnvDTE.DTE)serviceProvider.GetService(typeof(EnvDTE.DTE));
- }
-
- // Fail if we couldn't get the DTE. This can happen when trying to run in TextTransform.exe
- if (Dte == null)
- {
- throw new Exception("T4MVC can only execute through the Visual Studio host");
- }
-
- Project = GetProjectContainingT4File(Dte);
-
- if (Project == null)
- {
- Error("Could not find the VS Project containing the T4 file.");
- return;
- }
-
- // Get the path of the root folder of the app
- AppRoot = Path.GetDirectoryName(Project.FullName) + '\\';
-
- ProcessAreas(Project);
- }
-
- Project GetProjectContainingT4File(DTE dte)
- {
-
- // Find the .tt file's ProjectItem
- ProjectItem projectItem = dte.Solution.FindProjectItem(Host.TemplateFile);
-
- // If the .tt file is not opened, open it
- if (projectItem.Document == null)
- projectItem.Open(EnvDTE.Constants.vsViewKindCode);
-
- return projectItem.ContainingProject;
- }
-
- void ProcessAreas(Project project)
- {
- // Process the default area
- ProcessArea(project.ProjectItems, null);
-
- // Get the Areas folder
- ProjectItem areaProjectItem = GetProjectItem(project, settings.AreasFolder);
-
- // Process areas folder
- if (areaProjectItem != null)
- {
- foreach (ProjectItem item in areaProjectItem.ProjectItems)
- {
- if (IsFolder(item))
- {
- ProcessArea(item.ProjectItems, item.Name);
- }
- }
- }
-
- // Process portable areas
- foreach (string portableArea in settings.PortableAreas)
- {
- ProjectItem portableAreaProjectItem = GetProjectItem(project, portableArea);
-
- if (portableAreaProjectItem == null)
- return;
-
- if (IsFolder(portableAreaProjectItem))
- {
- ProcessArea(portableAreaProjectItem.ProjectItems, portableAreaProjectItem.Name);
- }
- }
- }
-
- void ProcessArea(ProjectItems areaFolderItems, string name)
- {
- var area = new AreaInfo() { Name = name };
- ProcessAreaControllers(areaFolderItems, area);
- ProcessAreaViews(areaFolderItems, area);
- Areas.Add(area);
-
- if (String.IsNullOrEmpty(name))
- DefaultArea = area;
- }
-
- void ProcessAreaControllers(ProjectItems areaFolderItems, AreaInfo area)
- {
- // Get area Controllers folder
- ProjectItem controllerProjectItem = GetProjectItem(areaFolderItems, settings.ControllersFolder);
- if (controllerProjectItem == null)
- return;
-
- ProcessControllersRecursive(controllerProjectItem, area);
- }
-
- void ProcessAreaViews(ProjectItems areaFolderItems, AreaInfo area)
- {
- // Get area Views folder
- ProjectItem viewsProjectItem = GetProjectItem(areaFolderItems, settings.ViewsRootFolder);
- if (viewsProjectItem == null)
- return;
-
- ProcessAllViews(viewsProjectItem, area);
- }
-
- void ProcessControllersRecursive(ProjectItem projectItem, AreaInfo area)
- {
-
- // Recurse into all the sub-items (both files and folder can have some - e.g. .tt files)
- foreach (ProjectItem item in projectItem.ProjectItems)
- {
- ProcessControllersRecursive(item, area);
- }
-
- if (projectItem.FileCodeModel != null)
- {
- DateTime controllerLastWriteTime = File.GetLastWriteTime(projectItem.get_FileNames(0));
- foreach (var type in projectItem.FileCodeModel.CodeElements.OfType<CodeClass2>())
- {
- ProcessControllerType(type, area, controllerLastWriteTime);
- }
- // Process all the elements that are namespaces
- foreach (var ns in projectItem.FileCodeModel.CodeElements.OfType<CodeNamespace>())
- {
- foreach (var type in ns.Members.OfType<CodeClass2>())
- {
- ProcessControllerType(type, area, controllerLastWriteTime);
- }
- }
- }
- }
-
- void ProcessControllerType(CodeClass2 type, AreaInfo area, DateTime controllerLastWriteTime)
- {
- // Only process controllers
- if (!IsController(type))
- return;
-
- // Don't process generic classes (their concrete derived classes will be processed)
- if (type.IsGeneric)
- return;
-
- //Ignore references to controllers we create
- if(area.Controllers.Any(c => c.DerivedClassName == type.Name))
- return;
-
- // Make sure the class is partial
- if (type.ClassKind != vsCMClassKind.vsCMClassKindPartialClass)
- {
- try
- {
- type.ClassKind = vsCMClassKind.vsCMClassKindPartialClass;
- }
- catch
- {
- // If we couldn't make it partial, give a warning and skip it
- Warning(String.Format("{0} was not able to make the class {1} partial. Please change it manually if possible", T4FileName, type.Name));
- return;
- }
- Warning(String.Format("{0} changed the class {1} to be partial", T4FileName, type.Name));
- }
-
- // Collect misc info about the controller class and add it to the collection
- var controllerInfo = new ControllerInfo
- {
- Area = area,
- Namespace = type.Namespace != null ? type.Namespace.Name : String.Empty,
- ClassName = type.Name
- };
-
- //Filter references to controllers we create
- foreach(var derived in area.Controllers.Where(c => c.ClassName == controllerInfo.DerivedClassName).ToArray())
- area.Controllers.Remove(derived);
-
- // Check if the controller has changed since the generated file was last created
- DateTime lastGenerationTime = File.GetLastWriteTime(controllerInfo.GeneratedFileFullPath);
- if (lastGenerationTime > controllerLastWriteTime)
- {
- controllerInfo.GeneratedCodeIsUpToDate = true;
- }
-
- // Either process new ControllerInfo or integrate results into existing object for partially defined controllers
- var target = area.Controllers.Add(controllerInfo) ? controllerInfo : area.Controllers.First(c => c.Equals(controllerInfo));
- target.HasExplicitConstructor |= HasExplicitConstructor(type);
- target.HasExplicitDefaultConstructor |= HasExplicitDefaultConstructor(type);
-
- if (type.IsAbstract)
- {
- // If it's abstract, set a flag and don't process action methods (derived classes will)
- target.IsAbstract = true;
- }
- else
- {
- // Process all the action methods in the controller
- ProcessControllerActionMethods(target, type);
- }
- }
-
- void ProcessControllerActionMethods(ControllerInfo controllerInfo, CodeClass2 current)
- {
-
- bool isAsyncController = IsAsyncController(current);
-
- // We want to process not just the controller class itself, but also its parents, as they
- // may themselves define actions
- for (CodeClass2 type = current; type != null && type.FullName != "System.Web.Mvc.Controller"; type = (CodeClass2)type.Bases.Item(1))
- {
-
- // If the type doesn't come from this project, some actions on it will fail. Try to get a real project type if possible.
- if (type.InfoLocation != vsCMInfoLocation.vsCMInfoLocationProject)
- {
- // Go through all the projects in the solution
- for (int i = 1; i <= Dte.Solution.Projects.Count; i++)
- {
- Project prj = null;
- try
- {
- prj = Dte.Solution.Projects.Item(i);
- }
- catch (System.Runtime.Serialization.SerializationException)
- {
- // Some project types (that we don't care about) cause a strange exception, so ingore it
- continue;
- }
-
- // Skip it if it's the current project or doesn't have a code model
- try
- {
- if (prj == Project || prj.CodeModel == null)
- continue;
- }
- catch (System.NotImplementedException)
- {
- // Installer project does not implement CodeModel property
- continue;
- }
-
- try
- {
- // If we can get a local project type, use it instead of the original
- var codeType = prj.CodeModel.CodeTypeFromFullName(type.FullName);
- if (codeType != null && codeType.InfoLocation == vsCMInfoLocation.vsCMInfoLocationProject)
- {
- type = (CodeClass2)codeType;
- break;
- }
- }
- catch (System.ArgumentException)
- {
- // CodeTypeFromFullName throws when called on VB projects with a type it doesn't know
- // (instead of returning null), so ignore those exceptions (See http://t4mvc.codeplex.com/workitem/7)
- }
- }
- }
-
- foreach (CodeFunction2 method in GetMethods(type))
- {
- // Ignore non-public methods
- if (method.Access != vsCMAccess.vsCMAccessPublic)
- continue;
-
- // Ignore methods that are marked as not being actions
- if (GetAttribute(method.Attributes, "System.Web.Mvc.NonActionAttribute") != null)
- continue;
-
- // Ignore methods that are marked as Obsolete
- if (GetAttribute(method.Attributes, "System.ObsoleteAttribute") != null)
- continue;
-
- // Ignore generic methods
- if (method.IsGeneric)
- continue;
-
- if(isAsyncController && settings.SupportAsyncActions && (method.Type.TypeKind == vsCMTypeRef.vsCMTypeRefVoid) && method.Name.EndsWith("Async"))
- {
- //Async methods return void and there could be multiple matching Completed methods, so we will use
- //the generic ActionResult as the return type for the method.
- var resultType = Project.CodeModel.CreateCodeTypeRef("System.Web.Mvc.ActionResult");
- // If we haven't yet seen this return type, keep track of it
- if (!ResultTypes.ContainsKey(resultType.AsFullName))
- {
- var resTypeInfo = new ResultTypeInfo(resultType);
- ResultTypes[resultType.AsFullName] = resTypeInfo;
- }
-
- // Collect misc info about the action method and add it to the collection
- controllerInfo.ActionMethods.Add(new ActionMethodInfo(method, current, resultType));
-
- continue;
- }
-
- // This takes care of avoiding generic types which cause method.Type.CodeType to blow up
- if (method.Type.TypeKind != vsCMTypeRef.vsCMTypeRefCodeType || !(method.Type.CodeType is CodeClass2))
- continue;
-
- // We only support action methods that return an ActionResult and Task<ActionResult> derived types
- if (!method.Type.CodeType.get_IsDerivedFrom("System.Web.Mvc.ActionResult") && method.Type.CodeType.FullName !="System.Threading.Tasks.Task<System.Web.Mvc.ActionResult>")
- {
- Warning(String.Format("{0} doesn't support {1}.{2} because it doesn't return a supported {3} type", T4FileName, type.Name, method.Name, method.Type.CodeType.FullName));
- continue;
- }
-
- // Ignore async completion methods as they can't really be used in T4MVC, and can cause issues.
- // See http://stackoverflow.com/questions/5419173/t4mvc-asynccontroller
- if (isAsyncController && method.Name.EndsWith("Completed", StringComparison.OrdinalIgnoreCase))
- continue;
-
- var methodType = method.Type;
- if(method.Type.CodeType.FullName == "System.Threading.Tasks.Task<System.Web.Mvc.ActionResult>")
- methodType = Project.CodeModel.CreateCodeTypeRef("System.Web.Mvc.ActionResult");
-
- // If we haven't yet seen this return type, keep track of it
- var resTypeInfo2 = new ResultTypeInfo(methodType);
- if (!ResultTypes.ContainsKey(resTypeInfo2.FullName))
- {
- ResultTypes[resTypeInfo2.FullName] = resTypeInfo2;
- }
-
- // Make sure the method is virtual
- if (!method.CanOverride && method.OverrideKind != vsCMOverrideKind.vsCMOverrideKindOverride)
- {
- try
- {
- method.CanOverride = true;
- }
- catch
- {
- // If we couldn't make it virtual, give a warning and skip it
- Warning(String.Format("{0} was not able to make the action method {1}.{2} virtual. Please change it manually if possible", T4FileName, type.Name, method.Name));
- continue;
- }
- Warning(String.Format("{0} changed the action method {1}.{2} to be virtual", T4FileName, type.Name, method.Name));
- }
-
- // Collect misc info about the action method and add it to the collection
- controllerInfo.ActionMethods.Add(new ActionMethodInfo(method, current));
- }
- }
- }
-
- void ProcessAllViews(ProjectItem viewsProjectItem, AreaInfo area)
- {
- // Go through all the sub-folders in the Views folder
- foreach (ProjectItem item in viewsProjectItem.ProjectItems)
- {
-
- // We only care about sub-folders, not files
- if (!IsFolder(item))
- continue;
-
- // Find the controller for this view folder
- ControllerInfo controller = area.Controllers.SingleOrDefault(c => c.Name.Equals(item.Name, StringComparison.OrdinalIgnoreCase));
-
- if (controller == null)
- {
- // If it doesn't match a controller, treat as a pseudo-controller for consistency
- controller = new ControllerInfo
- {
- Area = area,
- NotRealController = true,
- Namespace = MakeClassName(settings.T4MVCNamespace, area.Name),
- ClassName = item.Name + ControllerSuffix
- };
- area.Controllers.Add(controller);
- }
-
- AddViewsRecursive(item.ProjectItems, controller.ViewsFolder);
- }
- }
-
- void AddViewsRecursive(ProjectItems items, ViewsFolderInfo viewsFolder)
- {
- AddViewsRecursive(items, viewsFolder, false);
- }
-
- void AddViewsRecursive(ProjectItems items, ViewsFolderInfo viewsFolder, bool useNonQualifiedViewNames)
- {
- // Go through all the files in the subfolder to get the view names
- foreach (ProjectItem item in items)
- {
- if (item.Kind == EnvDTE.Constants.vsProjectItemKindPhysicalFile)
- {
- // Ignore some extensions that are normally not views
- if (settings.ExcludedViewExtensions.Any(extension => Path.GetExtension(item.Name).Equals(extension, StringComparison.OrdinalIgnoreCase)))
- continue;
-
- viewsFolder.AddView(item, useNonQualifiedViewNames);
- }
- else if (item.Kind == EnvDTE.Constants.vsProjectItemKindPhysicalFolder)
- {
- string folderName = Path.GetFileName(item.Name);
- if (folderName.Equals("App_LocalResources", StringComparison.OrdinalIgnoreCase))
- continue;
- // Use simple view names if we're already in that mode, or if the folder name is in the collection
- bool folderShouldUseNonQualifiedViewNames = useNonQualifiedViewNames || settings.NonQualifiedViewFolders.Contains(folderName, StringComparer.OrdinalIgnoreCase);
- var subViewFolder = new ViewsFolderInfo() { Name = folderName };
- viewsFolder.SubFolders.Add(subViewFolder);
- AddViewsRecursive(item.ProjectItems, subViewFolder, folderShouldUseNonQualifiedViewNames);
- }
- }
- }
-
- void RenderControllerViews(ControllerInfo controller)
- {
- PushIndent(" ");
- RenderViewsRecursive(controller.ViewsFolder, controller);
- PopIndent();
- }
-
- void RenderViewsRecursive(ViewsFolderInfo viewsFolder, ControllerInfo controller)
- {
- if(!viewsFolder.HasNonQualifiedViewNames)
- {
- #>
- static readonly _ViewNamesClass s_ViewNames = new _ViewNamesClass();
- public _ViewNamesClass ViewNames { get { return s_ViewNames; } }
- public class _ViewNamesClass
- {
- <#+
- PushIndent(" ");
- foreach (var viewPair in viewsFolder.Views)
- {
- WriteLine("public readonly string " + EscapeID(Sanitize(viewPair.Key)) + " = \"" + viewPair.Key + "\";");
- }
- PopIndent();
- #>
- }
- <#+}
- // For each view, generate a readonly string
- foreach (var viewPair in viewsFolder.Views)
- {
- WriteLine("public readonly string " + EscapeID(Sanitize(viewPair.Key)) + " = \"" + viewPair.Value + "\";");
- }
-
- // For each sub folder, generate a class and recurse
- foreach (var subFolder in viewsFolder.SubFolders)
- {
- string name = Sanitize(subFolder.Name);
- string className = "_" + name;
-
- // If the folder name is the same as the parent, add a modifier to avoid class name conflicts
- // http://mvccontrib.codeplex.com/workitem/7153
- if (name == Sanitize(viewsFolder.Name))
- {
- className += "_";
- }#>
- static readonly <#=className#>Class s_<#=name#> = new <#=className#>Class();
- public <#=className#>Class <#=EscapeID(name)#> { get { return s_<#=name#>; } }
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public partial class <#=className#>Class
- {
- <#+
- PushIndent(" ");
- RenderViewsRecursive(subFolder, controller);
- PopIndent();
-
- WriteLine("}");
- }
- }
-
- IEnumerable<string> GetStaticFilesViewFolders()
- {
- if (settings.AddAllViewsFoldersToStaticFilesFolders)
- {
- foreach (var area in Areas)
- {
- yield return area.Name == null ?
- settings.ViewsRootFolder :
- settings.AreasFolder + "\\" + area.Name + "\\" + settings.ViewsRootFolder;
- }
- }
- }
-
- void ProcessStaticFiles(Project project, string folder)
- {
- ProjectItem folderProjectItem = GetProjectItem(project, folder);
- if (folderProjectItem != null)
- {
- var rootPath = "~";
- if (folder.Contains("\\"))
- {
- rootPath += "/" + folder.Replace("\\", "/");
- rootPath = rootPath.Substring(0, rootPath.LastIndexOf("/"));
- }
- ProcessStaticFilesRecursive(folderProjectItem, rootPath);
- }
- }
-
- void ProcessStaticFilesRecursive(ProjectItem projectItem, string path)
- {
- int nestedLevel = BuildClassStructureForProvidedPath(path);
- ProcessStaticFilesRecursive(projectItem, path, new HashSet<String>());
- for(int i = 0; i < nestedLevel; ++i) {#>
- }
- <#+
- PopIndent();
- }
- }
-
- void ProcessStaticFilesRecursive(ProjectItem projectItem, string path, HashSet<String> nameSet)
- {
- // The passed in HashSet is to guarantee uniqueness with our parent and siblings
- string name = SanitizeWithNoConflicts(projectItem.Name, nameSet);
-
- // This HashSet is to guarantee uniqueness of our direct children
- // We add our own name to it to avoid class name conflicts (http://mvccontrib.codeplex.com/workitem/7153)
- var childrenNameSet = new HashSet<String>();
- childrenNameSet.Add(name);
-
- if (IsFolder(projectItem))
- {
- #>
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public static class <#=EscapeID(name)#> {
- private const string URLPATH = "<#=path#>/<#=projectItem.Name#>";
- public static string Url() { return T4MVCHelpers.ProcessVirtualPath(URLPATH); }
- public static string Url(string fileName) { return T4MVCHelpers.ProcessVirtualPath(URLPATH + "/" + fileName); }
- <#+
- PushIndent(" ");
-
- // Recurse into all the items in the folder
- foreach (ProjectItem item in projectItem.ProjectItems)
- {
- ProcessStaticFilesRecursive(
- item,
- path + "/" + projectItem.Name,
- childrenNameSet);
- }
-
- PopIndent();
- #>
- }
-
- <#+
- }
- else { #>
- <#+
- if (!settings.ExcludedStaticFileExtensions.Any(extension => projectItem.Name.EndsWith(extension, StringComparison.OrdinalIgnoreCase))) {
- // if it's a Typescript file
- if (projectItem.Name.EndsWith(".ts")) {
- string tsJavascriptName = projectItem.Name.Replace(".ts", ".js");
- string minifiedName = projectItem.Name.Replace(".ts", ".min.js");
- if (AddTimestampToStaticLink(projectItem)) { #>
- public static readonly string <#=name#> = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/<#=minifiedName#>") ? Url("<#=minifiedName#>")+"?"+T4MVCHelpers.TimestampString(URLPATH + "/<#=minifiedName#>") : Url("<#=tsJavascriptName#>")+"?"+T4MVCHelpers.TimestampString(URLPATH + "/<#=tsJavascriptName#>");
- <#+} else {#>
- public static readonly string <#=name#> = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/<#=minifiedName#>") ? Url("<#=minifiedName#>") : Url("<#=tsJavascriptName#>");
- <#+} #>
- <#+}
- // if it's a non-minified javascript file
- else if (projectItem.Name.EndsWith(".js") && !projectItem.Name.EndsWith(".min.js")) {
- string minifiedName = projectItem.Name.Replace(".js", ".min.js");
- if (AddTimestampToStaticLink(projectItem)) { #>
- public static readonly string <#=name#> = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/<#=minifiedName#>") ? Url("<#=minifiedName#>")+"?"+T4MVCHelpers.TimestampString(URLPATH + "/<#=minifiedName#>") : Url("<#=projectItem.Name#>")+"?"+T4MVCHelpers.TimestampString(URLPATH + "/<#=projectItem.Name#>");
- <#+} else {#>
- public static readonly string <#=name#> = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/<#=minifiedName#>") ? Url("<#=minifiedName#>") : Url("<#=projectItem.Name#>");
- <#+} #>
- <#+}
- else if (projectItem.Name.EndsWith(".css") && !projectItem.Name.EndsWith(".min.css")) {
- string minifiedName = projectItem.Name.Replace(".css", ".min.css");
- if (AddTimestampToStaticLink(projectItem)) { #>
- public static readonly string <#=name#> = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/<#=minifiedName#>") ? Url("<#=minifiedName#>")+"?"+T4MVCHelpers.TimestampString(URLPATH + "/<#=minifiedName#>") : Url("<#=projectItem.Name#>")+"?"+T4MVCHelpers.TimestampString(URLPATH + "/<#=projectItem.Name#>");
- <#+} else {#>
- public static readonly string <#=name#> = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/<#=minifiedName#>") ? Url("<#=minifiedName#>") : Url("<#=projectItem.Name#>");
- <#+} #>
- <#+}
- else if (AddTimestampToStaticLink(projectItem)) { #>
- public static readonly string <#=name#> = Url("<#=projectItem.Name#>")+"?"+T4MVCHelpers.TimestampString(URLPATH + "/<#=projectItem.Name#>");
- <#+}
- else { #>
- public static readonly string <#=name#> = Url("<#=projectItem.Name#>");
- <#+}
- } #>
- <#+
- // Non folder items may also have children (virtual folders, Class.cs -> Class.Designer.cs, template output)
- // Just register them on the same path as their parent item
- foreach (ProjectItem item in projectItem.ProjectItems)
- {
- ProcessStaticFilesRecursive(item, path, childrenNameSet);
- }
- }
- }
-
- int BuildClassStructureForProvidedPath(string path)
- {
- var folders = path.Split(new char[] {'/', '~'}, StringSplitOptions.RemoveEmptyEntries);
- var parentFolder = String.Empty;
- var currentPath = "~";
- foreach(var folder in folders)
- {
- currentPath += "/" + folder;
- string className = EscapeID(Sanitize(folder));
- // If the folder name is the same as the parent, add a modifier to avoid class name conflicts
- // http://mvccontrib.codeplex.com/workitem/7153
- if (parentFolder == folder)
- {
- className += "_";
- }
-
- if(!virtualPathesForStaticFiles.Contains(currentPath))
- {
- virtualPathesForStaticFiles.Add(currentPath);#>
-
- [<#= GeneratedCode #>, DebuggerNonUserCode]
- public static partial class <#=className #> {
- private const string URLPATH = "<#=currentPath#>";
- public static string Url() { return T4MVCHelpers.ProcessVirtualPath(URLPATH); }
- public static string Url(string fileName) { return T4MVCHelpers.ProcessVirtualPath(URLPATH + "/" + fileName); }
- <#+ } else {
- #>
-
- public static partial class <#=className #> {
- <#+ }
- PushIndent(" ");
- parentFolder = folder;
- }
- return folders.Length;
- }
-
- ProjectItem GetProjectItem(Project project, string name)
- {
- return GetProjectItem(project.ProjectItems, name);
- }
-
- ProjectItem GetProjectItem(ProjectItems items, string subPath)
- {
-
- ProjectItem current = null;
- foreach (string name in subPath.Split('\\'))
- {
- try
- {
- // ProjectItems.Item() throws when it doesn't exist, so catch the exception
- // to return null instead.
- current = items.Item(name);
- }
- catch
- {
- // If any chunk couldn't be found, fail
- return null;
- }
- items = current.ProjectItems;
- }
-
- return current;
- }
-
- static bool IsController(CodeClass2 type)
- {
- // Ignore any class which name doesn't end with "Controller"
- if (!type.FullName.EndsWith(ControllerSuffix)) return false;
-
- for (; type.FullName != "System.Web.Mvc.Controller"; type = (CodeClass2)type.Bases.Item(1))
- {
- if (type.Bases.Count == 0)
- return false;
- }
- return true;
- }
-
- static bool IsAsyncController(CodeClass2 type)
- {
- for (; type.FullName != "System.Web.Mvc.AsyncController"; type = (CodeClass2)type.Bases.Item(1))
- {
- if (type.Bases.Count == 0)
- return false;
- }
- return true;
- }
-
- static string GetVirtualPath(ProjectItem item)
- {
- string fileFullPath = item.get_FileNames(0);
-
- // Ignore files that are not under the app root (e.g. they could be linked files)
- if (!fileFullPath.StartsWith(AppRoot, StringComparison.OrdinalIgnoreCase))
- return null;
-
- // Make a virtual path from the physical path
- return "~/" + fileFullPath.Substring(AppRoot.Length).Replace('\\', '/');
- }
-
- static string ProcessAreaOrControllerName(string name)
- {
- return settings.UseLowercaseRoutes ? name.ToLowerInvariant() : name;
- }
-
- // Return all the CodeFunction2 in the CodeElements collection
- static IEnumerable<CodeFunction2> GetMethods(CodeClass2 codeClass)
- {
- // Only look at regular method (e.g. ignore things like contructors)
- return codeClass.Members.OfType<CodeFunction2>()
- .Where(f => f.FunctionKind == vsCMFunction.vsCMFunctionFunction);
- }
-
- // Check if the class has any explicit constructor
- static bool HasExplicitConstructor(CodeClass2 codeClass)
- {
- return codeClass.Members.OfType<CodeFunction2>().Any(
- f => !f.IsShared && f.FunctionKind == vsCMFunction.vsCMFunctionConstructor);
- }
-
- // Check if the class has a default (i.e. no params) constructor
- static bool HasExplicitDefaultConstructor(CodeClass2 codeClass)
- {
- return codeClass.Members.OfType<CodeFunction2>().Any(
- f => !f.IsShared && f.FunctionKind == vsCMFunction.vsCMFunctionConstructor && f.Parameters.Count == 0);
- }
-
- // Find a method with a given name
- static CodeFunction2 GetMethod(CodeClass2 codeClass, string name)
- {
- return GetMethods(codeClass).FirstOrDefault(f => f.Name == name);
- }
-
- // Find an attribute of a given type on an attribute collection
- static CodeAttribute2 GetAttribute(CodeElements attributes, string attributeType)
- {
- for (int i = 1; i <= attributes.Count; i++)
- {
- try
- {
- var attrib = (CodeAttribute2)attributes.Item(i);
- if (attributeType.Split(',').Contains(attrib.FullName, StringComparer.OrdinalIgnoreCase))
- {
- return attrib;
- }
- }
- catch
- {
- // FullName can throw in some cases, so just ignore those attributes
- continue;
- }
- }
- return null;
- }
-
- static CodeAttribute2 GetAttribute(CodeClass2 type, string attributeType)
- {
- while(type != null) {
- var attribute = GetAttribute(type.Attributes, attributeType);
- if(attribute != null)
- return attribute;
- if (type.Bases.Count == 0)
- return null;
- type = (CodeClass2)type.Bases.Item(1);
- }
- return null;
- }
-
- static string UniqueFullName(CodeTypeRef codeType)
- {
- return UniqueFullName(codeType.CodeType);
- }
-
- static string UniqueFullName(CodeType codeType)
- {
- var uniqueName = codeType.FullName;
-
- // Match characters not allowed in class names.
- uniqueName = Regex.Replace(uniqueName, @"[^\p{Ll}\p{Lu}\p{Lt}\p{Lm}\p{Lo}\p{Nl}\d]", "_");
-
- // Remove duplicate '_' characters
- uniqueName = Regex.Replace(uniqueName, @"__+", "_");
-
- // Remove trailing '_' characters
- uniqueName = uniqueName.TrimEnd('_');
-
- return uniqueName;
- }
-
- // Return whether a ProjectItem is a folder and not a file
- static bool IsFolder(ProjectItem item)
- {
- return (item.Kind == EnvDTE.Constants.vsProjectItemKindPhysicalFolder);
- }
-
- static string MakeClassName(string ns, string classname)
- {
- return String.IsNullOrEmpty(ns) ? classname :
- String.IsNullOrEmpty(classname) ? ns : ns + "." + codeProvider.CreateEscapedIdentifier(classname);
- }
-
- static string SanitizeWithNoConflicts(string token, HashSet<string> names)
- {
- string name = Sanitize(token);
-
- while (names.Contains(name))
- {
- name += "_";
- }
-
- names.Add(name);
-
- return name;
- }
-
- static string Sanitize(string token)
- {
- if (token == null) return null;
-
- // Replace all invalid chars by underscores
- token = Regex.Replace(token, @"[\W\b]", "_", RegexOptions.IgnoreCase);
-
- // If it starts with a digit, prefix it with an underscore
- token = Regex.Replace(token, @"^\d", @"_$0");
-
- // Check for reserved…
Large files files are truncated, but you can click here to view the full file