169 lines
7.0 KiB
C#
Raw Normal View History

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 doesnt 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 youre 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 doesnt 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;
}
}
}