169 lines
7.0 KiB
C#
169 lines
7.0 KiB
C#
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Text;
|
|||
|
using Mono.Cecil;
|
|||
|
using Mono.Cecil.Rocks;
|
|||
|
using Mono.Collections.Generic;
|
|||
|
using Mono.Documentation.Updater;
|
|||
|
using Mono.Documentation.Util;
|
|||
|
|
|||
|
namespace mdoc.Mono.Documentation.Updater.Formatters
|
|||
|
{
|
|||
|
public class JsFormatter : MemberFormatter
|
|||
|
{
|
|||
|
// For the V1 Pri1 implementation, we will not implement custom “retrievers”.
|
|||
|
// If a non-static class doesn’t have a public constructor
|
|||
|
// (in other words, it is not possible to automatically determine the call to instantiate an instance of the class),
|
|||
|
// the Javascript syntax should either:
|
|||
|
//
|
|||
|
// show a standard disclaimer such as:
|
|||
|
// “This class does not provide a public constructor” or
|
|||
|
// “See the remarks section for information on obtaining an instance of this class”
|
|||
|
// Give a degenerate declarative syntax, such as simply: “Windows.System.FolderLauncherOptions” for the FolderLauncherOptions class.
|
|||
|
// The specific solution to use here is still TBD. If you’re blocked, pick A1 for now.
|
|||
|
// We will investigate whether a Pri 2 feature to modify the syntax block with custom syntax is necessary.
|
|||
|
public override bool IsSupported(TypeReference tref)
|
|||
|
{
|
|||
|
var type = tref.Resolve();
|
|||
|
|
|||
|
if (type == null
|
|||
|
|| type.IsAbstract
|
|||
|
|| type.IsInterface// Interfaces: You cannot implement a Windows Runtime interface in JavaScript.
|
|||
|
|| type.HasGenericParameters
|
|||
|
|| !IsSupported(type.CustomAttributes)
|
|||
|
|| type.DeclaringType != null)//WinRT type can not be nested
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
if (type.IsEnum ||
|
|||
|
type.IsValueType ||
|
|||
|
DocUtils.IsDelegate(type))
|
|||
|
{
|
|||
|
if (type.IsEnum && !IsEnumSupported(type)) return false;
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
// Windows Runtime types cannot have multiple constructors with same number of arguments
|
|||
|
var publicConstructors = type.GetConstructors().Where(i => i.IsPublic).ToList();
|
|||
|
if (!publicConstructors.Any())
|
|||
|
return false;
|
|||
|
|
|||
|
var constructorsWithEqualNumberOfArguments = publicConstructors.GroupBy(x => x.Parameters.Count)
|
|||
|
.Where(g => g.Count() > 1)
|
|||
|
.Select(y => y.Key)
|
|||
|
.ToList();
|
|||
|
|
|||
|
return constructorsWithEqualNumberOfArguments.Count == 0;
|
|||
|
}
|
|||
|
|
|||
|
protected virtual bool IsEnumSupported(TypeDefinition type)
|
|||
|
{
|
|||
|
return type.GetMembers().Skip(1).Any();//skip "__value element"
|
|||
|
}
|
|||
|
|
|||
|
public override bool IsSupported(MemberReference mref)
|
|||
|
{
|
|||
|
switch (mref)
|
|||
|
{
|
|||
|
case PropertyDefinition propertyDefinition:
|
|||
|
if (!IsPropertySupported(propertyDefinition))
|
|||
|
return false;
|
|||
|
break;
|
|||
|
case MethodDefinition methodDefinition:
|
|||
|
if (!IsMethodSupported(methodDefinition))
|
|||
|
return false;
|
|||
|
break;
|
|||
|
case FieldDefinition _:
|
|||
|
return false;// In WinRT fields can be exposed only by structures.
|
|||
|
case AttachedEventDefinition _:
|
|||
|
return false;
|
|||
|
case AttachedPropertyDefinition _:
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
var member = mref.Resolve();
|
|||
|
return member != null
|
|||
|
&& !member.DeclaringType.HasGenericParameters
|
|||
|
&& !(mref is IGenericParameterProvider genericParameterProvider && genericParameterProvider.HasGenericParameters)
|
|||
|
&& !(mref is IMethodSignature methodSignature && methodSignature.Parameters.Any(i => i.ParameterType is GenericParameter))
|
|||
|
&& mref.DeclaringType.DeclaringType == null//WinRT type can not be nested
|
|||
|
&& IsSupported(member.CustomAttributes);
|
|||
|
}
|
|||
|
|
|||
|
private bool IsMethodSupported(MethodDefinition methodDefinition)
|
|||
|
{
|
|||
|
bool isDestructor = DocUtils.IsDestructor(methodDefinition);
|
|||
|
return
|
|||
|
!DocUtils.IsOperator(methodDefinition)
|
|||
|
&& (!isDestructor || methodDefinition.DeclaringType.Interfaces.Any(i => i.InterfaceType.FullName == "Windows.Foundation.IClosable"))
|
|||
|
&& methodDefinition.Parameters.All(i => IsSupported(i.CustomAttributes) && !(i.ParameterType is ByReferenceType))
|
|||
|
&& IsSupported(methodDefinition.MethodReturnType.CustomAttributes);
|
|||
|
}
|
|||
|
|
|||
|
// How to determine if an API supports JavaScript
|
|||
|
// Use the WebHostHidden attribute. If WebHostHidden is present, the API doesn’t support JavaScript.
|
|||
|
// None of the APIs in the “XAML” namespaces support JavaScript.
|
|||
|
protected bool IsSupported(Collection<CustomAttribute> memberCustomAttributes)
|
|||
|
{
|
|||
|
return
|
|||
|
memberCustomAttributes.All(
|
|||
|
i => i.AttributeType.FullName != "Windows.Foundation.Metadata.WebHostHiddenAttribute");
|
|||
|
}
|
|||
|
|
|||
|
protected virtual bool IsPropertySupported(PropertyDefinition property)
|
|||
|
{
|
|||
|
bool getVisible = property.GetMethod != null && property.GetMethod.IsPublic;
|
|||
|
bool setVisible = property.SetMethod != null && property.SetMethod.IsPublic;
|
|||
|
if (!setVisible && !getVisible)
|
|||
|
return false;
|
|||
|
|
|||
|
IEnumerable<MemberReference> defs = property.DeclaringType.GetDefaultMembers();
|
|||
|
foreach (MemberReference mi in defs)
|
|||
|
{
|
|||
|
if (mi == property)
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
return property.Parameters.Count == 0;
|
|||
|
}
|
|||
|
|
|||
|
protected override StringBuilder AppendParameters(StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters)
|
|||
|
{
|
|||
|
return buf.Append(string.Join(", ", parameters.Select(i => i.Name)));
|
|||
|
}
|
|||
|
|
|||
|
protected MethodDefinition GetConstructor(TypeDefinition type)
|
|||
|
{
|
|||
|
return type.GetConstructors()
|
|||
|
.Where(i => i.IsPublic)
|
|||
|
.OrderByDescending(i => i.Parameters.Count)
|
|||
|
.First();
|
|||
|
}
|
|||
|
|
|||
|
protected override string GetMethodName(MethodReference method)
|
|||
|
{
|
|||
|
if (DocUtils.IsDestructor(method.Resolve()))
|
|||
|
return "Close";
|
|||
|
return CamelCase(method.Name);
|
|||
|
}
|
|||
|
|
|||
|
protected override string GetTypeName(TypeReference type, DynamicParserContext context, bool appendGeneric = true)
|
|||
|
{
|
|||
|
int n = type.Name.IndexOf("`");
|
|||
|
if (n >= 0)
|
|||
|
return type.Name.Substring(0, n);
|
|||
|
return type.Name;
|
|||
|
}
|
|||
|
|
|||
|
protected string ProcessFullName(string fullName)
|
|||
|
{
|
|||
|
int n = fullName.IndexOf("`");
|
|||
|
if (n >= 0)
|
|||
|
return fullName.Substring(0, n);
|
|||
|
return fullName;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|