feat(objects): ExtractProperties — [CommandProperty] props with enum expansion

Add ObjectIntrospection.ExtractProperties(Type) to extract public instance
properties carrying [CommandProperty] attribute, including inherited ones.
Properties include type via ObjectNaming.FriendlyTypeName, read/write access
levels, readOnly flag, and enum values expanded via Enum.GetNames.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kamron Batman 2026-07-19 10:54:40 -07:00
parent 95d57afdec
commit 685fbc146e
No known key found for this signature in database
GPG key ID: 7D81DF26D9A5D94A
2 changed files with 53 additions and 0 deletions

View file

@ -0,0 +1,23 @@
using System.Linq;
using Server.Commands;
using Server.Items;
using Xunit;
namespace UOContent.Tests.Commands.Objects;
[Collection("Sequential UOContent Tests")]
public class ObjectIntrospectionPropertiesTests
{
[Fact]
public void ExtractProperties_includes_inherited_item_command_properties()
{
var props = ObjectIntrospection.ExtractProperties(typeof(Runebook));
var hue = Assert.Single(props, p => p.Name == "Hue");
Assert.Equal("int", hue.Type);
var lootType = Assert.Single(props, p => p.Name == "LootType");
Assert.NotNull(lootType.EnumValues);
Assert.Contains("Blessed", lootType.EnumValues);
}
}

View file

@ -90,4 +90,34 @@ public static class ObjectIntrospection
return docs;
}
public static List<PropertyDoc> ExtractProperties(Type type)
{
var docs = new List<PropertyDoc>();
var props = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var p in props)
{
var attr = p.GetCustomAttribute<CommandPropertyAttribute>(true);
if (attr == null)
{
continue;
}
var pt = p.PropertyType;
docs.Add(
new PropertyDoc
{
Name = p.Name,
Type = ObjectNaming.FriendlyTypeName(pt),
ReadLevel = attr.ReadLevel.ToString(),
WriteLevel = attr.WriteLevel.ToString(),
ReadOnly = attr.ReadOnly || !p.CanWrite,
EnumValues = pt.IsEnum ? Enum.GetNames(pt) : null
}
);
}
return docs;
}
}