Пример #1
0
        /// <summary>
        /// Generate a javascript "class"
        /// </summary>
        private static void GenerateTypeDocumentation(TextWriter writer, Type type, XmlDocument xmlDoc, ConsoleParameters parms, List <Type> enumerationTypes, List <Type> alreadyGenerated, Dictionary <String, object> metaData)
        {
            if (parms.NoAbstract && type.IsAbstract)
            {
                return;
            }

            var propertyData = new Dictionary <String, object>();

            if (!type.IsAbstract && !type.IsInterface && !type.IsGenericTypeDefinition)
            {
                metaData.Add(type.Name, propertyData);
            }

            if (alreadyGenerated.Contains(type))
            {
                return;
            }
            else
            {
                alreadyGenerated.Add(type);
            }
            writer.WriteLine("// {0}", type.AssemblyQualifiedName);
            writer.WriteLine("//if(!{0})", type.GetCustomAttribute <JsonObjectAttribute>().Id);
            writer.WriteLine("/**");
            writer.WriteLine(" * @class");
            writer.WriteLine(" * @constructor");
            writer.WriteLine(" * @public");
            if (type.IsAbstract)
            {
                writer.WriteLine(" * @abstract");
            }
            var jobject = type.GetCustomAttribute <JsonObjectAttribute>();

            if (type.BaseType != typeof(Object) &&
                (!type.BaseType.IsAbstract ^ !parms.NoAbstract))
            {
                writer.WriteLine(" * @extends {0}", type.BaseType.GetCustomAttribute <JsonObjectAttribute>().Id);
            }

            // Lookup the summary information
            var typeDoc = xmlDoc.SelectSingleNode(String.Format("//*[local-name() = 'member'][@name = 'T:{0}']", type.FullName));

            if (typeDoc != null)
            {
                if (typeDoc.SelectSingleNode(".//*[local-name() = 'summary']") != null)
                {
                    writer.WriteLine(" * @summary {0}", TransformXDoc(typeDoc.SelectSingleNode(".//*[local-name() = 'summary']")));
                }
                if (typeDoc.SelectSingleNode(".//*[local-name() = 'remarks']") != null)
                {
                    writer.WriteLine(" * @description {0}", TransformXDoc(typeDoc.SelectSingleNode(".//*[local-name() = 'remarks']")));
                }
                if (typeDoc.SelectSingleNode(".//*[local-name() = 'example']") != null)
                {
                    writer.WriteLine(" * @example {0}", typeDoc.SelectSingleNode(".//*[local-name() = 'example']").InnerText.Replace("\r\n", ""));
                }
            }

            List <KeyValuePair <String, String> > copyCommands = new List <KeyValuePair <string, string> >();
            Dictionary <String, String>           propDocs     = new Dictionary <string, string>();

            // Get all properties and document them
            foreach (var itm in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                if (itm.GetCustomAttribute <JsonPropertyAttribute>() == null && itm.GetCustomAttribute <SerializationReferenceAttribute>() == null)
                {
                    continue;
                }

                Type itmType = itm.PropertyType;
                if (itmType.IsGenericType)
                {
                    itmType = itmType.GetGenericArguments()[0];
                }

                var itmJobject = itmType.GetCustomAttribute <JsonObjectAttribute>();
                if (itmJobject == null)
                {
                    if (itmType.StripNullable().IsEnum)
                    {
                        itmJobject = new JsonObjectAttribute(String.Format("{0}", itmType.Name));
                    }
                    else if (!primitives.TryGetValue(itmType, out itmJobject))
                    {
                        itmJobject = new JsonObjectAttribute(itmType.Name);
                    }
                }
                else
                {
                    itmJobject = new JsonObjectAttribute(String.Format("{0}", itmJobject.Id));
                }

                var simpleAtt = itmType.GetCustomAttribute <SimpleValueAttribute>();
                if (simpleAtt != null)
                {
                    var simpleProperty = itmType.GetProperty(simpleAtt.ValueProperty);
                    if (!primitives.TryGetValue(simpleProperty.PropertyType, out itmJobject))
                    {
                        itmJobject = new JsonObjectAttribute(simpleProperty.PropertyType.Name);
                    }
                }

                var originalType = itmJobject.Id;

                // Is this a classified object? if so then the classifier values act as properties themselves
                var classAttr = itmType.GetCustomAttribute <ClassifierAttribute>();
                if (classAttr != null && itm.PropertyType.IsGenericType)
                {
                    itmJobject = new JsonObjectAttribute("object");
                }
                else if (itm.Name.Contains("TimeXml") || itm.Name.Contains("DateXml")) // XML Representations of offsets
                {
                    itmJobject = new JsonObjectAttribute("Date");
                }

                writer.Write(" * @property {{{0}}} ", itmJobject.Id);
                var jprop = itm.GetCustomAttribute <JsonPropertyAttribute>();
                var redir = itm.GetCustomAttribute <SerializationReferenceAttribute>();
                if (jprop != null)
                {
                    writer.Write(jprop.PropertyName);
                    copyCommands.Add(new KeyValuePair <String, String>(jprop.PropertyName, itmJobject.Id));
                }
                else if (redir != null)
                {
                    var backingProperty = type.GetProperty(redir.RedirectProperty);
                    jprop = backingProperty.GetCustomAttribute <JsonPropertyAttribute>();
                    writer.Write("{0}Model [Delay loaded from {0}], ", jprop.PropertyName);
                    copyCommands.Add(new KeyValuePair <String, String>(jprop.PropertyName + "Model", itmJobject.Id));
                }
                else
                {
                    writer.Write(itm.Name + "Model");
                    copyCommands.Add(new KeyValuePair <string, string>(itm.Name + "Model", itmJobject.Id));
                }

                // We're going to add this to metadata
                var propertyInfo = new Dictionary <String, Object>();
                if (propertyData.TryGetValue(jprop.PropertyName, out object cValue))
                {
                    propertyInfo = (Dictionary <String, Object>)cValue;
                    if (propertyInfo["type"].Equals("Guid"))
                    {
                        propertyInfo["type"] = itm.PropertyType.StripGeneric().Name;
                    }
                }
                else
                {
                    propertyData.Add(jprop.PropertyName, propertyInfo);
                    // Now - let's add some info
                    propertyInfo.Add("isCollection", typeof(ICollection).IsAssignableFrom(itm.PropertyType));
                    propertyInfo.Add("type", itm.PropertyType.StripGeneric().Name);
                }

                if (propertyInfo["isCollection"].Equals(true)) // Classifier?
                {
                    var classifier = itm.PropertyType.StripGeneric().GetCustomAttribute <ClassifierAttribute>();
                    if (classifier != null)
                    {
                        var classifierProperty = itm.PropertyType.StripGeneric().GetProperty(classifier.ClassifierProperty);
                        propertyInfo.Add("classifierType", classifierProperty.PropertyType.StripGeneric().Name);

                        var sredir = classifierProperty.GetCustomAttribute <SerializationReferenceAttribute>();
                        if (sredir != null)
                        {
                            classifierProperty = itm.PropertyType.StripGeneric().GetProperty(sredir.RedirectProperty);
                        }

                        var binding = classifierProperty.GetCustomAttribute <BindingAttribute>();
                        if (binding != null)
                        {
                            propertyInfo.Add("classifierValues", binding.Binding.GetFields().Where(r => r.FieldType == typeof(Guid)).Select(o => o.Name));
                        }
                    }
                }
                else
                {
                    var binding = itm.GetCustomAttribute <BindingAttribute>();
                    if (binding != null)
                    {
                        propertyInfo.Add("values", binding.Binding.GetFields().Where(r => r.FieldType == typeof(Guid)).Select(o => o.Name));
                    }
                }

                // Output documentation
                typeDoc = xmlDoc.SelectSingleNode(String.Format("//*[local-name() = 'member'][@name = 'P:{0}.{1}']", itm.DeclaringType.FullName, itm.Name));
                if (typeDoc != null)
                {
                    var docNode = typeDoc.SelectSingleNode(".//*[local-name() = 'summary']");
                    if (docNode != null)
                    {
                        var jsDoc = TransformXDoc(docNode);
                        if (propDocs.TryGetValue(jprop.PropertyName, out string edoc))
                        {
                            if (edoc.Length < jsDoc.Length)
                            {
                                propDocs[jprop.PropertyName] = jsDoc;
                            }
                        }
                        else
                        {
                            propDocs.Add(jprop.PropertyName, jsDoc);
                        }
                        writer.Write($" {jsDoc}");
                    }
                }

                var bindAttr = itm.GetCustomAttribute <BindingAttribute>();
                if (itmType.StripNullable().IsEnum)
                {
                    bindAttr = new BindingAttribute(itmType.StripNullable());
                }

                if (bindAttr != null)
                {
                    enumerationTypes.Add(bindAttr.Binding);
                    writer.Write("(see: {{@link {0}}} for values)", bindAttr.Binding.Name);
                }
                writer.WriteLine();

                // Classified object? If so we need to clarify how the object is propogated
                if (classAttr != null && itm.PropertyType.IsGenericType)
                {
                    // Does the classifier have a binding
                    var classProperty = itmType.GetProperty(classAttr.ClassifierProperty);
                    if (classProperty.GetCustomAttribute <SerializationReferenceAttribute>() != null)
                    {
                        classProperty = itmType.GetProperty(classProperty.GetCustomAttribute <SerializationReferenceAttribute>().RedirectProperty);
                    }
                    bindAttr = classProperty.GetCustomAttribute <BindingAttribute>();
                    if (bindAttr != null)
                    {
                        enumerationTypes.Add(bindAttr.Binding);

                        // Binding attribute found so lets enumerate it
                        foreach (var fi in bindAttr.Binding.GetFields(BindingFlags.Public | BindingFlags.Static))
                        {
                            writer.Write(" * @property {{{0}}} {1}.{2} ", originalType, jprop.PropertyName, fi.Name, classProperty.GetCustomAttribute <JsonPropertyAttribute>()?.PropertyName);
                            typeDoc = xmlDoc.SelectSingleNode(String.Format("//*[local-name() = 'member'][@name = 'F:{0}.{1}']", fi.DeclaringType.FullName, fi.Name));
                            if (typeDoc != null)
                            {
                                if (typeDoc.SelectSingleNode(".//*[local-name() = 'summary']") != null)
                                {
                                    writer.Write(typeDoc.SelectSingleNode(".//*[local-name() = 'summary']").InnerText.Replace("\r\n", ""));
                                }
                            }
                            writer.WriteLine();
                        }
                        writer.WriteLine(" * @property {{{0}}} {1}.$other Unclassified", originalType, jprop.PropertyName);
                    }
                    else
                    {
                        writer.Write(" * @property {{{0}}} {1}.{2} ", originalType, jprop.PropertyName, "classifier");
                        writer.Write(" where classifier is from {{@link {0}}} {1}", classProperty.DeclaringType.GetCustomAttribute <JsonObjectAttribute>().Id, classProperty.GetCustomAttribute <JsonPropertyAttribute>()?.PropertyName);
                        writer.WriteLine();
                    }
                }
            }
            writer.WriteLine(" * @param {{{0}}} copyData Copy constructor (if present)", jobject.Id);

            writer.WriteLine(" */");
            writer.WriteLine("function {0} (copyData) {{ ", jobject.Id);

            writer.WriteLine("\tthis.$type = '{0}';", jobject.Id);
            writer.WriteLine("\tif(copyData) {");
            copyCommands.Reverse();
            // Get all properties and document them
            foreach (var itm in copyCommands.Where(o => o.Key != "$type"))
            {
                writer.WriteLine("\t/**");
                if (propDocs.TryGetValue(itm.Key, out string doc))
                {
                    writer.WriteLine("\t * @summary {0}", doc);
                }
                writer.WriteLine("\t * @type {{{0}}} ", itm.Value);
                writer.WriteLine("\t */");
                writer.WriteLine("\tthis.{0} = copyData.{0};", itm.Key);
            }
            writer.WriteLine("\t}");

            writer.WriteLine("}}  // {0} ", jobject.Id);
        }
