<# #region File and License Information /* Copyright © 2007, Daniel Vaughan. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2009-08-15 11:55:41Z */ #endregion #> <#@ template language="C#" hostSpecific="true" debug="true" #> <#@ assembly name="System.dll" #> <#@ assembly name="EnvDTE" #> <#@ Import Namespace="EnvDTE" #> <#@ Import Namespace="System.Text" #> <#@ Import Namespace="System.Collections.Generic" #> <#@ import namespace="System.Diagnostics" #> /* This code was automatically generated by Daniel Vaughan's metadata generator. Changes to this file may be lost if regeneration occurs. http://danielvaughan.orpius.com */ <# IServiceProvider hostServiceProvider = (IServiceProvider)Host; EnvDTE.DTE dte = (EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE)); EnvDTE.ProjectItem containingProjectItem = dte.Solution.FindProjectItem(Host.TemplateFile); Project project = containingProjectItem.ContainingProject; /* Build the namespace representations, which contain class etc. */ Dictionary namespaceBuilders = new Dictionary(); foreach (ProjectItem projectItem in project.ProjectItems) { ProcessProjectItem(projectItem, namespaceBuilders); } /* Finally, write them to the output. */ foreach (object item in namespaceBuilders.Values) { WriteLine(item.ToString()); } #> <#+ /// /// The modifier to use when outputting classes. /// const string generatedClassAccessModifier = "internal"; /// /// The prefix to use for output class and interface names. /// The combination of this and provides /// MetaGen with the ability to identify those classes etc., /// for which it should generated metadata, and to ignore MetaGen generated classes. /// const string generatedClassPrefix = ""; /// /// The suffix to use for output class and interface names. /// The combination of this and provides /// MetaGen with the ability to identify those classes etc., /// for which it should generated metadata, and to ignore MetaGen generated classes. /// const string generatedClassSuffix = "Metadata"; /// /// The child namespace in which to place generated items. /// If there is a class in MyNamespace namespace, /// the metadata class will be generated /// in the MyNamespace.[generatedClassSuffix] namespace. /// This string can be null or empty, in which case a subnamesapce /// will not be created, and generated output will reside /// in the original classes namespace. /// const string generatedNamespace = "Metadata"; /// /// The number of spaces to insert for a one step indent. /// const int tabSize = 4; public void ProcessProjectItem(ProjectItem projectItem, Dictionary namespaceBuilders) { FileCodeModel fileCodeModel = projectItem.FileCodeModel; if (fileCodeModel != null) { foreach (CodeElement codeElement in fileCodeModel.CodeElements) { WalkElements(codeElement, null, null, namespaceBuilders); } } if (projectItem.ProjectItems != null) { foreach (ProjectItem childItem in projectItem.ProjectItems) { ProcessProjectItem(childItem, namespaceBuilders); } } } int indent; public void WalkElements(CodeElement codeElement, CodeElement parent, BuilderBase parentContainer, Dictionary namespaceBuilders) { indent++; CodeElements codeElements; if (parentContainer == null) { NamespaceBuilder builder; string name = "global"; if (!namespaceBuilders.TryGetValue(name, out builder)) { builder = new NamespaceBuilder(name, null, 0); namespaceBuilders[name] = builder; } parentContainer = builder; } switch(codeElement.Kind) { /* Handle namespaces */ case vsCMElement.vsCMElementNamespace: { CodeNamespace codeNamespace = (CodeNamespace)codeElement; string name = codeNamespace.FullName; if (!string.IsNullOrEmpty(generatedNamespace) && name.EndsWith(generatedNamespace)) { break; } NamespaceBuilder builder; if (!namespaceBuilders.TryGetValue(name, out builder)) { builder = new NamespaceBuilder(name, null, 0); namespaceBuilders[name] = builder; } codeElements = codeNamespace.Members; foreach (CodeElement element in codeElements) { WalkElements(element, codeElement, builder, namespaceBuilders); } break; } /* Process classes */ case vsCMElement.vsCMElementClass: { CodeClass codeClass = (CodeClass)codeElement; string name = codeClass.Name; if (string.IsNullOrEmpty(generatedNamespace) && name.StartsWith(generatedClassPrefix) && name.EndsWith(generatedClassSuffix)) { break; } List comments = new List(); comments.Add(string.Format("/// Metadata for class ", codeClass.FullName)); BuilderBase builder; if (!parentContainer.Children.TryGetValue(name, out builder)) { builder = new ClassBuilder(name, comments, indent); parentContainer.Children[name] = builder; } codeElements = codeClass.Members; if (codeElements != null) { foreach (CodeElement ce in codeElements) { WalkElements(ce, codeElement, builder, namespaceBuilders); } } break; } /* Process interfaces. */ case vsCMElement.vsCMElementInterface: { CodeInterface codeInterface = (CodeInterface)codeElement; string name = codeInterface.Name; if (name.StartsWith(generatedClassPrefix) && name.EndsWith(generatedClassSuffix)) { break; } List comments = new List(); string commentName = FormatTypeNameForComment(codeInterface.FullName); comments.Add(string.Format("/// Metadata for interface ", commentName)); InterfaceBuilder builder = new InterfaceBuilder(name, comments, indent); parentContainer.AddChild(builder); codeElements = codeInterface.Members; if (codeElements != null) { foreach (CodeElement ce in codeElements) { WalkElements(ce, codeElement, builder, namespaceBuilders); } } break; } /* Process methods */ case vsCMElement.vsCMElementFunction: { CodeFunction codeFunction = (CodeFunction)codeElement; if (codeFunction.Name == parentContainer.Name || codeFunction.Name == "ToString" || codeFunction.Name == "Equals" || codeFunction.Name == "GetHashCode" || codeFunction.Name == "GetType" || codeFunction.Name == "MemberwiseClone" || codeFunction.Name == "ReferenceEquals") { break; } string name = codeFunction.Name.Replace('.', '_'); List comments = new List(); string commentName = FormatTypeNameForComment(codeFunction.FullName); comments.Add(string.Format("/// Name of method ", commentName)); MemberBuilder builder = new MemberBuilder(name, comments, indent); parentContainer.AddChild(builder); break; } /* Process properties. */ case vsCMElement.vsCMElementProperty: { CodeProperty codeProperty = (CodeProperty)codeElement; string name = codeProperty.Name.Replace('.', '_'); if (name != "this") { List comments = new List(); string commentName = FormatTypeNameForComment(codeProperty.FullName); comments.Add(string.Format("/// Name of property ", commentName)); MemberBuilder builder = new MemberBuilder(name, comments, indent); parentContainer.AddChild(builder); } break; } /* Process fields. */ case vsCMElement.vsCMElementVariable: { CodeVariable codeVariable = (CodeVariable)codeElement; string name = codeVariable.Name; List comments = new List(); string commentName = FormatTypeNameForComment(codeVariable.FullName); comments.Add(string.Format("/// Name of field ", commentName)); MemberBuilder builder = new MemberBuilder(name, comments, indent); parentContainer.AddChild(builder); break; } } indent--; } string FormatTypeNameForComment(string typeName) { return typeName.Replace('<', '{').Replace('>', '}'); } /// /// The base class for all project item representations. /// public abstract class BuilderBase { string name; public string Name { get { return name; } } List comments; public List Comments { get { return comments; } } int indent; public int Indent { get { return indent; } set { indent = value; } } protected BuilderBase(string name, List comments, int indent) { this.name = name; this.comments = comments; this.indent = indent; } Dictionary children = new Dictionary(); public Dictionary Children { get { return children; } } public void AddChild(BuilderBase obj) { if (children.ContainsKey(obj.Name)) { return; } children.Add(obj.Name, obj); } public override int GetHashCode() { return Name != null ? Name.GetHashCode() : 0; } } /// /// Represents a namespace within a project and is a container /// for classes. /// public sealed class NamespaceBuilder : BuilderBase { public NamespaceBuilder(string name, List comments, int indent) : base(name, comments, indent) { } public override string ToString() { string indentString = string.Empty.PadLeft(Indent); StringBuilder sb = new StringBuilder(); bool global = Name == "global"; if (!global) { sb.Append("namespace "); sb.Append(Name); if (!string.IsNullOrEmpty(generatedNamespace)) { sb.Append('.'); sb.AppendLine(generatedNamespace); } else { sb.AppendLine(); } sb.AppendLine("{"); } foreach (BuilderBase item in Children.Values) { item.Indent = Indent + tabSize; sb.AppendLine(item.ToString()); } if (!global) { sb.AppendLine("}"); } return sb.ToString(); } } /// /// Represents a class within a project. /// class ClassBuilder : BuilderBase { public ClassBuilder(string name, List comments, int indent) : base(name, comments, indent) { } public override string ToString() { string indent1 = string.Empty.PadLeft(Indent); string indent2 = string.Empty.PadLeft(Indent + tabSize); StringBuilder sb = new StringBuilder(); /* Write comments. */ foreach (string line in Comments) { sb.Append(indent1); sb.AppendLine(line); } sb.Append(indent1); sb.Append(generatedClassAccessModifier); sb.Append(" static class "); sb.Append(generatedClassPrefix); sb.Append(Name); sb.AppendLine(generatedClassSuffix); sb.Append(indent1); sb.AppendLine("{"); sb.Append(indent2); sb.AppendLine("public static class MemberNames"); sb.Append(indent2); sb.AppendLine(" {"); foreach (BuilderBase item in Children.Values) { item.Indent = Indent + 8; sb.Append(item.ToString()); sb.AppendLine(); } sb.Append(indent2); sb.AppendLine(" }"); sb.Append(indent1); sb.AppendLine("}"); return sb.ToString(); } } /// /// Represents an interface within a project. /// sealed class InterfaceBuilder : ClassBuilder { public InterfaceBuilder(string name, List comments, int indent) : base(name, comments, indent) { } } /// /// Represents a property, method, or field. /// public sealed class MemberBuilder : BuilderBase { public MemberBuilder(string name, List comments, int indent) : base(name, comments, indent) { } public override string ToString() { string indent = string.Empty.PadLeft(Indent); StringBuilder sb = new StringBuilder(); foreach (string line in Comments) { sb.Append(indent); sb.AppendLine(line); } sb.Append(indent); sb.AppendFormat("public const string {0} = \"{1}\";", Name, Name); sb.AppendLine(); return sb.ToString(); } } #>