public void AddProperties(StringBuilderWrapper sb, MetadataType type, bool includeResponseStatus)
        {
            var makeExtensible = Config.MakeDataContractsExtensible && type.Inherits == null;

            var @virtual = Config.MakeVirtual && !type.IsInterface() ? "virtual " : "";
            var wasAdded = false;

            var dataMemberIndex = 1;
            if (type.Properties != null)
            {
                foreach (var prop in type.Properties)
                {
                    if (wasAdded) sb.AppendLine();

                    var propType = Type(prop.Type, prop.GenericArgs, includeNested:true);
                    wasAdded = AppendComments(sb, prop.Description);
                    wasAdded = AppendDataMember(sb, prop.DataMember, dataMemberIndex++) || wasAdded;
                    wasAdded = AppendAttributes(sb, prop.Attributes) || wasAdded;
                    var visibility = type.IsInterface() ? "" : "public ";
                    sb.AppendLine("{0}{1}{2} {3} {{ get; set; }}"
                        .Fmt(visibility, @virtual, propType, prop.Name.SafeToken()));
                }
            }

            if (type.IsInterface())
                return;

            if (includeResponseStatus)
            {
                if (wasAdded) sb.AppendLine();
                wasAdded = true;

                AppendDataMember(sb, null, dataMemberIndex++);
                sb.AppendLine("public {0}ResponseStatus ResponseStatus {{ get; set; }}".Fmt(@virtual));
            }

            if (makeExtensible
                && (type.Properties == null
                    || type.Properties.All(x => x.Name != "ExtensionData")))
            {
                if (wasAdded) sb.AppendLine();
                wasAdded = true;

                sb.AppendLine("public {0}ExtensionDataObject ExtensionData {{ get; set; }}".Fmt(@virtual));
            }
        }
        public void AddProperties(StringBuilderWrapper sb, MetadataType type, bool includeResponseStatus)
        {
            var makeExtensible = Config.MakeDataContractsExtensible && type.Inherits == null;

            var wasAdded = false;

            var dataMemberIndex = 1;
            if (type.Properties != null)
            {
                foreach (var prop in type.Properties)
                {
                    if (wasAdded) sb.AppendLine();

                    var propType = Type(prop.Type, prop.GenericArgs);
                    wasAdded = AppendComments(sb, prop.Description);
                    wasAdded = AppendDataMember(sb, prop.DataMember, dataMemberIndex++) || wasAdded;
                    wasAdded = AppendAttributes(sb, prop.Attributes) || wasAdded;

                    if (!type.IsInterface())
                    {
                        sb.AppendLine("member val {1}:{0} = {2} with get,set".Fmt(
                            propType, prop.Name.SafeToken(), GetDefaultLiteral(prop, type)));
                    }
                    else
                    {
                        sb.AppendLine("abstract {1}:{0} with get,set".Fmt(
                            propType, prop.Name.SafeToken()));
                    }
                }
            }

            if (type.IsInterface())
                return;

            if (includeResponseStatus)
            {
                if (wasAdded) sb.AppendLine();
                wasAdded = true;

                AppendDataMember(sb, null, dataMemberIndex++);
                sb.AppendLine("member val ResponseStatus:ResponseStatus = null with get,set");
            }

            if (makeExtensible
                && (type.Properties == null
                    || type.Properties.All(x => x.Name != "ExtensionData")))
            {
                if (wasAdded) sb.AppendLine();
                wasAdded = true;

                sb.AppendLine("member val ExtensionData:ExtensionDataObject = null with get,set");
            }
        }