Пример #2
0
        /// <summary>
        /// Generate enumeration documentation
        /// </summary>
        private static void GenerateEnumerationDocumentation(TextWriter writer, Type type, XmlDocument xmlDoc, ConsoleParameters parms)
        {
            var jobject = type.GetCustomAttribute <JsonObjectAttribute>();

            if (jobject == null)
            {
                jobject = new JsonObjectAttribute(type.Name);
            }

            writer.WriteLine("// {0}", type.AssemblyQualifiedName);
            writer.WriteLine("// if(!{0})", jobject.Id);

            writer.WriteLine("/**");
            writer.WriteLine(" * @enum {string}");
            writer.WriteLine(" * @public");
            writer.WriteLine(" * @readonly");

            // Lookup the summary information
            var typeDoc = xmlDoc.SelectSingleNode(String.Format("//*[local-name() = 'member'][@name = 'T:{0}']", type.FullName));

            if (typeDoc != null)
            {
                if (typeDoc.SelectSingleNode(".//*[local-name() = 'summary']") != null)
                {
                    writer.WriteLine(" * @summary {0}", typeDoc.SelectSingleNode(".//*[local-name() = 'summary']").InnerText.Replace("\r\n", ""));
                }
                if (typeDoc.SelectSingleNode(".//*[local-name() = 'remarks']") != null)
                {
                    writer.WriteLine(" * @description {0}", typeDoc.SelectSingleNode(".//*[local-name() = 'remarks']").InnerText.Replace("\r\n", ""));
                }
                if (typeDoc.SelectSingleNode(".//*[local-name() = 'example']") != null)
                {
                    writer.WriteLine(" * @example {0}", typeDoc.SelectSingleNode(".//*[local-name() = 'example']").InnerText.Replace("\r\n", ""));
                }
            }
            writer.WriteLine(" */");
            writer.WriteLine("const {0} = {{ ", jobject.Id);

            // Enumerate fields
            foreach (var fi in type.GetFields(BindingFlags.Public | BindingFlags.Static))
            {
                writer.WriteLine("\t/** ");
                writer.Write("\t * ");
                typeDoc = xmlDoc.SelectSingleNode(String.Format("//*[local-name() = 'member'][@name = 'F:{0}.{1}']", fi.DeclaringType.FullName, fi.Name));
                if (typeDoc != null)
                {
                    if (typeDoc.SelectSingleNode(".//*[local-name() = 'summary']") != null)
                    {
                        writer.Write(typeDoc.SelectSingleNode(".//*[local-name() = 'summary']").InnerText.Replace("\r\n", ""));
                    }
                }
                writer.WriteLine();
                writer.WriteLine("\t */");

                writer.WriteLine("\t{0} : '{1}',", fi.Name, fi.GetValue(null));
            }

            writer.WriteLine("}}  // {0} ", jobject.Id);
        }