Inheritance: IDescription
        private DataType BuildGraph(
            DataType parent,
            Type type, 
            bool inputGraph,
            IEnumerable<Type> ancestors, 
            MemberDescription memberDescription = null,
            ActionCall action = null)
        {
            var description = _typeConvention.GetDescription(type);

            var dataType = new DataType
            {
                Name = !type.IsSimpleType() && memberDescription != null ? 
                    memberDescription.Name : description.Name,
                LongNamespace = parent.MapOrEmpty(x => x.LongNamespace.Concat(x.Name).ToList(), new List<string>()),
                ShortNamespace = new List<string>(),
                Comments = description.Comments
            };

            if (type.IsDictionary())
                BuildDictionary(dataType, type, description, inputGraph, ancestors, memberDescription);
            else if (type.IsArray || type.IsList())
                BuildArray(dataType, type, description, inputGraph, ancestors, memberDescription);
            else if (type.IsSimpleType()) BuildSimpleType(dataType, type);
            else BuildComplexType(dataType, type, inputGraph, ancestors, action);

            return _configuration.TypeOverrides.Apply(type, dataType);
        }
 public List<BodyLineItem> Create(DataType type)
 {
     var data = new List<BodyLineItem>();
     WalkGraph(data, type, 0);
     data.ForEach((x, i) => x.Index = i + 1);
     return data;
 }
        private void WalkSimpleType(
            List<BodyLineItem> description, 
            DataType type, int level,
            Action<BodyLineItem> opening)
        {
            var data = new BodyLineItem
            {
                Name = type.Name,
                TypeName = type.Name,
                Comments = type.Comments.TransformMarkdownInline(),
                Whitespace = Whitespace.Repeat(level),
                IsSimpleType = true
            };

            switch (type.Name)
            {
                case Xml.UnsignedLongType:
                case Xml.LongType:
                case Xml.UnsignedIntType:
                case Xml.IntType:
                case Xml.UnsignedShortType:
                case Xml.ShortType:
                case Xml.ByteType:
                case Xml.UnsignedByteType:
                    data.IsNumeric = true;
                    data.SampleValue = _configuration.SampleIntegerValue.ToSampleValueString(_configuration);
                    break;
                case Xml.FloatType:
                case Xml.DoubleType:
                case Xml.DecimalType: 
                    data.IsNumeric = true;
                    data.SampleValue = _configuration.SampleRealValue.ToSampleValueString(_configuration);
                    break;
                case Xml.BooleanType: 
                    data.IsBoolean = true;
                    data.SampleValue = _configuration.SampleBoolValue.ToString().ToLower();
                    break;
                case Xml.DateTimeType: 
                    data.IsDateTime = true;
                    data.SampleValue = _configuration.SampleDateTimeValue.ToSampleValueString(_configuration);
                   break;
                case Xml.DurationType: 
                    data.IsDuration = true;
                    data.SampleValue = _configuration.SampleTimeSpanValue.ToSampleValueString(_configuration);
                    break;
                case Xml.UuidType: 
                    data.IsGuid = true;
                    data.SampleValue = _configuration.SampleGuidValue.ToSampleValueString(_configuration);
                    break;
                default: 
                    data.IsString = true;
                    data.SampleValue = _configuration.SampleStringValue; 
                    break;
            }

            data.Options = WalkOptions(type, x => data.SampleValue = x.Options.First().Value);

            if (opening != null) opening(data);
            description.Add(data);
        }
 private void WalkGraph(List<BodyLineItem> data, DataType type, int level, 
     Action<BodyLineItem> opening = null, 
     Action<BodyLineItem> closing = null)
 {
     if (type.IsSimple) WalkSimpleType(data, type, level, opening);
     else if (type.IsArray) WalkArray(data, type, level, opening, closing);
     else if (type.IsDictionary) WalkDictionary(data, type, level, opening, closing);
     else if (type.IsComplex) WalkComplexType(data, type, level, opening, closing);
     if (level == 0)
     {
         data.First().IsFirst = true;
         data.Last().IsLast = true;
     }
 }
 private void BuildDictionary(
     DataType dataType,
     Type type,
     TypeDescription typeDescription,
     bool inputGraph,
     IEnumerable<Type> ancestors, 
     MemberDescription memberDescription)
 {
     var types = type.GetGenericDictionaryTypes();
     dataType.IsDictionary = true;
     dataType.Comments = memberDescription.WhenNotNull(x => x.Comments).OtherwiseDefault() ?? dataType.Comments;
     dataType.DictionaryEntry = new DictionaryEntry
     {
         KeyName = memberDescription.WhenNotNull(x => x.DictionaryEntry.KeyName).OtherwiseDefault() ??
                   typeDescription.WhenNotNull(x => x.DictionaryEntry.KeyName).OtherwiseDefault(),
         KeyComments = memberDescription.WhenNotNull(x => x.DictionaryEntry.KeyComments).OtherwiseDefault() ??
                       typeDescription.WhenNotNull(x => x.DictionaryEntry.KeyComments).OtherwiseDefault(),
         KeyType = BuildGraph(dataType, types.Key, inputGraph, ancestors),
         ValueComments = memberDescription.WhenNotNull(x => x.DictionaryEntry.ValueComments).OtherwiseDefault() ??
                         typeDescription.WhenNotNull(x => x.DictionaryEntry.ValueComments).OtherwiseDefault(),
         ValueType = BuildGraph(dataType, types.Value, inputGraph, ancestors)
     };
 }
 private void BuildArray(
     DataType dataType,
     Type type,
     TypeDescription typeDescription,
     bool inputGraph,
     IEnumerable<Type> ancestors,
     MemberDescription memberDescription)
 {
     dataType.IsArray = true;
     dataType.Comments = memberDescription.WhenNotNull(x => x.Comments).OtherwiseDefault() ?? dataType.Comments;
     var itemType = BuildGraph(dataType, type.GetListElementType(), inputGraph, ancestors);
     dataType.ArrayItem = new ArrayItem
     {
         Name = memberDescription.WhenNotNull(x => x.ArrayItem.Name).OtherwiseDefault() ??
                typeDescription.WhenNotNull(x => x.ArrayItem.Name).OtherwiseDefault() ?? itemType.Name,
         Comments = memberDescription.WhenNotNull(x => x.ArrayItem.Comments).OtherwiseDefault() ??
                    typeDescription.ArrayItem.WhenNotNull(x => x.Comments).OtherwiseDefault(),
         Type = itemType
     };
 }
 private static IEnumerable<DataType> GetTypeChildTypes(DataType type)
 {
     if (type.Members != null)
         foreach (var childType in type.Members.Select(y => y.Type)) yield return childType;
     if (type.ArrayItem != null) yield return type.ArrayItem.Type;
     if (type.DictionaryEntry != null)
     {
         yield return type.DictionaryEntry.KeyType;
         yield return type.DictionaryEntry.ValueType;
     }
 } 
 private static void GenerateShortNamespaces(DataType type)
 {
     type.TraverseMany(GetTypeChildTypes)
         .GroupBy(x => x.Name)
         .Where(x => x.Count() > 1)
         .ForEach(x => x.ShrinkMultipartKeyRight(y => y.LongNamespace, (t, k) =>
             t.ShortNamespace = k.EndsWith(t.Name) ? k.Shorten(1).ToList() : k));
 }
 private void BuildComplexType(
     DataType dataType,
     Type type,
     bool inputGraph,
     IEnumerable<Type> ancestors,
     ActionCall action)
 {
     dataType.IsComplex = true;
     dataType.Members =
         (type.IsProjection() ?
            type.GetProjectionProperties() :
            _typeCache.GetPropertiesFor(type).Select(x => x.Value))
         .Where(x =>
             (!_configuration.ExcludeAutoBoundProperties || !x.IsAutoBound()) &&
             !x.IsQuerystring(action) &&
             !x.IsUrlParameter(action))
         .Select(x => new
         {
             Property = x,
             Ancestors = ancestors.Concat(type),
             Type = x.PropertyType,
             UnwrappedType = x.PropertyType.UnwrapType(),
             Description = _memberConvention.GetDescription(x)
         })
         .Where(x => x.Ancestors.All(y => y != x.UnwrappedType) &&
                     !x.Description.Hidden)
         .Select(x => _configuration.MemberOverrides.Apply(x.Property, new Member
         {
             Name = x.Description.WhenNotNull(y => y.Name).OtherwiseDefault(),
             Comments = x.Description.WhenNotNull(y => y.Comments).OtherwiseDefault(),
             DefaultValue = inputGraph ? x.Description.WhenNotNull(y => y.DefaultValue)
                 .WhenNotNull(z => z.ToSampleValueString(_configuration)).OtherwiseDefault() : null,
             SampleValue =  x.Description.WhenNotNull(y => y.SampleValue)
                 .WhenNotNull(z => z.ToSampleValueString(_configuration)).OtherwiseDefault(),
             Required = inputGraph && !x.Type.IsNullable() && x.Description.WhenNotNull(y => !y.Optional).OtherwiseDefault(),
             Optional = inputGraph && (x.Type.IsNullable() || x.Description.WhenNotNull(y => y.Optional).OtherwiseDefault()),
             Deprecated = x.Description.Deprecated,
             DeprecationMessage = x.Description.DeprecationMessage,
             Type = BuildGraph(dataType, x.Type, inputGraph, x.Ancestors, x.Description)
         })).ToList();
 }
 private void BuildSimpleType(DataType dataType, Type type)
 {
     dataType.IsSimple = true;
     dataType.LongNamespace.Clear();
     dataType.ShortNamespace.Clear();
     if (type.GetNullableUnderlyingType().IsEnum) 
         dataType.Options = _optionFactory.BuildOptions(type);
 }
        private void WalkComplexType(List<BodyLineItem> data, DataType type, int level,
            Action<BodyLineItem> opening = null,
            Action<BodyLineItem> closing = null)
        {
            var complexOpening = new BodyLineItem
            {
                Name = type.Name,
                LongNamespace = type.LongNamespace,
                ShortNamespace = type.ShortNamespace,
                Comments = type.Comments.TransformMarkdownInline(),
                Whitespace = Whitespace.Repeat(level),
                IsOpening = true,
                IsComplexType = true
            };

            if (opening != null) opening(complexOpening);

            data.Add(complexOpening);

            foreach (var member in type.Members)
            {
                var lastMember = member == type.Members.Last();

                WalkGraph(data, member.Type, level + 1, 
                    x => {
                        x.Name = member.Name;
                        x.Comments = member.Comments.TransformMarkdownInline();
                        x.DefaultValue = member.DefaultValue;
                        if (member.SampleValue != null) x.SampleValue = 
                            member.SampleValue.ToSampleValueString(_configuration);
                        x.IsMember = true;
                        if (lastMember) x.IsLastMember = true;
                        if (!member.Type.IsSimple) x.IsOpening = true;
                        if (member.Required) x.Required = true;
                        if (member.Optional) x.Optional = true;

                        if (member.Deprecated)
                        {
                            x.IsDeprecated = true;
                            x.DeprecationMessage = member.DeprecationMessage;
                        }
                    }, 
                    x => {
                        x.Name = member.Name;
                        x.IsMember = true;
                        if (lastMember) x.IsLastMember = true;
                    });
            }

            var complexClosing = new BodyLineItem
            {
                Name = type.Name,
                Whitespace = Whitespace.Repeat(level),
                IsClosing = true,
                IsComplexType = true
            };

            if (closing != null) closing(complexClosing);

            data.Add(complexClosing);
        }
        private void WalkDictionary(List<BodyLineItem> data, DataType type, int level,
            Action<BodyLineItem> opening = null,
            Action<BodyLineItem> closing = null)
        {
            var dictionaryOpening = new BodyLineItem
            {
                Name = type.Name,
                LongNamespace = type.LongNamespace,
                ShortNamespace = type.ShortNamespace,
                Comments = type.Comments.TransformMarkdownInline(),
                Whitespace = Whitespace.Repeat(level),
                IsOpening = true,
                IsDictionary = true
            };

            if (opening != null) opening(dictionaryOpening);

            data.Add(dictionaryOpening);

            WalkGraph(data, type.DictionaryEntry.ValueType, level + 1,
                x =>
                {
                    x.Name = type.DictionaryEntry.KeyName ?? 
                        _configuration.DefaultDictionaryKeyName;
                    x.IsDictionaryEntry = true;
                    if (type.DictionaryEntry.ValueComments != null)
                        x.Comments = type.DictionaryEntry.ValueComments.TransformMarkdownInline();
                    x.DictionaryKey = new Key
                    {
                        TypeName = type.DictionaryEntry.KeyType.Name,
                        Options = WalkOptions(type.DictionaryEntry.KeyType),
                        Comments = type.DictionaryEntry.KeyComments.TransformMarkdownInline()
                    };
                },
                x =>
                {
                    x.Name = _configuration.DefaultDictionaryKeyName;
                    x.IsDictionaryEntry = true;
                });

            var dictionaryClosing = new BodyLineItem
            {
                Name = type.Name,
                Whitespace = Whitespace.Repeat(level),
                IsClosing = true,
                IsDictionary = true
            };

            if (closing != null) closing(dictionaryClosing);

            data.Add(dictionaryClosing);
        }
        private void WalkArray(List<BodyLineItem> data, DataType type, int level,
            Action<BodyLineItem> opening = null,
            Action<BodyLineItem> closing = null)
        {
            var arrayOpening = new BodyLineItem
            {
                Name = type.Name,
                LongNamespace = type.LongNamespace,
                ShortNamespace = type.ShortNamespace,
                Comments = type.Comments.TransformMarkdownInline(),
                Whitespace = Whitespace.Repeat(level),
                IsOpening = true,
                IsArray = true
            };

            if (opening != null) opening(arrayOpening);

            data.Add(arrayOpening);

            WalkGraph(data, type.ArrayItem.Type, level + 1,
                x =>
                {
                    if (type.ArrayItem != null)
                    {
                        if (type.ArrayItem.Name != null)
                            x.Name = type.ArrayItem.Name;
                        if (type.ArrayItem.Comments != null)
                            x.Comments = type.ArrayItem.Comments.TransformMarkdownInline();
                    }
                },
                x =>
                {
                    if (type.ArrayItem != null && type.ArrayItem.Name != null)
                            x.Name = type.ArrayItem.Name;
                });

            var arrayClosing = new BodyLineItem
            {
                Name = type.Name,
                Whitespace = Whitespace.Repeat(level),
                IsClosing = true,
                IsArray = true
            };

            if (closing != null) closing(arrayClosing);

            data.Add(arrayClosing);
        }
 private static Enumeration WalkOptions(DataType type, 
     Action<Enumeration> whenOptions = null)
 {
     if (type.Options == null) return null;
     var enumeration = new Enumeration
     {
         Name = type.Options.Name,
         Comments = type.Options.Comments,
         Options = new List<Option>(type.Options.Options.Select(x => new Option
         {
             Name = x.Name == x.Value ? null : x.Name,
             Value = x.Value,
             Comments = x.Comments.TransformMarkdownInline()
         }))
     };
     if (whenOptions != null) whenOptions(enumeration);
     return enumeration;
 }