Exemple #3
0
        public void AddProperties(StringBuilderWrapper sb, MetadataType type)
        {
            var makeExtensible = Config.MakeDataContractsExtensible && type.Inherits == null;

            var @virtual = Config.MakeVirtual ? "virtual " : "";
            var wasAdded = false;

            var dataMemberIndex = 1;
            if (type.Properties != null)
            {
                foreach (var prop in type.Properties)
                {
                    if (wasAdded) sb.AppendLine();

                    var propType = Type(prop.Type, prop.GenericArgs);
                    wasAdded = AppendDataMember(sb, prop.DataMember, dataMemberIndex++);
                    wasAdded = AppendAttributes(sb, prop.Attributes) || wasAdded;
                    sb.AppendLine("public {0}{1} {2} {{ get; set; }}".Fmt(@virtual, propType, prop.Name.SafeToken()));
                }
            }

            if (Config.AddResponseStatus
                && (type.Properties == null
                    || type.Properties.All(x => x.Name != "ResponseStatus")))
            {
                if (wasAdded) sb.AppendLine();
                wasAdded = true;

                AppendDataMember(sb, null, dataMemberIndex++);
                sb.AppendLine("public {0}ResponseStatus ResponseStatus {{ get; set; }}".Fmt(@virtual));
            }

            if (makeExtensible
                && (type.Properties == null
                    || type.Properties.All(x => x.Name != "ExtensionData")))
            {
                if (wasAdded) sb.AppendLine();
                wasAdded = true;

                sb.AppendLine("public {0}ExtensionDataObject ExtensionData {{ get; set; }}".Fmt(@virtual));
            }
        }
        public string GetCode(MetadataTypes metadata, IRequest request, INativeTypesMetadata nativeTypes)
        {
            var typeNamespaces = new HashSet<string>();
            RemoveIgnoredTypes(metadata);
            metadata.Types.Each(x => typeNamespaces.Add(x.Namespace));
            metadata.Operations.Each(x => typeNamespaces.Add(x.Request.Namespace));

            var defaultImports = new List<string>(DefaultImports);
            if (!Config.DefaultImports.IsEmpty())
            {
                defaultImports = Config.DefaultImports;
            }
            else if (ReferencesGson(metadata))
            {
                if (!defaultImports.Contains(GSonAnnotationsNamespace))
                    defaultImports.Add(GSonAnnotationsNamespace);
                if (!defaultImports.Contains(GSonReflectNamespace))
                    defaultImports.Add(GSonReflectNamespace);
            }

            var defaultNamespace = Config.GlobalNamespace ?? DefaultGlobalNamespace;

            Func<string, string> defaultValue = k =>
                request.QueryString[k].IsNullOrEmpty() ? "//" : "";

            var sbInner = StringBuilderCache.Allocate();
            var sb = new StringBuilderWrapper(sbInner);
            sb.AppendLine("/* Options:");
            sb.AppendLine("Date: {0}".Fmt(DateTime.Now.ToString("s").Replace("T", " ")));
            sb.AppendLine("Version: {0}".Fmt(Env.ServiceStackVersion));
            sb.AppendLine("Tip: {0}".Fmt(HelpMessages.NativeTypesDtoOptionsTip.Fmt("//")));
            sb.AppendLine("BaseUrl: {0}".Fmt(Config.BaseUrl));
            sb.AppendLine();
            sb.AppendLine("{0}Package: {1}".Fmt(defaultValue("Package"), Config.Package));
            sb.AppendLine("{0}GlobalNamespace: {1}".Fmt(defaultValue("GlobalNamespace"), defaultNamespace));
            sb.AppendLine("{0}AddPropertyAccessors: {1}".Fmt(defaultValue("AddPropertyAccessors"), Config.AddPropertyAccessors));
            sb.AppendLine("{0}SettersReturnThis: {1}".Fmt(defaultValue("SettersReturnThis"), Config.SettersReturnThis));
            sb.AppendLine("{0}AddServiceStackTypes: {1}".Fmt(defaultValue("AddServiceStackTypes"), Config.AddServiceStackTypes));
            sb.AppendLine("{0}AddResponseStatus: {1}".Fmt(defaultValue("AddResponseStatus"), Config.AddResponseStatus));
            sb.AppendLine("{0}AddDescriptionAsComments: {1}".Fmt(defaultValue("AddDescriptionAsComments"), Config.AddDescriptionAsComments));
            sb.AppendLine("{0}AddImplicitVersion: {1}".Fmt(defaultValue("AddImplicitVersion"), Config.AddImplicitVersion));
            sb.AppendLine("{0}IncludeTypes: {1}".Fmt(defaultValue("IncludeTypes"), Config.IncludeTypes.Safe().ToArray().Join(",")));
            sb.AppendLine("{0}ExcludeTypes: {1}".Fmt(defaultValue("ExcludeTypes"), Config.ExcludeTypes.Safe().ToArray().Join(",")));
            sb.AppendLine("{0}TreatTypesAsStrings: {1}".Fmt(defaultValue("TreatTypesAsStrings"), Config.TreatTypesAsStrings.Safe().ToArray().Join(",")));
            sb.AppendLine("{0}DefaultImports: {1}".Fmt(defaultValue("DefaultImports"), defaultImports.Join(",")));

            sb.AppendLine("*/");
            sb.AppendLine();

            foreach (var typeName in Config.TreatTypesAsStrings.Safe())
            {
                TypeAliases[typeName] = "String";
            }

            if (Config.Package != null)
            {
                sb.AppendLine("package {0};".Fmt(Config.Package));
                sb.AppendLine();
            }

            string lastNS = null;

            var existingTypes = new HashSet<string>();

            var requestTypes = metadata.Operations.Select(x => x.Request).ToHashSet();
            var requestTypesMap = metadata.Operations.ToSafeDictionary(x => x.Request);
            var responseTypes = metadata.Operations
                .Where(x => x.Response != null)
                .Select(x => x.Response).ToHashSet();
            var types = metadata.Types.ToHashSet();

            AllTypes.AddRange(requestTypes);
            AllTypes.AddRange(responseTypes);
            AllTypes.AddRange(types);

            //TypeScript doesn't support reusing same type name with different generic airity
            var conflictPartialNames = AllTypes.Map(x => x.Name).Distinct()
                .GroupBy(g => g.LeftPart('`'))
                .Where(g => g.Count() > 1)
                .Select(g => g.Key)
                .ToList();

            this.conflictTypeNames = AllTypes
                .Where(x => conflictPartialNames.Any(name => x.Name.StartsWith(name)))
                .Map(x => x.Name);

            defaultImports.Each(x => sb.AppendLine("import {0};".Fmt(x)));
            sb.AppendLine();

            sb.AppendLine("public class {0}".Fmt(defaultNamespace.SafeToken()));
            sb.AppendLine("{");

            //ServiceStack core interfaces
            foreach (var type in AllTypes)
            {
                var fullTypeName = type.GetFullName();
                if (requestTypes.Contains(type))
                {
                    if (!existingTypes.Contains(fullTypeName))
                    {
                        MetadataType response = null;
                        MetadataOperationType operation;
                        if (requestTypesMap.TryGetValue(type, out operation))
                        {
                            response = operation.Response;
                        }

                        lastNS = AppendType(ref sb, type, lastNS,
                            new CreateTypeOptions
                            {
                                ImplementsFn = () =>
                                {
                                    if (!Config.AddReturnMarker
                                        && !type.ReturnVoidMarker
                                        && type.ReturnMarkerTypeName == null)
                                        return null;

                                    if (type.ReturnVoidMarker)
                                        return "IReturnVoid";
                                    if (type.ReturnMarkerTypeName != null)
                                        return Type("IReturn`1", new[] { Type(type.ReturnMarkerTypeName) });
                                    return response != null
                                        ? Type("IReturn`1", new[] { Type(response.Name, response.GenericArgs) })
                                        : null;
                                },
                                IsRequest = true,
                            });

                        existingTypes.Add(fullTypeName);
                    }
                }
                else if (responseTypes.Contains(type))
                {
                    if (!existingTypes.Contains(fullTypeName)
                        && !Config.IgnoreTypesInNamespaces.Contains(type.Namespace))
                    {
                        lastNS = AppendType(ref sb, type, lastNS,
                            new CreateTypeOptions
                            {
                                IsResponse = true,
                            });

                        existingTypes.Add(fullTypeName);
                    }
                }
                else if (types.Contains(type) && !existingTypes.Contains(fullTypeName))
                {
                    lastNS = AppendType(ref sb, type, lastNS,
                        new CreateTypeOptions { IsType = true });

                    existingTypes.Add(fullTypeName);
                }
            }

            sb.AppendLine();
            sb.AppendLine("}");

            return StringBuilderCache.ReturnAndFree(sbInner);
        }
        public void AppendDataContract(StringBuilderWrapper sb, MetadataDataContract dcMeta)
        {
            if (dcMeta == null)
            {
                if (Config.AddDataContractAttributes)
                    sb.AppendLine("@DataContract()");
                return;
            }

            var dcArgs = "";
            if (dcMeta.Name != null || dcMeta.Namespace != null)
            {
                if (dcMeta.Name != null)
                    dcArgs = "Name={0}".Fmt(dcMeta.Name.QuotedSafeValue());

                if (dcMeta.Namespace != null)
                {
                    if (dcArgs.Length > 0)
                        dcArgs += ", ";

                    dcArgs += "Namespace={0}".Fmt(dcMeta.Namespace.QuotedSafeValue());
                }

                dcArgs = "({0})".Fmt(dcArgs);
            }
            sb.AppendLine("@DataContract{0}".Fmt(dcArgs));
        }
        public bool AppendAttributes(StringBuilderWrapper sb, List<MetadataAttribute> attributes)
        {
            if (attributes == null || attributes.Count == 0) return false;

            var existingAttrs = new HashSet<string>();

            foreach (var attr in attributes)
            {
                //Java 7 doesn't allow repeating attrs
                var prefix = existingAttrs.Contains(attr.Name)
                    ? "// "
                    : "";
                existingAttrs.Add(attr.Name);

                if ((attr.Args == null || attr.Args.Count == 0)
                    && (attr.ConstructorArgs == null || attr.ConstructorArgs.Count == 0))
                {
                    sb.AppendLine(prefix + "@{0}()".Fmt(attr.Name));
                }
                else
                {
                    var args = StringBuilderCacheAlt.Allocate();
                    if (attr.ConstructorArgs != null)
                    {
                        if (attr.ConstructorArgs.Count > 1)
                            prefix = "// ";

                        foreach (var ctorArg in attr.ConstructorArgs)
                        {
                            if (args.Length > 0)
                                args.Append(", ");
                            args.Append("{0}".Fmt(TypeValue(ctorArg.Type, ctorArg.Value)));
                        }
                    }
                    else if (attr.Args != null)
                    {
                        foreach (var attrArg in attr.Args)
                        {
                            if (args.Length > 0)
                                args.Append(", ");
                            args.Append("{0}={1}".Fmt(attrArg.Name, TypeValue(attrArg.Type, attrArg.Value)));
                        }
                    }
                    sb.AppendLine(prefix + "@{0}({1})".Fmt(attr.Name, StringBuilderCacheAlt.ReturnAndFree(args)));
                }
            }

            return true;
        }
        public void AppendComments(StringBuilderWrapper sb, string desc)
        {
            if (desc == null) return;

            sb.AppendLine("/**");
            sb.AppendLine("* {0}".Fmt(desc.SafeComment()));
            sb.AppendLine("*/");
        }
        public void AddProperties(StringBuilderWrapper sb, MetadataType type,
            bool initCollections, bool includeResponseStatus)
        {
            var wasAdded = false;

            var dataMemberIndex = 1;
            foreach (var prop in type.Properties.Safe())
            {
                if (wasAdded) sb.AppendLine();

                var propTypeName = Type(prop.Type, prop.GenericArgs);
                var propType = FindType(prop.Type, prop.TypeNamespace, prop.GenericArgs);
                var optional = "";
                var defaultValue = "";
                if (propTypeName.EndsWith("?"))
                {
                    propTypeName = propTypeName.Substring(0, propTypeName.Length - 1);
                    optional = "?";
                }
                if (Config.MakePropertiesOptional)
                {
                    optional = "?";
                }

                if (prop.Attributes.Safe().FirstOrDefault(x => x.Name == "Required") != null)
                {
                    optional = "?"; //always use optional
                }

                if (prop.IsArray())
                {
                    optional = "";
                    defaultValue = " = []";
                }
                else if (initCollections && !prop.GenericArgs.IsEmpty())
                {
                    if (ArrayTypes.Contains(prop.Type))
                    {
                        optional = "";
                        defaultValue = " = []";
                    }
                    if (DictionaryTypes.Contains(prop.Type))
                    {
                        optional = "";
                        defaultValue = " = [:]";
                    }
                }

                if (propType.IsInterface() || IgnorePropertyNames.Contains(prop.Name))
                {
                    sb.AppendLine("//{0}:{1} ignored. Swift doesn't support interface properties"
                        .Fmt(prop.Name.SafeToken().PropertyStyle(), propTypeName));
                    continue;
                }
                else if (IgnorePropertyTypeNames.Contains(propTypeName))
                {
                    sb.AppendLine("//{0}:{1} ignored. Type could not be extended in Swift"
                        .Fmt(prop.Name.SafeToken().PropertyStyle(), propTypeName));
                    continue;
                }

                wasAdded = AppendDataMember(sb, prop.DataMember, dataMemberIndex++);
                wasAdded = AppendAttributes(sb, prop.Attributes) || wasAdded;

                if (type.IsInterface())
                {
                    sb.AppendLine("var {0}:{1}{2} {{ get set }}".Fmt(
                        prop.Name.SafeToken().PropertyStyle(), propTypeName, optional));
                }
                else
                {
                    sb.AppendLine("public var {0}:{1}{2}{3}".Fmt(
                        prop.Name.SafeToken().PropertyStyle(), propTypeName, optional, defaultValue));
                }
            }

            if (includeResponseStatus)
            {
                if (wasAdded) sb.AppendLine();

                AppendDataMember(sb, null, dataMemberIndex++);
                sb.AppendLine("public var {0}:ResponseStatus?".Fmt(typeof(ResponseStatus).Name.PropertyStyle()));
            }
        }
        private void AddEnumExtension(ref StringBuilderWrapper sbExt, MetadataType type)
        {
            if (type.EnumNames == null) return;

            sbExt.AppendLine();
            var typeName = Type(type.Name, type.GenericArgs);
            sbExt.AppendLine("extension {0} : StringSerializable".Fmt(typeName));
            sbExt.AppendLine("{");
            sbExt = sbExt.Indent();

            sbExt.AppendLine("public static var typeName:String {{ return \"{0}\" }}".Fmt(typeName));

            //toJson()
            sbExt.AppendLine("public func toJson() -> String {");
            sbExt = sbExt.Indent();
            sbExt.AppendLine("return jsonStringRaw(toString())");
            sbExt = sbExt.UnIndent();
            sbExt.AppendLine("}");

            //toString()
            sbExt.AppendLine("public func toString() -> String {");
            sbExt = sbExt.Indent();
            sbExt.AppendLine("switch self {");
            foreach (var name in type.EnumNames)
            {
                sbExt.AppendLine("case .{0}: return \"{0}\"".Fmt(name));
            }
            sbExt.AppendLine("}");
            sbExt = sbExt.UnIndent();
            sbExt.AppendLine("}");

            //fromString()
            sbExt.AppendLine("public static func fromString(strValue:String) -> {0}? {{".Fmt(typeName));
            sbExt = sbExt.Indent();

            sbExt.AppendLine("switch strValue {");
            foreach (var name in type.EnumNames)
            {
                sbExt.AppendLine("case \"{0}\": return .{0}".Fmt(name));
            }
            sbExt.AppendLine("default: return nil");

            sbExt.AppendLine("}");
            sbExt = sbExt.UnIndent();
            sbExt.AppendLine("}");

            //fromObject()
            sbExt.AppendLine("public static func fromObject(any:AnyObject) -> {0}? {{".Fmt(typeName));
            sbExt = sbExt.Indent();
            sbExt.AppendLine("switch any {");
            sbExt.AppendLine("case let i as Int: return {0}(rawValue: i)".Fmt(typeName));
            sbExt.AppendLine("case let s as String: return fromString(s)");
            sbExt.AppendLine("default: return nil");
            sbExt.AppendLine("}");
            sbExt = sbExt.UnIndent();
            sbExt.AppendLine("}");

            sbExt = sbExt.UnIndent();
            sbExt.AppendLine("}");
        }
        private string AppendType(ref StringBuilderWrapper sb, MetadataType type, string lastNS,
            CreateTypeOptions options)
        {
            sb.AppendLine();
            AppendComments(sb, type.Description);
            if (type.Routes != null)
            {
                AppendAttributes(sb, type.Routes.ConvertAll(x => x.ToMetadataAttribute()));
            }
            AppendAttributes(sb, type.Attributes);
            AppendDataContract(sb, type.DataContract);

            if (type.IsEnum.GetValueOrDefault())
            {
                if (type.IsEnumInt.GetValueOrDefault() || type.EnumNames.IsEmpty())
                {
                    var typeDeclaration = !Config.ExportAsTypes
                        ? "enum"
                        : "export enum";

                    sb.AppendLine("{0} {1}".Fmt(typeDeclaration, Type(type.Name, type.GenericArgs)));
                    sb.AppendLine("{");
                    sb = sb.Indent();

                    if (type.EnumNames != null)
                    {
                        for (var i = 0; i < type.EnumNames.Count; i++)
                        {
                            var name = type.EnumNames[i];
                            var value = type.EnumValues != null ? type.EnumValues[i] : null;

                            sb.AppendLine(value == null //Enum Value's are not impacted by JS Style
                                ? "{0},".Fmt(name)
                                : "{0} = {1},".Fmt(name, value));
                        }
                    }

                    sb = sb.UnIndent();
                    sb.AppendLine("}");
                }
                else
                {
                    var sbType = StringBuilderCache.Allocate();

                    var typeDeclaration = !Config.ExportAsTypes
                        ? "type"
                        : "export type";

                    sbType.Append("{0} {1} = ".Fmt(typeDeclaration, Type(type.Name, type.GenericArgs)));

                    for (var i = 0; i < type.EnumNames.Count; i++)
                    {
                        if (i > 0)
                            sbType.Append(" | ");

                        sbType.Append('"').Append(type.EnumNames[i]).Append('"');
                    }

                    sbType.Append(";");

                    sb.AppendLine(StringBuilderCache.ReturnAndFree(sbType));
                }
            }
            else
            {
                var extends = new List<string>();

                //: BaseClass, Interfaces
                if (type.Inherits != null)
                    extends.Add(Type(type.Inherits).InDeclarationType());

                string responseTypeExpression = null;

                var interfaces = new List<string>();
                var implStr = options.ImplementsFn?.Invoke();
                if (!string.IsNullOrEmpty(implStr))
                {
                    interfaces.Add(implStr);

                    if (implStr.StartsWith("IReturn<"))
                    {
                        var types = implStr.RightPart('<');
                        var returnType = types.Substring(0, types.Length - 1);

                        if (returnType == "any")
                            returnType = "Object";

                        // This is to avoid invalid syntax such as "return new string()"
                        string replaceReturnType;
                        if (primitiveDefaultValues.TryGetValue(returnType, out replaceReturnType))
                            returnType = replaceReturnType;

                        responseTypeExpression = replaceReturnType == null ?
                            "createResponse() {{ return new {0}(); }}".Fmt(returnType) :
                            "createResponse() {{ return {0}; }}".Fmt(returnType);
                    }
                    else if (implStr == "IReturnVoid")
                    {
                        responseTypeExpression = "createResponse() {}";
                    }
                }

                var isClass = Config.ExportAsTypes && !type.IsInterface.GetValueOrDefault();
                var extend = extends.Count > 0
                    ? " extends " + extends[0]
                    : "";

                if (interfaces.Count > 0)
                {
                    if (isClass)
                    {
                        extend += " implements " + string.Join(", ", interfaces.ToArray());
                    }
                    else
                    {
                        if (string.IsNullOrEmpty(extend))
                            extend = " extends ";
                        else
                            extend += ", ";

                        extend += string.Join(", ", interfaces.ToArray());
                    }
                }

                var typeDeclaration = !Config.ExportAsTypes
                    ? "interface"
                    : $"export {(isClass ? "class" : "interface")}"; 

                sb.AppendLine("{0} {1}{2}".Fmt(typeDeclaration, Type(type.Name, type.GenericArgs), extend));
                sb.AppendLine("{");

                sb = sb.Indent();

                var addVersionInfo = Config.AddImplicitVersion != null && options.IsRequest;
                if (addVersionInfo)
                {
                    sb.AppendLine("{0}{1}: number; //{2}".Fmt(
                        "Version".PropertyStyle(), isClass ? "" : "?", Config.AddImplicitVersion));
                }

                AddProperties(sb, type,
                    includeResponseStatus: Config.AddResponseStatus && options.IsResponse
                        && type.Properties.Safe().All(x => x.Name != typeof(ResponseStatus).Name));

                if (Config.ExportAsTypes && responseTypeExpression != null)
                {
                    sb.AppendLine(responseTypeExpression);
                    sb.AppendLine("getTypeName() {{ return \"{0}\"; }}".Fmt(type.Name));
                }

                sb = sb.UnIndent();
                sb.AppendLine("}");
            }

            return lastNS;
        }
        public string GetCode(MetadataTypes metadata, IRequest request, INativeTypesMetadata nativeTypes)
        {
            var typeNamespaces = new HashSet<string>();
            metadata.RemoveIgnoredTypes(Config);
            metadata.Types.Each(x => typeNamespaces.Add(x.Namespace));
            metadata.Operations.Each(x => typeNamespaces.Add(x.Request.Namespace));

            var defaultImports = !Config.DefaultImports.IsEmpty()
                ? Config.DefaultImports
                : DefaultImports;

            var globalNamespace = Config.GlobalNamespace;

            Func<string, string> defaultValue = k =>
                request.QueryString[k].IsNullOrEmpty() ? "//" : "";

            var sbInner = StringBuilderCache.Allocate();
            var sb = new StringBuilderWrapper(sbInner);
            sb.AppendLine("/* Options:");
            sb.AppendLine("Date: {0}".Fmt(DateTime.Now.ToString("s").Replace("T", " ")));
            sb.AppendLine("Version: {0}".Fmt(Env.ServiceStackVersion));
            sb.AppendLine("Tip: {0}".Fmt(HelpMessages.NativeTypesDtoOptionsTip.Fmt("//")));
            sb.AppendLine("BaseUrl: {0}".Fmt(Config.BaseUrl));
            sb.AppendLine();
            sb.AppendLine("{0}GlobalNamespace: {1}".Fmt(defaultValue("GlobalNamespace"), Config.GlobalNamespace));
            //sb.AppendLine("{0}ExportAsTypes: {1}".Fmt(defaultValue("ExportAsTypes"), Config.ExportAsTypes));
            sb.AppendLine("{0}MakePropertiesOptional: {1}".Fmt(defaultValue("MakePropertiesOptional"), Config.MakePropertiesOptional));
            sb.AppendLine("{0}AddServiceStackTypes: {1}".Fmt(defaultValue("AddServiceStackTypes"), Config.AddServiceStackTypes));
            sb.AppendLine("{0}AddResponseStatus: {1}".Fmt(defaultValue("AddResponseStatus"), Config.AddResponseStatus));
            sb.AppendLine("{0}AddImplicitVersion: {1}".Fmt(defaultValue("AddImplicitVersion"), Config.AddImplicitVersion));
            sb.AppendLine("{0}AddDescriptionAsComments: {1}".Fmt(defaultValue("AddDescriptionAsComments"), Config.AddDescriptionAsComments));
            sb.AppendLine("{0}IncludeTypes: {1}".Fmt(defaultValue("IncludeTypes"), Config.IncludeTypes.Safe().ToArray().Join(",")));
            sb.AppendLine("{0}ExcludeTypes: {1}".Fmt(defaultValue("ExcludeTypes"), Config.ExcludeTypes.Safe().ToArray().Join(",")));
            sb.AppendLine("{0}DefaultImports: {1}".Fmt(defaultValue("DefaultImports"), defaultImports.Join(",")));

            sb.AppendLine("*/");
            sb.AppendLine();

            string lastNS = null;

            var existingTypes = new HashSet<string>();

            var requestTypes = metadata.Operations.Select(x => x.Request).ToHashSet();
            var requestTypesMap = metadata.Operations.ToSafeDictionary(x => x.Request);
            var responseTypes = metadata.Operations
                .Where(x => x.Response != null)
                .Select(x => x.Response).ToHashSet();

            // Base Types need to be written first
            var types = CreateSortedTypeList(metadata.Types);

            allTypes = new List<MetadataType>();
            allTypes.AddRange(types);
            allTypes.AddRange(responseTypes);
            allTypes.AddRange(requestTypes);
            allTypes.RemoveAll(x => x.IgnoreType(Config));

            allTypes = FilterTypes(allTypes);

            //TypeScript doesn't support reusing same type name with different generic airity
            var conflictPartialNames = allTypes.Map(x => x.Name).Distinct()
                .GroupBy(g => g.LeftPart('`'))
                .Where(g => g.Count() > 1)
                .Select(g => g.Key)
                .ToList();

            this.conflictTypeNames = allTypes
                .Where(x => conflictPartialNames.Any(name => x.Name.StartsWith(name)))
                .Map(x => x.Name);

            defaultImports.Each(x => sb.AppendLine("import {0};".Fmt(x)));

            if (!string.IsNullOrEmpty(globalNamespace))
            {
                var moduleDef = Config.ExportAsTypes ? "" : "declare ";
                sb.AppendLine();
                sb.AppendLine("{0}module {1}".Fmt(moduleDef, globalNamespace.SafeToken()));
                sb.AppendLine("{");

                sb = sb.Indent();
            }

            //ServiceStack core interfaces
            foreach (var type in allTypes)
            {
                var fullTypeName = type.GetFullName();
                if (requestTypes.Contains(type))
                {
                    if (!existingTypes.Contains(fullTypeName))
                    {
                        MetadataType response = null;
                        MetadataOperationType operation;
                        if (requestTypesMap.TryGetValue(type, out operation))
                        {
                            response = operation.Response;
                        }

                        lastNS = AppendType(ref sb, type, lastNS,
                            new CreateTypeOptions
                            {
                                ImplementsFn = () =>
                                {
                                    if (!Config.AddReturnMarker
                                        && !type.ReturnVoidMarker
                                        && type.ReturnMarkerTypeName == null)
                                        return null;

                                    if (type.ReturnVoidMarker)
                                        return "IReturnVoid";
                                    if (type.ReturnMarkerTypeName != null)
                                        return Type("IReturn`1", new[] { Type(type.ReturnMarkerTypeName).InDeclarationType() });
                                    return response != null
                                        ? Type("IReturn`1", new[] { Type(response.Name, response.GenericArgs).InDeclarationType() })
                                        : null;
                                },
                                IsRequest = true,
                            });

                        existingTypes.Add(fullTypeName);
                    }
                }
                else if (responseTypes.Contains(type))
                {
                    if (!existingTypes.Contains(fullTypeName)
                        && !Config.IgnoreTypesInNamespaces.Contains(type.Namespace))
                    {
                        lastNS = AppendType(ref sb, type, lastNS,
                            new CreateTypeOptions
                            {
                                IsResponse = true,
                            });

                        existingTypes.Add(fullTypeName);
                    }
                }
                else if (types.Contains(type) && !existingTypes.Contains(fullTypeName))
                {
                    lastNS = AppendType(ref sb, type, lastNS,
                        new CreateTypeOptions { IsType = true });

                    existingTypes.Add(fullTypeName);
                }
            }

            if (!string.IsNullOrEmpty(globalNamespace))
            {
                sb = sb.UnIndent();
                sb.AppendLine();
                sb.AppendLine("}");
            }

            return StringBuilderCache.ReturnAndFree(sbInner);
        }
        public string GetCode(MetadataTypes metadata, IRequest request)
        {
            var namespaces = new HashSet<string>();
            Config.DefaultNamespaces.Each(x => namespaces.Add(x));

            var typeNamespaces = new HashSet<string>();
            metadata.Types.Each(x => typeNamespaces.Add(x.Namespace));
            metadata.Operations.Each(x => typeNamespaces.Add(x.Request.Namespace));

            // Look first for shortest Namespace ending with `ServiceModel` convention, else shortest ns
            var globalNamespace = Config.GlobalNamespace
                ?? typeNamespaces.Where(x => x.EndsWith("ServiceModel"))
                    .OrderBy(x => x).FirstOrDefault()
                ?? typeNamespaces.OrderBy(x => x).First();

            Func<string, string> defaultValue = k =>
                request.QueryString[k].IsNullOrEmpty() ? "//" : "";

            var sb = new StringBuilderWrapper(new StringBuilder());
            sb.AppendLine("(* Options:");
            sb.AppendLine("Date: {0}".Fmt(DateTime.Now.ToString("s").Replace("T", " ")));
            sb.AppendLine("Version: {0}".Fmt(metadata.Version));
            sb.AppendLine("BaseUrl: {0}".Fmt(Config.BaseUrl));
            sb.AppendLine();
            sb.AppendLine("{0}MakeDataContractsExtensible: {1}".Fmt(defaultValue("MakeDataContractsExtensible"), Config.MakeDataContractsExtensible));
            sb.AppendLine("{0}AddReturnMarker: {1}".Fmt(defaultValue("AddReturnMarker"), Config.AddReturnMarker));
            sb.AppendLine("{0}AddDescriptionAsComments: {1}".Fmt(defaultValue("AddDescriptionAsComments"), Config.AddDescriptionAsComments));
            sb.AppendLine("{0}AddDataContractAttributes: {1}".Fmt(defaultValue("AddDataContractAttributes"), Config.AddDataContractAttributes));
            sb.AppendLine("{0}AddIndexesToDataMembers: {1}".Fmt(defaultValue("AddIndexesToDataMembers"), Config.AddIndexesToDataMembers));
            sb.AppendLine("{0}AddResponseStatus: {1}".Fmt(defaultValue("AddResponseStatus"), Config.AddResponseStatus));
            sb.AppendLine("{0}AddImplicitVersion: {1}".Fmt(defaultValue("AddImplicitVersion"), Config.AddImplicitVersion));
            sb.AppendLine("{0}InitializeCollections: {1}".Fmt(defaultValue("InitializeCollections"), Config.InitializeCollections));
            //sb.AppendLine("{0}AddDefaultXmlNamespace: {1}".Fmt(defaultValue("AddDefaultXmlNamespace"), Config.AddDefaultXmlNamespace));
            //sb.AppendLine("{0}DefaultNamespaces: {1}".Fmt(defaultValue("DefaultNamespaces"), Config.DefaultNamespaces.ToArray().Join(", ")));
            sb.AppendLine("*)");
            sb.AppendLine();

            //if (Config.AddDataContractAttributes
            //    && Config.AddDefaultXmlNamespace != null)
            //{
            //    sb.AppendLine();

            //    var list = namespaces.Where(x => !Config.DefaultNamespaces.Contains(x)).ToList();
            //    list.ForEach(x =>
            //        sb.AppendLine("[<assembly: ContractNamespace(\"{0}\", ClrNamespace=\"{1}\")>]"
            //            .Fmt(Config.AddDefaultXmlNamespace, x)));

            //    if (list.Count > 0)
            //    {
            //        sb.AppendLine("do()"); //http://scottseely.com/2009/01/23/f-assembly-level-attributes-assemblyinfo-fs-and-do/
            //    }
            //}
            //sb.AppendLine();

            string lastNS = null;

            var existingOps = new HashSet<string>();

            var requestTypes = metadata.Operations.Select(x => x.Request).ToHashSet();
            var requestTypesMap = metadata.Operations.ToSafeDictionary(x => x.Request);
            var responseTypes = metadata.Operations
                .Where(x => x.Response != null)
                .Select(x => x.Response).ToHashSet();
            var types = metadata.Types.ToHashSet();

            var allTypes = new List<MetadataType>();
            allTypes.AddRange(types);
            allTypes.AddRange(responseTypes);
            allTypes.AddRange(requestTypes);

            var orderedTypes = allTypes.OrderTypesByDeps();

            sb.AppendLine("namespace {0}".Fmt(globalNamespace.SafeToken()));
            sb.AppendLine();
            foreach (var ns in namespaces)
            {
                sb.AppendLine("open " + ns);
            }

            foreach (var type in orderedTypes)
            {
                var fullTypeName = type.GetFullName();
                if (requestTypes.Contains(type))
                {
                    if (!existingOps.Contains(fullTypeName))
                    {
                        MetadataType response = null;
                        MetadataOperationType operation;
                        if (requestTypesMap.TryGetValue(type, out operation))
                        {
                            response = operation.Response;
                        }

                        lastNS = AppendType(ref sb, type, lastNS,
                            new CreateTypeOptions
                            {
                                ImplementsFn = () =>
                                {
                                    if (!Config.AddReturnMarker
                                        && !type.ReturnVoidMarker
                                        && type.ReturnMarkerTypeName == null)
                                        return null;

                                    if (type.ReturnVoidMarker)
                                        return "IReturnVoid";
                                    if (type.ReturnMarkerTypeName != null)
                                        return Type("IReturn`1", new[] { Type(type.ReturnMarkerTypeName) });
                                    return response != null
                                        ? Type("IReturn`1", new[] { Type(type.Name, type.GenericArgs) })
                                        : null;
                                },
                                IsRequest = true,
                            });

                        existingOps.Add(fullTypeName);
                    }
                }
                else if (responseTypes.Contains(type))
                {
                    if (!existingOps.Contains(fullTypeName)
                        && !Config.IgnoreTypesInNamespaces.Contains(type.Namespace))
                    {
                        lastNS = AppendType(ref sb, type, lastNS,
                            new CreateTypeOptions
                            {
                                IsResponse = true,
                            });

                        existingOps.Add(fullTypeName);
                    }
                }
                else if (types.Contains(type) && !existingOps.Contains(fullTypeName))
                {
                    lastNS = AppendType(ref sb, type, lastNS,
                        new CreateTypeOptions { IsType = true });
                }
            }

            sb.AppendLine();

            return sb.ToString();
        }
        private string AppendType(ref StringBuilderWrapper sb, MetadataType type, string lastNS,
            CreateTypeOptions options)
        {
            if (type == null || (type.Namespace != null && type.Namespace.StartsWith("System")))
                return lastNS;

            sb = sb.Indent();

            sb.AppendLine();
            AppendComments(sb, type.Description);
            if (type.Routes != null)
            {
                AppendAttributes(sb, type.Routes.ConvertAll(x => x.ToMetadataAttribute()));
            }
            AppendAttributes(sb, type.Attributes);
            AppendDataContract(sb, type.DataContract);

            if (type.IsEnum.GetValueOrDefault())
            {
                sb.AppendLine("type {0} =".Fmt(Type(type.Name, type.GenericArgs)));
                sb = sb.Indent();

                if (type.EnumNames != null)
                {
                    for (var i = 0; i < type.EnumNames.Count; i++)
                    {
                        var name = type.EnumNames[i];
                        var value = type.EnumValues != null ? type.EnumValues[i] : i.ToString();
                        sb.AppendLine("| {0} = {1}".Fmt(name, value));
                    }
                }

                sb = sb.UnIndent();
            }
            else
            {
                //sb.AppendLine("[<CLIMutable>]"); // only for Record Types
                sb.AppendLine("[<AllowNullLiteral>]");
                sb.AppendLine("type {0}() = ".Fmt(Type(type.Name, type.GenericArgs)));
                sb = sb.Indent();
                var startLen = sb.Length;

                //: BaseClass, Interfaces
                if (type.Inherits != null)
                    sb.AppendLine("inherit {0}()".Fmt(Type(type.Inherits)));

                if (options.ImplementsFn != null)
                {
                    var implStr = options.ImplementsFn();
                    if (!string.IsNullOrEmpty(implStr))
                        sb.AppendLine("interface {0}".Fmt(implStr));
                }

                var makeExtensible = Config.MakeDataContractsExtensible && type.Inherits == null;
                if (makeExtensible)
                {
                    sb.AppendLine("interface IExtensibleDataObject with");
                    sb.AppendLine("    member val ExtensionData:ExtensionDataObject = null with get, set");
                    sb.AppendLine("end");
                }

                var addVersionInfo = Config.AddImplicitVersion != null && options.IsOperation;
                if (addVersionInfo)
                {
                    sb.AppendLine("member val Version:int = {0} with get, set".Fmt(Config.AddImplicitVersion));
                }

                AddProperties(sb, type);

                if (sb.Length == startLen)
                    sb.AppendLine("class end");

                sb = sb.UnIndent();
            }

            sb = sb.UnIndent();
            return lastNS;
        }
        public bool AppendDataMember(StringBuilderWrapper sb, MetadataDataMember dmMeta, int dataMemberIndex)
        {
            if (dmMeta == null)
            {
                if (Config.AddDataContractAttributes)
                {
                    sb.AppendLine(Config.AddIndexesToDataMembers
                        ? $"[DataMember(Order={dataMemberIndex})]"
                        : "[DataMember]");
                    return true;
                }
                return false;
            }

            var dmArgs = "";
            if (dmMeta.Name != null
                || dmMeta.Order != null
                || dmMeta.IsRequired != null
                || dmMeta.EmitDefaultValue != null
                || Config.AddIndexesToDataMembers)
            {
                if (dmMeta.Name != null)
                    dmArgs = $"Name={dmMeta.Name.QuotedSafeValue()}";

                if (dmMeta.Order != null || Config.AddIndexesToDataMembers)
                {
                    if (dmArgs.Length > 0)
                        dmArgs += ", ";

                    dmArgs += $"Order={dmMeta.Order ?? dataMemberIndex}";
                }

                if (dmMeta.IsRequired != null)
                {
                    if (dmArgs.Length > 0)
                        dmArgs += ", ";

                    dmArgs += $"IsRequired={dmMeta.IsRequired.ToString().ToLower()}";
                }

                if (dmMeta.EmitDefaultValue != null)
                {
                    if (dmArgs.Length > 0)
                        dmArgs += ", ";

                    dmArgs += $"EmitDefaultValue={dmMeta.EmitDefaultValue.ToString().ToLower()}";
                }

                dmArgs = $"({dmArgs})";
            }
            sb.AppendLine($"[DataMember{dmArgs}]");

            return true;
        }
        public void AppendDataContract(StringBuilderWrapper sb, MetadataDataContract dcMeta)
        {
            if (dcMeta == null)
            {
                if (Config.AddDataContractAttributes)
                    sb.AppendLine("[DataContract]");
                return;
            }

            var dcArgs = "";
            if (dcMeta.Name != null || dcMeta.Namespace != null)
            {
                if (dcMeta.Name != null)
                    dcArgs = $"Name={dcMeta.Name.QuotedSafeValue()}";

                if (dcMeta.Namespace != null)
                {
                    if (dcArgs.Length > 0)
                        dcArgs += ", ";

                    dcArgs += $"Namespace={dcMeta.Namespace.QuotedSafeValue()}";
                }

                dcArgs = $"({dcArgs})";
            }
            sb.AppendLine($"[DataContract{dcArgs}]");
        }
        private string AppendType(ref StringBuilderWrapper sb, ref StringBuilderWrapper sbExt, MetadataType type, string lastNS,
            CreateTypeOptions options)
        {
            //sb = sb.Indent();

            var hasGenericBaseType = type.Inherits != null && !type.Inherits.GenericArgs.IsEmpty();
            if (Config.ExcludeGenericBaseTypes && hasGenericBaseType)
            {
                sb.AppendLine("//Excluded {0} : {1}<{2}>".Fmt(type.Name, type.Inherits.Name.SplitOnFirst('`')[0], string.Join(",", type.Inherits.GenericArgs)));
                return lastNS;
            }

            sb.AppendLine();
            AppendComments(sb, type.Description);
            if (type.Routes != null)
            {
                AppendAttributes(sb, type.Routes.ConvertAll(x => x.ToMetadataAttribute()));
            }
            AppendAttributes(sb, type.Attributes);
            AppendDataContract(sb, type.DataContract);

            if (type.IsEnum.GetValueOrDefault())
            {
                sb.AppendLine("public enum {0} : Int".Fmt(Type(type.Name, type.GenericArgs)));
                sb.AppendLine("{");
                sb = sb.Indent();

                if (type.EnumNames != null)
                {
                    for (var i = 0; i < type.EnumNames.Count; i++)
                    {
                        var name = type.EnumNames[i];
                        var value = type.EnumValues != null ? type.EnumValues[i] : null;
                        sb.AppendLine(value == null
                            ? "case {0}".Fmt(name)
                            : "case {0} = {1}".Fmt(name, value));
                    }
                }

                sb = sb.UnIndent();
                sb.AppendLine("}");

                AddEnumExtension(ref sbExt, type);
            }
            else
            {
                var defType = "class";
                var typeName = Type(type.Name, type.GenericArgs).AddGenericConstraints();
                var extends = new List<string>();

                //: BaseClass, Interfaces
                if (type.Inherits != null)
                {
                    var baseType = Type(type.Inherits).InheritedType();

                    //Swift requires re-declaring base type generics definition on super type
                    var genericDefPos = baseType.IndexOf("<");
                    if (genericDefPos >= 0)
                    {
                        //Need to declare BaseType is JsonSerializable
                        var subBaseType = baseType.Substring(genericDefPos)
                            .AddGenericConstraints();

                        typeName += subBaseType;
                    }

                    extends.Add(baseType);
                }
                else if (Config.BaseClass != null && !type.IsInterface())
                {
                    extends.Add(Config.BaseClass);
                }

                var typeAliases = new List<string>();

                if (options.ImplementsFn != null)
                {
                    //Swift doesn't support Generic Interfaces like IReturn<T> 
                    //Converting them into protocols with typealiases instead 
                    ExtractTypeAliases(options, typeAliases, extends, ref sbExt);

                    if (!type.Implements.IsEmpty())
                        type.Implements.Each(x => extends.Add(Type(x)));
                }

                if (type.IsInterface())
                {
                    defType = "protocol";

                    //Extract Protocol Arguments into different typealiases
                    if (!type.GenericArgs.IsEmpty())
                    {
                        typeName = Type(type.Name, null);
                        foreach (var arg in type.GenericArgs)
                        {
                            typeAliases.Add("public typealias {0} = {0}".Fmt(arg));
                        }
                    }
                }

                var extend = extends.Count > 0
                    ? " : " + (string.Join(", ", extends.ToArray()))
                    : "";

                sb.AppendLine("public {0} {1}{2}".Fmt(defType, typeName, extend));
                sb.AppendLine("{");

                sb = sb.Indent();

                if (typeAliases.Count > 0)
                {
                    foreach (var typeAlias in typeAliases)
                    {
                        sb.AppendLine(typeAlias);
                    }
                    sb.AppendLine();
                }

                if (!type.IsInterface())
                {
                    if (extends.Count > 0 && OverrideInitForBaseClasses.Contains(extends[0]))
                    {
                        sb.AppendLine("required public override init(){}");
                    }
                    else
                    {
                        sb.AppendLine("required public init(){}");
                    }
                }

                var addVersionInfo = Config.AddImplicitVersion != null && options.IsRequest;
                if (addVersionInfo)
                {
                    sb.AppendLine("public var {0}:Int = {1}".Fmt("Version".PropertyStyle(), Config.AddImplicitVersion));
                }

                AddProperties(sb, type,
                    initCollections: !type.IsInterface() && Config.InitializeCollections,
                    includeResponseStatus: Config.AddResponseStatus && options.IsResponse
                        && type.Properties.Safe().All(x => x.Name != typeof(ResponseStatus).Name));

                sb = sb.UnIndent();
                sb.AppendLine("}");

                if (!type.IsInterface())
                {
                    AddTypeExtension(ref sbExt, type,
                        initCollections: Config.InitializeCollections);
                }
            }

            //sb = sb.UnIndent();

            return lastNS;
        }
        private void AddTypeExtension(ref StringBuilderWrapper sbExt, MetadataType type, bool initCollections)
        {
            //Swift doesn't support extensions on same protocol used by Base and Sub types
            if (type.IsAbstract())
                return;

            var typeName = Type(type.Name, type.GenericArgs);

            var typeNameOnly = typeName.SplitOnFirst('<')[0];

            sbExt.AppendLine();
            sbExt.AppendLine("extension {0} : JsonSerializable".Fmt(typeNameOnly));
            sbExt.AppendLine("{");
            sbExt = sbExt.Indent();

            sbExt.AppendLine("public static var typeName:String {{ return \"{0}\" }}".Fmt(typeName));

            //func typeConfig()

            var isGenericType = !type.GenericArgs.IsEmpty();
            if (!isGenericType)
            {
                sbExt.AppendLine("public static var metadata = Metadata.create([");
                sbExt = sbExt.Indent();
            }
            else
            {
                //Swift 2.0 doesn't allow stored static properties on generic types yet
                sbExt.AppendLine("public static var metadata:Metadata {");
                sbExt = sbExt.Indent();
                sbExt.AppendLine("return Metadata.create([");
            }

            sbExt = sbExt.Indent();

            foreach (var prop in GetPropertes(type))
            {
                var propType = FindType(prop.Type, prop.TypeNamespace, prop.GenericArgs);
                if (propType.IsInterface()
                    || IgnorePropertyTypeNames.Contains(prop.Type)
                    || IgnorePropertyNames.Contains(prop.Name))
                    continue;

                var fnName = "property";
                if (prop.IsArray() || ArrayTypes.Contains(prop.Type))
                {
                    fnName = initCollections
                        ? "arrayProperty"
                        : "optionalArrayProperty";
                }
                else if (DictionaryTypes.Contains(prop.Type))
                {
                    fnName = initCollections
                        ? "objectProperty"
                        : "optionalObjectProperty";
                }
                else
                {
                    if (propType != null && !propType.IsEnum.GetValueOrDefault())
                    {
                        fnName = "optionalObjectProperty";
                    }
                    else
                    {
                        fnName = "optionalProperty";
                    }
                }

                var propName = prop.Name.SafeToken().PropertyStyle();
                var unescapedName = propName.UnescapeReserved();
                sbExt.AppendLine("Type<{0}>.{1}(\"{2}\", get: {{ $0.{3} }}, set: {{ $0.{3} = $1 }}),".Fmt(
                        typeName, fnName, unescapedName, propName));
            }
            sbExt = sbExt.UnIndent();
            sbExt.AppendLine("])");
            sbExt = sbExt.UnIndent();

            if (isGenericType)
            {
                sbExt.AppendLine("}");
            }

            sbExt = sbExt.UnIndent();
            sbExt.AppendLine("}");
        }
        private string AppendType(ref StringBuilderWrapper sb, MetadataType type, string lastNS,
            CreateTypeOptions options)
        {
            sb = sb.Indent();

            sb.AppendLine();
            AppendComments(sb, type.Description);
            if (type.Routes != null)
            {
                AppendAttributes(sb, type.Routes.ConvertAll(x => x.ToMetadataAttribute()));
            }
            AppendAttributes(sb, type.Attributes);
            AppendDataContract(sb, type.DataContract);

            if (type.IsEnum.GetValueOrDefault())
            {
                sb.AppendLine("enum {0}".Fmt(Type(type.Name, type.GenericArgs)));
                sb.AppendLine("{");
                sb = sb.Indent();

                if (type.EnumNames != null)
                {
                    for (var i = 0; i < type.EnumNames.Count; i++)
                    {
                        var name = type.EnumNames[i];
                        var value = type.EnumValues != null ? type.EnumValues[i] : null;
                        sb.AppendLine(value == null
                            ? "{0},".Fmt(name.PropertyStyle())
                            : "{0} = {1},".Fmt(name.PropertyStyle(), value));
                    }
                }

                sb = sb.UnIndent();
                sb.AppendLine("}");
            }
            else
            {
                var extends = new List<string>();

                //: BaseClass, Interfaces
                if (type.Inherits != null)
                    extends.Add(Type(type.Inherits).InheritedType());

                if (options.ImplementsFn != null)
                {
                    var implStr = options.ImplementsFn();
                    if (!string.IsNullOrEmpty(implStr))
                        extends.Add(implStr);
                }

                var extend = extends.Count > 0
                    ? " extends " + (string.Join(", ", extends.ToArray()))
                    : "";

                sb.AppendLine("interface {0}{1}".Fmt(Type(type.Name, type.GenericArgs), extend));
                sb.AppendLine("{");

                sb = sb.Indent();

                var addVersionInfo = Config.AddImplicitVersion != null && options.IsRequest;
                if (addVersionInfo)
                {
                    sb.AppendLine("{0}?: number; //{1}".Fmt("Version".PropertyStyle(), Config.AddImplicitVersion));
                }

                AddProperties(sb, type,
                    includeResponseStatus: Config.AddResponseStatus && options.IsResponse
                        && type.Properties.Safe().All(x => x.Name != typeof(ResponseStatus).Name));

                sb = sb.UnIndent();
                sb.AppendLine("}");
            }

            sb = sb.UnIndent();

            return lastNS;
        }
        public string GetCode(MetadataTypes metadata, IRequest request)
        {
            var typeNamespaces = new HashSet<string>();
            RemoveIgnoredTypes(metadata);
            metadata.Types.Each(x => typeNamespaces.Add(x.Namespace));
            metadata.Operations.Each(x => typeNamespaces.Add(x.Request.Namespace));

            var defaultImports = !Config.DefaultImports.IsEmpty()
                ? Config.DefaultImports
                : DefaultImports;

            Func<string, string> defaultValue = k =>
                request.QueryString[k].IsNullOrEmpty() ? "//" : "";

            var sb = new StringBuilderWrapper(new StringBuilder());
            var sbExt = new StringBuilderWrapper(new StringBuilder());
            sb.AppendLine("/* Options:");
            sb.AppendLine("Date: {0}".Fmt(DateTime.Now.ToString("s").Replace("T", " ")));
            sb.AppendLine("SwiftVersion: 2.0");
            sb.AppendLine("Version: {0}".Fmt(Env.ServiceStackVersion));
            sb.AppendLine("Tip: {0}".Fmt(HelpMessages.NativeTypesDtoOptionsTip.Fmt("//")));
            sb.AppendLine("BaseUrl: {0}".Fmt(Config.BaseUrl));
            sb.AppendLine();

            sb.AppendLine("{0}BaseClass: {1}".Fmt(defaultValue("BaseClass"), Config.BaseClass));
            sb.AppendLine("{0}AddModelExtensions: {1}".Fmt(defaultValue("AddModelExtensions"), Config.AddModelExtensions));
            sb.AppendLine("{0}AddServiceStackTypes: {1}".Fmt(defaultValue("AddServiceStackTypes"), Config.AddServiceStackTypes));
            sb.AppendLine("{0}IncludeTypes: {1}".Fmt(defaultValue("IncludeTypes"), Config.IncludeTypes.Safe().ToArray().Join(",")));
            sb.AppendLine("{0}ExcludeTypes: {1}".Fmt(defaultValue("ExcludeTypes"), Config.ExcludeTypes.Safe().ToArray().Join(",")));
            sb.AppendLine("{0}ExcludeGenericBaseTypes: {1}".Fmt(defaultValue("ExcludeGenericBaseTypes"), Config.ExcludeGenericBaseTypes));
            sb.AppendLine("{0}AddResponseStatus: {1}".Fmt(defaultValue("AddResponseStatus"), Config.AddResponseStatus));
            sb.AppendLine("{0}AddImplicitVersion: {1}".Fmt(defaultValue("AddImplicitVersion"), Config.AddImplicitVersion));
            sb.AppendLine("{0}InitializeCollections: {1}".Fmt(defaultValue("InitializeCollections"), Config.InitializeCollections));
            sb.AppendLine("{0}TreatTypesAsStrings: {1}".Fmt(defaultValue("TreatTypesAsStrings"), Config.TreatTypesAsStrings.Safe().ToArray().Join(",")));
            sb.AppendLine("{0}DefaultImports: {1}".Fmt(defaultValue("DefaultImports"), defaultImports.Join(",")));

            sb.AppendLine("*/");
            sb.AppendLine();

            foreach (var typeName in Config.TreatTypesAsStrings.Safe())
            {
                TypeAliases[typeName] = "String";
            }

            string lastNS = null;

            var existingTypes = new HashSet<string>();

            var requestTypes = metadata.Operations.Select(x => x.Request).ToHashSet();
            var requestTypesMap = metadata.Operations.ToSafeDictionary(x => x.Request);
            var responseTypes = metadata.Operations
                .Where(x => x.Response != null)
                .Select(x => x.Response).ToHashSet();
            var types = metadata.Types.ToHashSet();

            AllTypes.AddRange(requestTypes);
            AllTypes.AddRange(responseTypes);
            AllTypes.AddRange(types);

            //Swift doesn't support reusing same type name with different generic airity
            var conflictPartialNames = AllTypes.Map(x => x.Name).Distinct()
                .GroupBy(g => g.SplitOnFirst('`')[0])
                .Where(g => g.Count() > 1)
                .Select(g => g.Key)
                .ToList();

            this.conflictTypeNames = AllTypes
                .Where(x => conflictPartialNames.Any(name => x.Name.StartsWith(name)))
                .Map(x => x.Name);

            defaultImports.Each(x => sb.AppendLine("import {0};".Fmt(x)));

            //ServiceStack core interfaces
            foreach (var type in AllTypes)
            {
                var fullTypeName = type.GetFullName();
                if (requestTypes.Contains(type))
                {
                    if (!existingTypes.Contains(fullTypeName))
                    {
                        MetadataType response = null;
                        MetadataOperationType operation;
                        if (requestTypesMap.TryGetValue(type, out operation))
                        {
                            response = operation.Response;
                        }

                        lastNS = AppendType(ref sb, ref sbExt, type, lastNS,
                            new CreateTypeOptions
                            {
                                ImplementsFn = () =>
                                {
                                    if (!Config.AddReturnMarker
                                        && !type.ReturnVoidMarker
                                        && type.ReturnMarkerTypeName == null)
                                        return null;

                                    if (type.ReturnVoidMarker)
                                        return "IReturnVoid";
                                    if (type.ReturnMarkerTypeName != null)
                                        return ReturnType("IReturn`1", new[] { Type(type.ReturnMarkerTypeName) });
                                    return response != null
                                        ? ReturnType("IReturn`1", new[] { Type(response.Name, response.GenericArgs) })
                                        : null;
                                },
                                IsRequest = true,
                            });

                        existingTypes.Add(fullTypeName);
                    }
                }
                else if (responseTypes.Contains(type))
                {
                    if (!existingTypes.Contains(fullTypeName)
                        && !Config.IgnoreTypesInNamespaces.Contains(type.Namespace))
                    {
                        lastNS = AppendType(ref sb, ref sbExt, type, lastNS,
                            new CreateTypeOptions
                            {
                                IsResponse = true,
                            });

                        existingTypes.Add(fullTypeName);
                    }
                }
                else if (types.Contains(type) && !existingTypes.Contains(fullTypeName))
                {
                    lastNS = AppendType(ref sb, ref sbExt, type, lastNS,
                        new CreateTypeOptions { IsType = true });

                    existingTypes.Add(fullTypeName);
                }
            }

            if (Config.AddModelExtensions)
            {
                sb.AppendLine();
                sb.AppendLine(sbExt.ToString());
            }

            return sb.ToString();
        }
        public void AddProperties(StringBuilderWrapper sb, MetadataType type, bool includeResponseStatus)
        {
            var wasAdded = false;

            var dataMemberIndex = 1;
            if (type.Properties != null)
            {
                foreach (var prop in type.Properties)
                {
                    if (wasAdded) sb.AppendLine();

                    var propType = Type(prop.Type, prop.GenericArgs);
                    var optional = "";
                    if (propType.EndsWith("?"))
                    {
                        propType = propType.Substring(0, propType.Length - 1);
                        optional = "?";
                    }
                    if (Config.MakePropertiesOptional)
                    {
                        optional = "?";
                    }

                    if (prop.Attributes.Safe().FirstOrDefault(x => x.Name == "Required") != null)
                    {
                        optional = "";
                    }

                    wasAdded = AppendDataMember(sb, prop.DataMember, dataMemberIndex++);
                    wasAdded = AppendAttributes(sb, prop.Attributes) || wasAdded;
                    sb.AppendLine("{1}{2}: {0};".Fmt(propType, prop.Name.SafeToken().PropertyStyle(), optional));
                }
            }

            if (includeResponseStatus)
            {
                if (wasAdded) sb.AppendLine();

                AppendDataMember(sb, null, dataMemberIndex++);
                sb.AppendLine("{0}?: ResponseStatus;".Fmt(typeof(ResponseStatus).Name.PropertyStyle()));
            }
        }
        public bool AppendAttributes(StringBuilderWrapper sb, List<MetadataAttribute> attributes)
        {
            if (attributes == null || attributes.Count == 0) return false;

            foreach (var attr in attributes)
            {
                if ((attr.Args == null || attr.Args.Count == 0)
                    && (attr.ConstructorArgs == null || attr.ConstructorArgs.Count == 0))
                {
                    sb.AppendLine("// @{0}()".Fmt(attr.Name));
                }
                else
                {
                    var args = new StringBuilder();
                    if (attr.ConstructorArgs != null)
                    {
                        foreach (var ctorArg in attr.ConstructorArgs)
                        {
                            if (args.Length > 0)
                                args.Append(", ");
                            args.Append("{0}".Fmt(TypeValue(ctorArg.Type, ctorArg.Value)));
                        }
                    }
                    else if (attr.Args != null)
                    {
                        foreach (var attrArg in attr.Args)
                        {
                            if (args.Length > 0)
                                args.Append(", ");
                            args.Append("{0}={1}".Fmt(attrArg.Name, TypeValue(attrArg.Type, attrArg.Value)));
                        }
                    }
                    sb.AppendLine("// @{0}({1})".Fmt(attr.Name, args));
                }
            }

            return true;
        }
        public string GetCode(MetadataTypes metadata, IRequest request, INativeTypesMetadata nativeTypes)
        {
            var typeNamespaces = new HashSet<string>();
            metadata.RemoveIgnoredTypes(Config);
            metadata.Types.Each(x => typeNamespaces.Add(x.Namespace));
            metadata.Operations.Each(x => typeNamespaces.Add(x.Request.Namespace));

            var defaultImports = !Config.DefaultImports.IsEmpty()
                ? Config.DefaultImports
                : DefaultImports;

            // Look first for shortest Namespace ending with `ServiceModel` convention, else shortest ns
            var globalNamespace = Config.GlobalNamespace
                ?? typeNamespaces.Where(x => x.EndsWith("ServiceModel"))
                    .OrderBy(x => x).FirstOrDefault()
                ?? typeNamespaces.OrderBy(x => x).First();

            Func<string, string> defaultValue = k =>
                request.QueryString[k].IsNullOrEmpty() ? "//" : "";

            var sb = new StringBuilderWrapper(new StringBuilder());
            sb.AppendLine("/* Options:");
            sb.AppendLine("Date: {0}".Fmt(DateTime.Now.ToString("s").Replace("T", " ")));
            sb.AppendLine("Version: {0}".Fmt(Env.ServiceStackVersion));
            sb.AppendLine("BaseUrl: {0}".Fmt(Config.BaseUrl));
            sb.AppendLine();
            sb.AppendLine("{0}GlobalNamespace: {1}".Fmt(defaultValue("GlobalNamespace"), Config.GlobalNamespace));
            sb.AppendLine("{0}MakePropertiesOptional: {1}".Fmt(defaultValue("MakePropertiesOptional"), Config.MakePropertiesOptional));
            sb.AppendLine("{0}AddServiceStackTypes: {1}".Fmt(defaultValue("AddServiceStackTypes"), Config.AddServiceStackTypes));
            sb.AppendLine("{0}AddResponseStatus: {1}".Fmt(defaultValue("AddResponseStatus"), Config.AddResponseStatus));
            sb.AppendLine("{0}AddImplicitVersion: {1}".Fmt(defaultValue("AddImplicitVersion"), Config.AddImplicitVersion));
            sb.AppendLine("{0}IncludeTypes: {1}".Fmt(defaultValue("IncludeTypes"), Config.IncludeTypes.Safe().ToArray().Join(",")));
            sb.AppendLine("{0}ExcludeTypes: {1}".Fmt(defaultValue("ExcludeTypes"), Config.ExcludeTypes.Safe().ToArray().Join(",")));
            sb.AppendLine("{0}DefaultImports: {1}".Fmt(defaultValue("DefaultImports"), defaultImports.Join(",")));

            sb.AppendLine("*/");
            sb.AppendLine();

            string lastNS = null;

            var existingTypes = new HashSet<string>();

            var requestTypes = metadata.Operations.Select(x => x.Request).ToHashSet();
            var requestTypesMap = metadata.Operations.ToSafeDictionary(x => x.Request);
            var responseTypes = metadata.Operations
                .Where(x => x.Response != null)
                .Select(x => x.Response).ToHashSet();
            var types = metadata.Types.ToHashSet();

            var allTypes = new List<MetadataType>();
            allTypes.AddRange(types);
            allTypes.AddRange(responseTypes);
            allTypes.AddRange(requestTypes);
            allTypes.RemoveAll(x => x.IgnoreType(Config));

            //TypeScript doesn't support reusing same type name with different generic airity
            var conflictPartialNames = allTypes.Map(x => x.Name).Distinct()
                .GroupBy(g => g.SplitOnFirst('`')[0])
                .Where(g => g.Count() > 1)
                .Select(g => g.Key)
                .ToList();

            this.conflictTypeNames = allTypes
                .Where(x => conflictPartialNames.Any(name => x.Name.StartsWith(name)))
                .Map(x => x.Name);

            defaultImports.Each(x => sb.AppendLine("import {0};".Fmt(x)));
            sb.AppendLine();

            sb.AppendLine("declare module {0}".Fmt(globalNamespace.SafeToken()));
            sb.AppendLine("{");

            //ServiceStack core interfaces
            foreach (var type in allTypes)
            {
                var fullTypeName = type.GetFullName();
                if (requestTypes.Contains(type))
                {
                    if (!existingTypes.Contains(fullTypeName))
                    {
                        MetadataType response = null;
                        MetadataOperationType operation;
                        if (requestTypesMap.TryGetValue(type, out operation))
                        {
                            response = operation.Response;
                        }

                        lastNS = AppendType(ref sb, type, lastNS,
                            new CreateTypeOptions
                            {
                                ImplementsFn = () =>
                                {
                                    if (!Config.AddReturnMarker
                                        && !type.ReturnVoidMarker
                                        && type.ReturnMarkerTypeName == null)
                                        return null;

                                    if (type.ReturnVoidMarker)
                                        return "IReturnVoid";
                                    if (type.ReturnMarkerTypeName != null)
                                        return Type("IReturn`1", new[] { Type(type.ReturnMarkerTypeName) });
                                    return response != null
                                        ? Type("IReturn`1", new[] { Type(response.Name, response.GenericArgs) })
                                        : null;
                                },
                                IsRequest = true,
                            });

                        existingTypes.Add(fullTypeName);
                    }
                }
                else if (responseTypes.Contains(type))
                {
                    if (!existingTypes.Contains(fullTypeName)
                        && !Config.IgnoreTypesInNamespaces.Contains(type.Namespace))
                    {
                        lastNS = AppendType(ref sb, type, lastNS,
                            new CreateTypeOptions
                            {
                                IsResponse = true,
                            });

                        existingTypes.Add(fullTypeName);
                    }
                }
                else if (types.Contains(type) && !existingTypes.Contains(fullTypeName))
                {
                    lastNS = AppendType(ref sb, type, lastNS,
                        new CreateTypeOptions { IsType = true });

                    existingTypes.Add(fullTypeName);
                }
            }

            sb.AppendLine();
            sb.AppendLine("}");

            return sb.ToString();
        }
