Editor/Prism/Model/NodeAttributes.cs

Attribute and enum declarations for the Prism editor node system. Defines NodeTier, and several attributes (NodeInfoAttribute, InAttribute, OutAttribute, InlineValueAttribute, NodeVersionAttribute, FormerlyKnownAsAttribute) used to annotate node classes and properties for metadata, serialization, UI presentation and migration.

Reflection
namespace Editor.Prism.Model;

/// <summary>How prominently a node type is offered in the search palette and library tree.</summary>
public enum NodeTier
{
	/// <summary>Shown without a search filter. The everyday set.</summary>
	Common,
	/// <summary>Shown only when searched for.</summary>
	Advanced,
	/// <summary>Shown only when searched for, and badged. May change without a migration.</summary>
	Experimental,
	/// <summary>Hidden from search. Still loads, still compiles, and suggests its replacement.</summary>
	Deprecated
}

/// <summary>
/// Declares a node type. <see cref="Id"/> is the stable identity written into saved documents —
/// it is decoupled from the C# type name on purpose, so renaming a class never breaks a graph.
/// </summary>
[AttributeUsage( AttributeTargets.Class, Inherited = false )]
public sealed class NodeInfoAttribute : Attribute, ITypeAttribute
{
	/// <summary>REQUIRED. Stable node type id, e.g. <c>prism.math.multiply</c>. Never change this.</summary>
	public string Id { get; init; }

	/// <summary>Display title. Falls back to a prettified type name.</summary>
	public string Title { get; init; }

	/// <summary>Slash-separated category, e.g. <c>Math/Basic</c>. Drives the menu path and library tree.</summary>
	public string Category { get; init; }

	/// <summary>Material Icons glyph name, or an image file name.</summary>
	public string Icon { get; init; }

	/// <summary>One-line description. Falls back to the XML summary of the class.</summary>
	public string Description { get; init; }

	/// <summary>Extra search terms, e.g. <c>mul</c>, <c>product</c>, <c>*</c>.</summary>
	public string[] Keywords { get; init; }

	/// <summary>How prominently the node is offered.</summary>
	public NodeTier Tier { get; init; } = NodeTier.Common;

	/// <summary>Version of Prism this node first appeared in.</summary>
	public string Since { get; init; }

	/// <summary>For deprecated nodes: the id of the node type that replaces this one.</summary>
	public string DeprecatedBy { get; init; }

	/// <summary>Set by the type library when the attributed class is registered.</summary>
	public Type TargetType { get; set; }
}

/// <summary>
/// Marks a property as an input port. Declaration order is socket order.
/// The property type should be <see cref="PortRef"/>.
/// </summary>
[AttributeUsage( AttributeTargets.Property, Inherited = true )]
public sealed class InAttribute : Attribute
{
	/// <summary>
	/// Declared port type: a concrete spelling (<c>float</c>, <c>float3</c>, <c>Texture2D</c>) or a
	/// type variable (<c>T</c>, <c>T.scalar</c>, <c>vecN</c>, <c>float{N}</c>, <c>any</c>).
	/// </summary>
	public InAttribute( string type = null )
	{
		Type = type;
	}

	/// <summary>The declared type spelling passed to the constructor.</summary>
	public string Type { get; }

	/// <summary>Display label. An empty string means an unlabelled socket.</summary>
	public string Name { get; init; }

	/// <summary>Optional collapsible port group on the card.</summary>
	public string Group { get; init; }

	/// <summary>When true, leaving this port unconnected with no inline value is an error.</summary>
	public bool Required { get; init; }

	/// <summary>Tooltip shown on the handle and the label.</summary>
	public string Tooltip { get; init; }

	/// <summary>Explicit sort order within the node. Lower sorts first; ties keep declaration order.</summary>
	public int Order { get; init; }
}

/// <summary>
/// Marks a property as an output port. Declaration order is socket order.
/// The property type should be <see cref="PortRef"/>.
/// </summary>
[AttributeUsage( AttributeTargets.Property, Inherited = true )]
public sealed class OutAttribute : Attribute
{
	/// <summary>
	/// Declared port type: a concrete spelling (<c>float</c>, <c>float3</c>, <c>Texture2D</c>) or a
	/// type variable (<c>T</c>, <c>T.scalar</c>, <c>vecN</c>, <c>float{N}</c>, <c>any</c>).
	/// </summary>
	public OutAttribute( string type = null )
	{
		Type = type;
	}

	/// <summary>The declared type spelling passed to the constructor.</summary>
	public string Type { get; }

	/// <summary>Display label. An empty string means an unlabelled socket.</summary>
	public string Name { get; init; }

	/// <summary>Optional collapsible port group on the card.</summary>
	public string Group { get; init; }

	/// <summary>Tooltip shown on the handle and the label.</summary>
	public string Tooltip { get; init; }

	/// <summary>Explicit sort order within the node. Lower sorts first; ties keep declaration order.</summary>
	public int Order { get; init; }
}

/// <summary>
/// Marks a property as the inline literal used when the named input port has nothing connected.
/// The property is edited by the pill drawn beside the handle and serialized under <c>inline</c>.
/// </summary>
[AttributeUsage( AttributeTargets.Property, Inherited = true )]
public sealed class InlineValueAttribute : Attribute
{
	/// <summary>Bind this property to the inline value of <paramref name="portName"/>.</summary>
	public InlineValueAttribute( string portName )
	{
		PortName = portName;
	}

	/// <summary>The port whose unconnected value this property supplies.</summary>
	public string PortName { get; }
}

/// <summary>
/// Per-node-type serialization version, written as <c>v</c> on every saved node. Bump it whenever
/// the shape of the node's properties changes, and register a matching migration.
/// </summary>
[AttributeUsage( AttributeTargets.Class, Inherited = false )]
public sealed class NodeVersionAttribute : Attribute
{
	/// <summary>Declare the node-type version.</summary>
	public NodeVersionAttribute( int version )
	{
		Version = version;
	}

	/// <summary>The current version of this node type.</summary>
	public int Version { get; }
}

/// <summary>
/// An old node type id (on a class) or an old port id (on a property) that must still deserialize
/// into this one. Applies to inputs as well as outputs, unlike the built-in editor's alias support.
/// </summary>
[AttributeUsage( AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = true, Inherited = false )]
public sealed class FormerlyKnownAsAttribute : Attribute
{
	/// <summary>Declare a former name.</summary>
	public FormerlyKnownAsAttribute( string oldName )
	{
		OldName = oldName;
	}

	/// <summary>The name this type or port used to have.</summary>
	public string OldName { get; }
}