예제 #1
0
        //Abstrafting
        public override OutputFileAbstraction GetAbstraction()
        {
            //If external
            if (this.HasCustomMap)
            {
                return(null);
            }

            //Static
            if (TypeSymbol.IsStatic)
            {
                return(null);
            }

            var abstraction = new ModelAbstraction();

            abstraction.Path      = AbstractPath;
            abstraction.Fields    = new List <FieldAbstraction>();
            abstraction.AllFields = new List <FieldAbstraction>();


            var context = new ResolutionContext(this);

            abstraction.Type = TypeResolver.Resolve(TypeSymbol, context, true);
            //Members
            var currentTypeSymbol           = TypeSymbol;
            HashSet <string> existingFields = new HashSet <string>();

            do
            {
                foreach (var m in currentTypeSymbol.GetMembers())
                {
                    if (existingFields.Contains(m.Name))
                    {
                        continue;
                    }
                    if (m.Kind != SymbolKind.Field && m.Kind != SymbolKind.Property)
                    {
                        continue;
                    }
                    if (m.IsStatic)
                    {
                        continue;
                    }
                    if (m.DeclaredAccessibility != Accessibility.Public)
                    {
                        continue;
                    }

                    var fieldAbstraction = new FieldAbstraction();

                    var prop       = m as IPropertySymbol;
                    var isNullable = TypeResolver.IsNullable(prop.Type) || !prop.Type.IsValueType;
                    var name       = Options.KeepPropsCase ? m.Name : m.Name.ToCamelCase();

                    var summary = prop.GetDocumentationCommentXml();
                    if (!string.IsNullOrWhiteSpace(summary))
                    {
                        summary = summary.Split("<summary>").Last().Split("</summary>").First().Trim();
                        fieldAbstraction.Summary = summary;
                    }

                    var typeResolution = TypeResolver.Resolve(prop.Type, context);

                    fieldAbstraction.IsNullable      = isNullable;
                    fieldAbstraction.Name            = name;
                    fieldAbstraction.TypeDeclaration = typeResolution.Declaration;
                    fieldAbstraction.TypeResolution  = typeResolution;


                    //fieldAbstraction.Attributes = m.GetAttributes().Select(a => new AttributeAbstraction {
                    //    ConstructedFrom = a.AttributeClass.ConstructedFrom.ToString(),
                    //    NamedArguments = a.NamedArguments
                    //    .Select(na => new KeyValuePair<string, NamedArgumentAbstraction>(
                    //        na.Key,
                    //        new NamedArgumentAbstraction
                    //        {
                    //            Kind = na.Value.Kind.ToString(),
                    //            Value = na.Value.Value,
                    //            IsNull = na.Value.IsNull
                    //        }
                    //    ))
                    //    .ToList()
                    //}).ToList();
                    fieldAbstraction.Attributes = new List <AttributeAbstraction>();
                    foreach (var attr in m.GetAttributes())
                    {
                        var attrAbstraction = new AttributeAbstraction();
                        //attrAbstraction.ArgumentsExpressions = new List<string>();
                        attrAbstraction.Arguments = new List <AttributeArgumentAbstraction>();
                        if (attr.ApplicationSyntaxReference == null) //From assembly
                        {
                            attrAbstraction.Name = attr.AttributeClass.Name;
                            if (attrAbstraction.Name.EndsWith("Attribute"))
                            {
                                attrAbstraction.Name = attrAbstraction.Name.Substring(0, attrAbstraction.Name.Length - 9);
                            }

                            foreach (var cArg in attr.ConstructorArguments)
                            {
                                attrAbstraction.Arguments.Add(new AttributeArgumentAbstraction
                                {
                                    Value = cArg.Value.ToString()
                                });
                                //attrAbstraction.ArgumentsExpressions.Add(cArg.Value.ToString());
                            }

                            foreach (var nArg in attr.NamedArguments)
                            {
                                attrAbstraction.Arguments.Add(new AttributeArgumentAbstraction
                                {
                                    //IsNull = nArg.Value.IsNull,
                                    //Kind = nArg.Value.Kind.ToString(),
                                    Name  = nArg.Key,
                                    Value = nArg.Value.Value.ToString(),
                                });
                                //attrAbstraction.ArgumentsExpressions.Add($"{nArg.Key} = {nArg.Value.Value.ToString()}");
                            }
                        }
                        else //From Code
                        {
                            var attrSyntax = (attr.ApplicationSyntaxReference.GetSyntax() as AttributeSyntax);
                            attrAbstraction.Name = attrSyntax.Name.ToString();
                            //attrAbstraction.NamedArguments = new List<KeyValuePair<string, NamedArgumentAbstraction>>();
                            //attrAbstraction.NamedArguments = new Dictionary<string, NamedArgumentAbstraction>();
                            if (attrSyntax.ArgumentList != null)
                            {
                                foreach (var arg in attrSyntax.ArgumentList.Arguments)
                                {
                                    if (arg.NameEquals != null)
                                    {
                                        attrAbstraction.Arguments.Add(new AttributeArgumentAbstraction
                                        {
                                            Name  = arg.NameEquals.Name.Identifier.ValueText,
                                            Value = arg.Expression.ToFullString()
                                        });
                                    }
                                    else
                                    {
                                    }
                                    //attrAbstraction.ArgumentsExpressions.Add(arg.ToFullString());
                                    attrAbstraction.Arguments.Add(new AttributeArgumentAbstraction
                                    {
                                        Value = arg.ToFullString()
                                    });
                                }
                            }
                        }
                        fieldAbstraction.Attributes.Add(attrAbstraction);
                    }

                    abstraction.AllFields.Add(fieldAbstraction);
                    if (currentTypeSymbol == TypeSymbol)
                    {
                        abstraction.Fields.Add(fieldAbstraction);
                    }
                }
                currentTypeSymbol = currentTypeSymbol.BaseType;
            } while (currentTypeSymbol != null);

            abstraction.Imports = context.GetImports();

            return(abstraction);
        }