Exemple #23
0
        public void AddProperties(StringBuilderWrapper sb, MetadataType type,
            bool includeResponseStatus,
            bool addPropertyAccessors,
            string settersReturnType)
        {
            var wasAdded = false;

            var sbInner = StringBuilderCacheAlt.Allocate();
            var sbAccessors = new StringBuilderWrapper(sbInner);
            if (addPropertyAccessors)
            {
                sbAccessors.AppendLine();
                sbAccessors = sbAccessors.Indent().Indent();
            }

            var dataMemberIndex = 1;
            if (type.Properties != null)
            {
                foreach (var prop in type.Properties)
                {
                    if (wasAdded) sb.AppendLine();

                    var propType = Type(prop.Type, prop.GenericArgs);

                    var fieldName = prop.Name.SafeToken().PropertyStyle();
                    var accessorName = fieldName.ToPascalCase();

                    wasAdded = AppendComments(sb, prop.Description);
                    wasAdded = AppendDataMember(sb, prop.DataMember, dataMemberIndex++) || wasAdded;
                    wasAdded = AppendAttributes(sb, prop.Attributes) || wasAdded;

                    if (!fieldName.IsKeyWord())
                    {
                        sb.AppendLine("public {0} {1} = null;".Fmt(propType, fieldName));
                    }
                    else
                    {
                        var originalName = fieldName;
                        fieldName = Char.ToUpper(fieldName[0]) + fieldName.SafeSubstring(1);
                        sb.AppendLine("@SerializedName(\"{0}\") public {1} {2} = null;".Fmt(originalName, propType, fieldName));
                    }

                    if (addPropertyAccessors)
                        sbAccessors.AppendPropertyAccessor(propType, fieldName, accessorName, settersReturnType);
                }
            }

            if (includeResponseStatus)
            {
                if (wasAdded) sb.AppendLine();

                AppendDataMember(sb, null, dataMemberIndex++);
                sb.AppendLine("public ResponseStatus {0} = null;".Fmt(typeof(ResponseStatus).Name.PropertyStyle()));

                if (addPropertyAccessors)
                    sbAccessors.AppendPropertyAccessor("ResponseStatus", "ResponseStatus", settersReturnType);
            }

            if (sbAccessors.Length > 0)
                sb.AppendLine(StringBuilderCacheAlt.ReturnAndFree(sbInner).TrimEnd()); //remove last \n
        }
        private string AppendType(ref StringBuilderWrapper sb, MetadataType type, string lastNS, List<MetadataType> allTypes, CreateTypeOptions options)
        {
            if (type.IsNested.GetValueOrDefault() && !options.IsNestedType)
                return lastNS;

            var ns = Config.GlobalNamespace ?? type.Namespace;
            if (ns != lastNS)
            {
                if (lastNS != null)
                    sb.AppendLine("}");

                lastNS = ns;

                sb.AppendLine();
                sb.AppendLine("namespace {0}".Fmt(ns.SafeToken()));
                sb.AppendLine("{");
            }

            sb = sb.Indent();

            sb.AppendLine();
            AppendComments(sb, type.Description);
            if (type.Routes != null)
            {
                AppendAttributes(sb, type.Routes.ConvertAll(x => x.ToMetadataAttribute()));
            }
            AppendAttributes(sb, type.Attributes);
            AppendDataContract(sb, type.DataContract);
            if (Config.AddGeneratedCodeAttributes)
                sb.AppendLine("[GeneratedCode(\"AddServiceStackReference\", \"{0}\")]".Fmt(Env.VersionString));

            if (type.IsEnum.GetValueOrDefault())
            {
                sb.AppendLine("public enum {0}".Fmt(Type(type.Name, type.GenericArgs)));
                sb.AppendLine("{");
                sb = sb.Indent();

                if (type.EnumNames != null)
                {
                    for (var i = 0; i < type.EnumNames.Count; i++)
                    {
                        var name = type.EnumNames[i];
                        var value = type.EnumValues != null ? type.EnumValues[i] : null;
                        sb.AppendLine(value == null 
                            ? "{0},".Fmt(name) 
                            : "{0} = {1},".Fmt(name, value));
                    }
                }

                sb = sb.UnIndent();
                sb.AppendLine("}");
            }
            else
            {
                var partial = Config.MakePartial ? "partial " : "";
                var defType = type.IsInterface() ? "interface" : "class";
                sb.AppendLine("public {0}{1} {2}".Fmt(partial, defType, Type(type.Name, type.GenericArgs)));

                //: BaseClass, Interfaces
                var inheritsList = new List<string>();
                if (type.Inherits != null)
                {
                    inheritsList.Add(Type(type.Inherits, includeNested:true));
                }

                if (options.ImplementsFn != null)
                {
                    var implStr = options.ImplementsFn();
                    if (!string.IsNullOrEmpty(implStr))
                        inheritsList.Add(implStr);
                    if (!type.Implements.IsEmpty())
                        type.Implements.Each(x => inheritsList.Add(Type(x)));
                }

                var makeExtensible = Config.MakeDataContractsExtensible && type.Inherits == null;
                if (makeExtensible)
                    inheritsList.Add("IExtensibleDataObject");
                if (inheritsList.Count > 0)
                    sb.AppendLine("    : {0}".Fmt(string.Join(", ", inheritsList.ToArray())));

                sb.AppendLine("{");
                sb = sb.Indent();

                AddConstuctor(sb, type, options);
                AddProperties(sb, type,
                    includeResponseStatus: Config.AddResponseStatus && options.IsResponse
                        && type.Properties.Safe().All(x => x.Name != typeof(ResponseStatus).Name));

                foreach (var innerTypeRef in type.InnerTypes.Safe())
                {
                    var innerType = allTypes.FirstOrDefault(x => x.Name == innerTypeRef.Name);
                    if (innerType == null)
                        continue;

                    sb = sb.UnIndent();
                    AppendType(ref sb, innerType, lastNS, allTypes,
                        new CreateTypeOptions { IsNestedType = true });
                    sb = sb.Indent();
                }

                sb = sb.UnIndent();
                sb.AppendLine("}");
            }

            sb = sb.UnIndent();
            return lastNS;
        }
