using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; namespace LLM.Editor.Analysis { public class GetComponentSchemaProvider : IContextProvider { public class MemberSchema { public string name; public string memberType; // "Property" or "Field" public string valueType; } public object GetContext(Object target, string qualifier) { if (string.IsNullOrEmpty(qualifier)) { return "Error: A component type name (qualifier) is required."; } try { var type = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(assembly => assembly.GetTypes()) .FirstOrDefault(t => t.FullName == qualifier && typeof(Component).IsAssignableFrom(t)); if (type == null) { return $"Error: Could not find a Component type named '{qualifier}'."; } var members = new List(); // 1. Get all public properties with a public setter, excluding obsolete/hidden ones. var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.CanWrite && p.GetSetMethod(true) != null && p.GetSetMethod(true).IsPublic) .Where(p => !p.IsDefined(typeof(ObsoleteAttribute), true)) .Where(p => !p.IsDefined(typeof(HideInInspector), true)); members.AddRange(properties.Select(p => new MemberSchema { name = p.Name, memberType = "Property", valueType = p.PropertyType.FullName })); // 2. Get all fields (public and private) to check for serialization attributes. var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); var serializableFields = fields.Where(f => { if (f.IsDefined(typeof(ObsoleteAttribute), true)) return false; if (f.IsDefined(typeof(HideInInspector), true)) return false; // A field is serialized if it's public OR has the [SerializeField] attribute. return f.IsPublic || f.IsDefined(typeof(SerializeField), true); }); members.AddRange(serializableFields.Select(f => new MemberSchema { name = f.Name, memberType = "Field", valueType = f.FieldType.FullName })); // Return a distinct list, as a property can have a backing field with the same name. return members.GroupBy(m => m.name) .Select(g => g.First()) .OrderBy(m => m.name) .ToList(); } catch (Exception e) { return $"Error reflecting on type '{qualifier}': {e.Message}"; } } } }