Code/SboxSuperuser/Engine/NativeSettings/NativeValue.cs

Utility for validating, normalizing and formatting native setting values. It validates keys and names, parses a string value against a CommandArgumentDescriptor using the command parser, and formats parsed arguments back to string.

Reflection
using System.Globalization;
using SboxSuperuser.Core.Contracts;
using SboxSuperuser.Engine.Commands;

namespace SboxSuperuser.Engine.NativeSettings;

internal static class NativeValue
{
	internal static string Key( string value )
	{
		ContractGuard.Key( value, nameof( value ) );
		if ( value.Length > 64 ) throw new ArgumentException( "Binding key exceeds 64 characters." );
		return value;
	}

	internal static string Name( string value )
	{
		if ( string.IsNullOrEmpty( value ) || value.Length > 96
			|| value.Any( character => !(character is >= 'a' and <= 'z' or >= '0' and <= '9' or '_') ) )
			throw new ArgumentException( "Native name must contain only lowercase letters, digits and underscores." );
		return value;
	}

	internal static string Normalize( NativeSettingDescriptor binding, string value, bool validateConstraints = true )
	{
		if ( value is null ) return null;
		// Direct native changes may be outside framework bounds; operators must still inspect and reset them.
		var argument = validateConstraints ? binding.Value : new CommandArgumentDescriptor( "value", binding.Description,
			binding.Value.Kind == CommandArgumentKind.Enum ? CommandArgumentKind.String : binding.Value.Kind );
		var descriptor = new CommandDescriptor( "settings.value", binding.Description, binding.Permission,
			"superuser.settings", new[] { argument } );
		var parsed = CommandArgumentParser.Parse( descriptor, new[] { value }, Array.Empty<CommandPlayer>() );
		return parsed.IsSuccess ? Format( argument, parsed.Arguments ) : null;
	}

	internal static string Format( CommandArgumentDescriptor argument, CommandArguments values ) => argument.Kind switch
	{
		CommandArgumentKind.Integer => values.Get<long>( argument.Name ).ToString( CultureInfo.InvariantCulture ),
		CommandArgumentKind.Number => values.Get<double>( argument.Name ).ToString( "R", CultureInfo.InvariantCulture ),
		CommandArgumentKind.Boolean => values.Get<bool>( argument.Name ) ? "1" : "0",
		_ => values.Get<string>( argument.Name )
	};
}