Exemple #25
0
 public bool AppendComments(StringBuilderWrapper sb, string desc)
 {
     if (desc != null && Config.AddDescriptionAsComments)
     {
         sb.AppendLine("/**");
         sb.AppendLine("* {0}".Fmt(desc.SafeComment()));
         sb.AppendLine("*/");
     }
     return false;
 }
        private void AddConstuctor(StringBuilderWrapper sb, MetadataType type, CreateTypeOptions options)
        {
            if (type.IsInterface())
                return;

            var initCollections = feature.ShouldInitializeCollections(type, Config.InitializeCollections);
            if (Config.AddImplicitVersion == null && !initCollections)
                return;

            var collectionProps = new List<MetadataPropertyType>();
            if (type.Properties != null && initCollections)
                collectionProps = type.Properties.Where(x => x.IsCollection()).ToList();

            var addVersionInfo = Config.AddImplicitVersion != null && options.IsRequest;
            if (!addVersionInfo && collectionProps.Count <= 0) return;

            if (addVersionInfo)
            {
                var @virtual = Config.MakeVirtual ? "virtual " : "";
                sb.AppendLine("public {0}int Version {{ get; set; }}".Fmt(@virtual));
                sb.AppendLine();
            }

            sb.AppendLine("public {0}()".Fmt(NameOnly(type.Name)));
            sb.AppendLine("{");
            sb = sb.Indent();

            if (addVersionInfo)
                sb.AppendLine("Version = {0};".Fmt(Config.AddImplicitVersion));

            foreach (var prop in collectionProps)
            {
                sb.AppendLine("{0} = new {1}{{}};".Fmt(
                prop.Name.SafeToken(),
                Type(prop.Type, prop.GenericArgs, includeNested: true)));
            }

            sb = sb.UnIndent();
            sb.AppendLine("}");
            sb.AppendLine();
        }
