/// <summary> /// Helper method which tries to create project navigator instance for given assembly. /// For given assembly it searches inside provided path for corresponding csproj file. /// </summary> public static bool TryCreate(string searchPath, Assembly assembly, out ProjectNavigator navigator) { navigator = null; if (!Directory.Exists(searchPath)) { return(false); } string assemblyName = assembly.GetName().Name; string projectName = $"{assemblyName}.csproj"; string projectCsName = $"{assemblyName}.Cs.csproj"; string projectPath = Directory.GetFiles(searchPath, projectName, SearchOption.AllDirectories).SingleOrDefault(); string projectCsPath = Directory.GetFiles(searchPath, projectCsName, SearchOption.AllDirectories).SingleOrDefault(); if (File.Exists(projectCsPath)) { navigator = new ProjectNavigator(projectCsPath); return(true); } if (File.Exists(projectPath)) { navigator = new ProjectNavigator(projectPath); return(true); } return(false); }
/// <summary> /// Extracts enum declarations from an assembly. /// </summary> private List <EnumDecl> ExtractEnums(Assembly assembly, CommentNavigator docNavigator, ProjectNavigator projNavigator) { return(TypesExtractor .GetEnums(assembly, new string[0]) .Select(type => DeclarationConvertor.EnumToDecl(type, docNavigator, projNavigator)) .ToList()); }
/// <summary> /// Factory method which creates declaration corresponding to given type. /// </summary> public static IDecl ToDecl(System.Type type, CommentNavigator navigator, ProjectNavigator projNavigator) { if (type.IsSubclassOf(typeof(Enum))) { return(EnumToDecl(type, navigator, projNavigator)); } if (type.IsSubclassOf(typeof(Data))) { return(TypeToDecl(type, navigator, projNavigator)); } throw new ArgumentException($"{type.FullName} is not subclass of Enum or Data", nameof(type)); }
/// <summary> /// Writes data types schema into specified Context. /// </summary> public void Generate(Context context) { var assemblies = GetAssemblies(); foreach (Assembly assembly in assemblies) { bool hasDocumentation = CommentNavigator.TryCreate(assembly, out CommentNavigator docNavigator); bool isProjectLocated = ProjectNavigator.TryCreate(null, assembly, out ProjectNavigator projNavigator); var declTypes = ExtractTypes(assembly, docNavigator, projNavigator); var declEnums = ExtractEnums(assembly, docNavigator, projNavigator); context.SaveMany(declTypes); context.SaveMany(declEnums); } }
/// <summary> /// Converts enum to EnumDecl /// </summary> public static EnumDecl EnumToDecl(System.Type type, CommentNavigator navigator, ProjectNavigator projNavigator) { if (!type.IsSubclassOf(typeof(Enum))) { throw new ArgumentException($"Cannot create enum declaration from type: {type.FullName}."); } EnumDecl decl = new EnumDecl(); decl.Name = type.Name; decl.Comment = GetCommentFromAttribute(type) ?? navigator?.GetXmlComment(type); decl.Category = projNavigator?.GetTypeLocation(type); decl.Module = new ModuleKey { ModuleName = type.Namespace }; decl.Label = GetLabelFromAttribute(type) ?? type.Name; List <FieldInfo> items = type.GetFields(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static).ToList(); decl.Items = items.Select(i => ToEnumItem(i, navigator)).ToList(); return(decl); }
/// <summary> /// Converts type inherited from Data to TypeDecl /// </summary> public static TypeDecl TypeToDecl(System.Type type, CommentNavigator navigator, ProjectNavigator projNavigator) { if (!type.IsSubclassOf(typeof(Data))) { throw new ArgumentException($"Cannot create type declaration from type: {type.FullName}."); } TypeDecl decl = new TypeDecl(); decl.Module = new ModuleKey { ModuleName = type.Namespace }; decl.Category = projNavigator?.GetTypeLocation(type); decl.Name = type.Name; decl.Label = GetLabelFromAttribute(type) ?? type.Name; decl.Comment = GetCommentFromAttribute(type) ?? navigator?.GetXmlComment(type); decl.Kind = GetKind(type); decl.IsRecord = type.IsSubclassOf(typeof(Record)); decl.Inherit = IsRoot(type.BaseType) ? null : CreateTypeDeclKey(type.BaseType.Namespace, type.BaseType.Name); decl.Index = GetIndexesFromAttributes(type); // Skip special (property getters, setters, etc) and inherited methods List <MethodInfo> handlers = type.GetMethods(PublicInstanceDeclaredFlags) .Where(IsProperHandler) .ToList(); var declares = new List <HandlerDeclareItem>(); var implements = new List <HandlerImplementItem>(); foreach (MethodInfo method in handlers) { // Abstract methods have only declaration if (method.IsAbstract) { declares.Add(ToDeclare(method, navigator)); } // Overriden methods are marked with override else if (method.GetBaseDefinition() != method) { // TODO: Temp adding declare to avoid signature search in bases. declares.Add(ToDeclare(method, navigator)); implements.Add(ToImplement(method)); } // Case for methods without modifiers else { declares.Add(ToDeclare(method, navigator)); implements.Add(ToImplement(method)); } } // Add method information to declaration if (declares.Any()) { decl.Declare = new HandlerDeclareBlock { Handlers = declares } } ; if (implements.Any()) { decl.Implement = new HandlerImplementBlock { Handlers = implements } } ; List <PropertyInfo> dataProperties = type.GetProperties(PublicInstanceDeclaredFlags) .Where(p => IsAllowedType(p.PropertyType)) .Where(IsPublicGetSet).ToList(); decl.Elements = dataProperties.Select(p => ToElement(p, navigator)).ToList(); decl.Keys = GetKeyProperties(type) .Where(p => IsAllowedType(p.PropertyType)) .Where(IsPublicGetSet) .Select(t => t.Name).ToList(); return(decl); }