예제 #2
0
        private (string file, string content) GenerateOutputModule()
        {
            //var hasConsts = false;
            //var subClasses = new List<INamedTypeSymbol>();
            var sb      = new StringBuilder();
            var context = new ResolutionContext(this);
            var level   = 0;

            if (!TypeSymbol.IsStatic)
            {
                string inheritance = "";

                if (TypeSymbol.BaseType != null && TypeSymbol.BaseType.SpecialType != SpecialType.System_Object)
                {
                    var inheritanceTypeResolution = TypeResolver.Resolve(TypeSymbol.BaseType, context);
                    if (inheritanceTypeResolution.IsAny)
                    {
                        if (inheritanceTypeResolution.Declaration.Contains("/*"))
                        {
                            inheritance = $"/*extends {inheritanceTypeResolution.Declaration.Replace("any/*", "").Replace("*/", "")}*/";
                        }
                    }
                    else
                    {
                        inheritance = $"extends {inheritanceTypeResolution.Declaration} ";
                    }
                }

                string genericArguments = "";
                if (TypeSymbol.TypeArguments.Any())
                {
                    genericArguments = $"<{string.Join(", ", TypeSymbol.TypeArguments.Select(t => t.Name))}>";
                }

                sb.AppendLine(level, $"export interface {ClassName}{genericArguments} {inheritance}{{");
                foreach (var m in TypeSymbol.GetMembers())
                {
                    if (m.Kind == SymbolKind.NamedType)
                    {
                        //subClasses.Add(m as INamedTypeSymbol);
                        continue;
                    }
                    if (m.IsStatic)
                    {
                        //if (m.Kind == SymbolKind.Field && (m as IFieldSymbol).IsConst)
                        //{
                        //    hasConsts = true;
                        //}
                        continue;
                    }
                    if (m.Kind != SymbolKind.Property)
                    {
                        continue;
                    }
                    if (m.DeclaredAccessibility != Accessibility.Public)
                    {
                        continue;
                    }
                    var prop       = m as IPropertySymbol;
                    var isNullable = TypeResolver.IsNullable(prop.Type) || !prop.Type.IsValueType;
                    var name       = Options.KeepPropsCase ? m.Name : m.Name.ToCamelCase();

                    var summary = prop.GetDocumentationCommentXml();
                    if (!string.IsNullOrWhiteSpace(summary))
                    {
                        summary = summary.Split("<summary>").Last().Split("</summary>").First().Trim();
                        sb.AppendLine(level + 1, "/**");
                        var lines = summary.Split(System.Environment.NewLine);
                        foreach (var l in lines)
                        {
                            sb.AppendLine(level + 1, $"*{l.Trim()}");
                        }
                        sb.AppendLine(level + 1, "**/");
                    }

                    sb.AppendLine(level + 1, $"{name}{(isNullable ? "?" : "")}: {TypeResolver.Resolve(prop.Type, context).Declaration};");
                }
                sb.AppendLine(level, "}");

                //if (hasConsts)
                //{
                //    sb.AppendLine();
                //}
            }
            //else
            //{
            //    hasConsts = true;
            //}

            ////Static part
            //if (hasConsts
            //             //removing const support for now
            //             //If we enable it again, we should merge these members with KeysAndNames...
            //             && false
            //             ) {
            //	//https://github.com/Microsoft/TypeScript/issues/17372
            //	//Currently we can't merge namespaces and const enums.
            //	//This is supposed to be a bug.
            //	//Besides, even if this is fixed, I think enums will never be mergeable with interfaces,
            //	//so I think it will be always necessary to discriminate with something like $.
            //	//$ can't be used in C# classes, so will never happen a conflict.
            //	//We transpile C# Consts to TypeScript const enums because this is currently
            //	//the only way to inline values. Consts values direclty inside namespaces/modules are not inlined...
            //	//---R: Now, supporting only scoped types, maybe values dont need to be inlined...

            //	sb.AppendLine(level, $"export class {ClassName} {{");
            //	level++;
            //	foreach (var m in TypeSymbol.GetMembers()) {
            //		var fieldSymbol = (m as IFieldSymbol);
            //		if (fieldSymbol != null && fieldSymbol.IsConst) {
            //			//Consts names should not be changed, they are commonly uppercased both in client and server...
            //			var name = m.Name;
            //			sb.AppendLine(level, $"static readonly {name} = {JsonConvert.SerializeObject(fieldSymbol.ConstantValue)};");
            //		}
            //	}
            //	level--;
            //	sb.AppendLine(level, "}");
            //}


            level--;

            AppendKeysAndNames(sb);

            sb.Insert(0, context.GetImportsText());
            string content = sb.ToString();

            return(OutputFilePath, content);
        }