Exemple #27
0
        public bool AppendDataMember(StringBuilderWrapper sb, MetadataDataMember dmMeta, int dataMemberIndex)
        {
            if (dmMeta == null)
            {
                if (Config.AddDataContractAttributes)
                {
                    sb.AppendLine(Config.AddIndexesToDataMembers
                                  ? "@DataMember(Order={0})".Fmt(dataMemberIndex)
                                  : "@DataMember()");
                    return true;
                }
                return false;
            }

            var dmArgs = "";
            if (dmMeta.Name != null
                || dmMeta.Order != null
                || dmMeta.IsRequired != null
                || dmMeta.EmitDefaultValue != null
                || Config.AddIndexesToDataMembers)
            {
                if (dmMeta.Name != null)
                    dmArgs = "Name={0}".Fmt(dmMeta.Name.QuotedSafeValue());

                if (dmMeta.Order != null || Config.AddIndexesToDataMembers)
                {
                    if (dmArgs.Length > 0)
                        dmArgs += ", ";

                    dmArgs += "Order={0}".Fmt(dmMeta.Order ?? dataMemberIndex);
                }

                if (dmMeta.IsRequired != null)
                {
                    if (dmArgs.Length > 0)
                        dmArgs += ", ";

                    dmArgs += "IsRequired={0}".Fmt(dmMeta.IsRequired.ToString().ToLower());
                }

                if (dmMeta.EmitDefaultValue != null)
                {
                    if (dmArgs.Length > 0)
                        dmArgs += ", ";

                    dmArgs += "EmitDefaultValue={0}".Fmt(dmMeta.EmitDefaultValue.ToString().ToLower());
                }

                dmArgs = "({0})".Fmt(dmArgs);
            }
            sb.AppendLine("@DataMember{0}".Fmt(dmArgs));

            if (dmMeta.Name != null)
            {
                sb.AppendLine("@SerializedName(\"{0}\")".Fmt(dmMeta.Name));
            }

            return true;
        }
        public string GetCode(MetadataTypes metadata, IRequest request)
        {
            var namespaces = Config.GetDefaultNamespaces(metadata);

            metadata.RemoveIgnoredTypesForNet(Config);

            if (Config.GlobalNamespace == null)
            {
                metadata.Types.Each(x => namespaces.Add(x.Namespace));
                metadata.Operations.Each(x => namespaces.Add(x.Request.Namespace));
            }
            else
            {
                namespaces.Add(Config.GlobalNamespace);
            }

            Func<string,string> defaultValue = k =>
                request.QueryString[k].IsNullOrEmpty() ? "//" : "";

            var sbInner = StringBuilderCache.Allocate();
            var sb = new StringBuilderWrapper(sbInner);
            sb.AppendLine("/* Options:");
            sb.AppendLine("Date: {0}".Fmt(DateTime.Now.ToString("s").Replace("T"," ")));
            sb.AppendLine("Version: {0}".Fmt(Env.ServiceStackVersion));
            sb.AppendLine("Tip: {0}".Fmt(HelpMessages.NativeTypesDtoOptionsTip.Fmt("//")));
            sb.AppendLine("BaseUrl: {0}".Fmt(Config.BaseUrl));
            sb.AppendLine();
            sb.AppendLine("{0}GlobalNamespace: {1}".Fmt(defaultValue("GlobalNamespace"), Config.GlobalNamespace));
            sb.AppendLine("{0}MakePartial: {1}".Fmt(defaultValue("MakePartial"), Config.MakePartial));
            sb.AppendLine("{0}MakeVirtual: {1}".Fmt(defaultValue("MakeVirtual"), Config.MakeVirtual));
            sb.AppendLine("{0}MakeDataContractsExtensible: {1}".Fmt(defaultValue("MakeDataContractsExtensible"), Config.MakeDataContractsExtensible));
            sb.AppendLine("{0}AddReturnMarker: {1}".Fmt(defaultValue("AddReturnMarker"), Config.AddReturnMarker));
            sb.AppendLine("{0}AddDescriptionAsComments: {1}".Fmt(defaultValue("AddDescriptionAsComments"), Config.AddDescriptionAsComments));
            sb.AppendLine("{0}AddDataContractAttributes: {1}".Fmt(defaultValue("AddDataContractAttributes"), Config.AddDataContractAttributes));
            sb.AppendLine("{0}AddIndexesToDataMembers: {1}".Fmt(defaultValue("AddIndexesToDataMembers"), Config.AddIndexesToDataMembers));
            sb.AppendLine("{0}AddGeneratedCodeAttributes: {1}".Fmt(defaultValue("AddGeneratedCodeAttributes"), Config.AddGeneratedCodeAttributes));
            sb.AppendLine("{0}AddResponseStatus: {1}".Fmt(defaultValue("AddResponseStatus"), Config.AddResponseStatus));
            sb.AppendLine("{0}AddImplicitVersion: {1}".Fmt(defaultValue("AddImplicitVersion"), Config.AddImplicitVersion));
            sb.AppendLine("{0}InitializeCollections: {1}".Fmt(defaultValue("InitializeCollections"), Config.InitializeCollections));
            sb.AppendLine("{0}IncludeTypes: {1}".Fmt(defaultValue("IncludeTypes"), Config.IncludeTypes.Safe().ToArray().Join(",")));
            sb.AppendLine("{0}ExcludeTypes: {1}".Fmt(defaultValue("ExcludeTypes"), Config.ExcludeTypes.Safe().ToArray().Join(",")));
            sb.AppendLine("{0}AddDefaultXmlNamespace: {1}".Fmt(defaultValue("AddDefaultXmlNamespace"), Config.AddDefaultXmlNamespace));

            //[GeneratedCode]
            //sb.AppendLine("{0}DefaultNamespaces: {1}".Fmt(defaultValue("DefaultNamespaces"), Config.DefaultNamespaces.ToArray().Join(", ")));
            sb.AppendLine("*/");
            sb.AppendLine();

            namespaces.Where(x => !string.IsNullOrEmpty(x))
                .Each(x => sb.AppendLine("using {0};".Fmt(x)));
            if (Config.AddGeneratedCodeAttributes)
                sb.AppendLine("using System.CodeDom.Compiler;");

            if (Config.AddDataContractAttributes
                && Config.AddDefaultXmlNamespace != null)
            {
                sb.AppendLine();

                namespaces.Where(x => !Config.DefaultNamespaces.Contains(x)).ToList()
                    .ForEach(x =>
                        sb.AppendLine("[assembly: ContractNamespace(\"{0}\", ClrNamespace=\"{1}\")]"
                            .Fmt(Config.AddDefaultXmlNamespace, x)));
            }

            sb.AppendLine();

            string lastNS = null;

            var existingTypes = new HashSet<string>();

            var requestTypes = metadata.Operations.Select(x => x.Request).ToHashSet();
            var requestTypesMap = metadata.Operations.ToSafeDictionary(x => x.Request);
            var responseTypes = metadata.Operations
                .Where(x => x.Response != null)
                .Select(x => x.Response).ToHashSet();
            var types = metadata.Types.ToHashSet();

            var allTypes = new List<MetadataType>();
            allTypes.AddRange(requestTypes);
            allTypes.AddRange(responseTypes);
            allTypes.AddRange(types);

            var orderedTypes = allTypes
                .OrderBy(x => x.Namespace)
                .ThenBy(x => x.Name);

            foreach (var type in orderedTypes)
            {
                var fullTypeName = type.GetFullName();
                if (requestTypes.Contains(type))
                {
                    if (!existingTypes.Contains(fullTypeName))
                    {
                        MetadataType response = null;
                        MetadataOperationType operation;
                        if (requestTypesMap.TryGetValue(type, out operation))
                        {
                            response = operation.Response;
                        }

                        lastNS = AppendType(ref sb, type, lastNS, allTypes, 
                            new CreateTypeOptions
                            {
                                ImplementsFn = () =>
                                    {
                                        if (!Config.AddReturnMarker
                                            && !type.ReturnVoidMarker
                                            && type.ReturnMarkerTypeName == null)
                                            return null;

                                        if (type.ReturnVoidMarker)
                                            return "IReturnVoid";
                                        if (type.ReturnMarkerTypeName != null)
                                            return Type("IReturn`1", new[] { Type(type.ReturnMarkerTypeName) });
                                        return response != null
                                            ? Type("IReturn`1", new[] { Type(response.Name, response.GenericArgs) })
                                            : null;
                                    },
                                IsRequest = true,
                            });

                        existingTypes.Add(fullTypeName);
                    }
                }
                else if (responseTypes.Contains(type))
                {
                    if (!existingTypes.Contains(fullTypeName)
                        && !Config.IgnoreTypesInNamespaces.Contains(type.Namespace))
                    {
                        lastNS = AppendType(ref sb, type, lastNS, allTypes, 
                            new CreateTypeOptions { IsResponse = true, });

                        existingTypes.Add(fullTypeName);
                    }
                }
                else if (types.Contains(type) && !existingTypes.Contains(fullTypeName))
                {
                    lastNS = AppendType(ref sb, type, lastNS, allTypes, 
                        new CreateTypeOptions { IsType = true });
                    
                    existingTypes.Add(fullTypeName);
                }
            }

            if (lastNS != null)
                sb.AppendLine("}");
            sb.AppendLine();

            return StringBuilderCache.ReturnAndFree(sbInner);
        }
Exemple #29
0
        private string AppendType(ref StringBuilderWrapper sb, MetadataType type, string lastNS,
            CreateTypeOptions options)
        {
            sb = sb.Indent();

            sb.AppendLine();
            AppendComments(sb, type.Description);
            if (type.Routes != null)
            {
                AppendAttributes(sb, type.Routes.ConvertAll(x => x.ToMetadataAttribute()));
            }
            AppendAttributes(sb, type.Attributes);
            AppendDataContract(sb, type.DataContract);

            var typeName = Type(type.Name, type.GenericArgs);

            if (type.IsEnum.GetValueOrDefault())
            {
                sb.AppendLine("public static enum {0}".Fmt(typeName));
                sb.AppendLine("{");
                sb = sb.Indent();

                if (type.EnumNames != null)
                {
                    var hasIntValue = false;
                    for (var i = 0; i < type.EnumNames.Count; i++)
                    {
                        var name = type.EnumNames[i];
                        var value = type.EnumValues != null ? type.EnumValues[i] : null;

                        var delim = i == type.EnumNames.Count - 1 ? ";" : ",";
                        var serializeAs = JsConfig.TreatEnumAsInteger || (type.Attributes.Safe().Any(x => x.Name == "Flags"))
                            ? "@SerializedName(\"{0}\") ".Fmt(value)
                            : "";

                        sb.AppendLine(value == null
                            ? "{0}{1}".Fmt(name.ToPascalCase(), delim)
                            : serializeAs + "{0}({1}){2}".Fmt(name.ToPascalCase(), value, delim));

                        hasIntValue = hasIntValue || value != null;
                    }

                    if (hasIntValue)
                    {
                        sb.AppendLine();
                        sb.AppendLine("private final int value;");
                        sb.AppendLine("{0}(final int intValue) {{ value = intValue; }}".Fmt(typeName));
                        sb.AppendLine("public int getValue() { return value; }");
                    }
                }

                sb = sb.UnIndent();
                sb.AppendLine("}");
            }
            else
            {
                var defType = type.IsInterface()
                    ? "interface"
                    : "class";
                var extends = new List<string>();

                //: BaseClass, Interfaces
                if (type.Inherits != null)
                    extends.Add(Type(type.Inherits).InheritedType());

                string responseTypeExpression = null;

                var interfaces = new List<string>();
                if (options.ImplementsFn != null)
                {
                    var implStr = options.ImplementsFn();
                    if (!string.IsNullOrEmpty(implStr))
                    {
                        interfaces.Add(implStr);

                        if (implStr.StartsWith("IReturn<"))
                        {
                            var types = implStr.RightPart('<');
                            var returnType = types.Substring(0, types.Length - 1);

                            //Can't get .class from Generic Type definition
                            responseTypeExpression = returnType.Contains("<")
                                ? "new TypeToken<{0}>(){{}}.getType()".Fmt(returnType)
                                : "{0}.class".Fmt(returnType);
                        }
                    }
                    if (!type.Implements.IsEmpty())
                    {
                        foreach (var interfaceRef in type.Implements)
                        {
                            interfaces.Add(Type(interfaceRef));
                        }
                    }
                }

                var extend = extends.Count > 0
                    ? " extends " + extends[0]
                    : "";

                if (interfaces.Count > 0)
                    extend += " implements " + string.Join(", ", interfaces.ToArray());

                var addPropertyAccessors = Config.AddPropertyAccessors && !type.IsInterface();
                var settersReturnType = addPropertyAccessors && Config.SettersReturnThis ? typeName : null;

                sb.AppendLine("public static {0} {1}{2}".Fmt(defType, typeName, extend));
                sb.AppendLine("{");

                sb = sb.Indent();

                var addVersionInfo = Config.AddImplicitVersion != null && options.IsRequest;
                if (addVersionInfo)
                {
                    sb.AppendLine("public Integer {0} = {1};".Fmt("Version".PropertyStyle(), Config.AddImplicitVersion));

                    if (addPropertyAccessors)
                        sb.AppendPropertyAccessor("Integer", "Version", settersReturnType);
                }

                AddProperties(sb, type,
                    includeResponseStatus: Config.AddResponseStatus && options.IsResponse
                        && type.Properties.Safe().All(x => x.Name != typeof(ResponseStatus).Name),
                    addPropertyAccessors: addPropertyAccessors,
                    settersReturnType: settersReturnType);

                if (responseTypeExpression != null)
                {
                    sb.AppendLine("private static Object responseType = {0};".Fmt(responseTypeExpression));
                    sb.AppendLine("public Object getResponseType() { return responseType; }");
                }

                sb = sb.UnIndent();
                sb.AppendLine("}");
            }

            sb = sb.UnIndent();

            return lastNS;
        }
        public void AppendComments(StringBuilderWrapper sb, string desc)
        {
            if (desc == null) return;

            if (Config.AddDescriptionAsComments)
            {
                sb.AppendLine("///<summary>");
                sb.AppendLine("///{0}".Fmt(desc.SafeComment()));
                sb.AppendLine("///</summary>");
            }
            else
            {
                sb.AppendLine("[Description({0})]".Fmt(desc.QuotedSafeValue()));
            }
        }