Skip to content

Commit

Permalink
Add schema to configs that enables autocompletion
Browse files Browse the repository at this point in the history
  • Loading branch information
flcl42 committed Sep 26, 2024
1 parent f8c910d commit 73170da
Show file tree
Hide file tree
Showing 4 changed files with 315 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Runner/configs/op-mainnet.cfg
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "https://gist.githubusercontent.com/flcl42/25b0396678b02cfc0c5dc1d68ea085a7/raw/2fda5155f38e9816bead94682eac92d3b7e74b8c/nethermind-config-schema.json",
"Init": {
"ChainSpecPath": "chainspec/op-mainnet.json",
"GenesisHash": "0x7ca38a1916c42007829c55e69d3e9a73265554b586a499015373241b8a3fa48b",
Expand Down
77 changes: 77 additions & 0 deletions tools/SchemaGenerator/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@

using NJsonSchema;
using System.Reflection;
using System.Reflection.Emit;
using Nethermind.Config;
using Nethermind.Core.Collections;

Type iConfigType = typeof(IConfig);

Type[] types = [
..Directory.GetFiles(".", "Nethermind.*.dll").SelectMany(f => GetConfigTypes(Assembly.LoadFrom(f))),
];

var assemblyName = new AssemblyName("Nethermind.Config");
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");

TypeBuilder typeBuilder = moduleBuilder.DefineType("NethermindConfig", TypeAttributes.Public);

foreach (Type configInterface in types)
{
CreateProperty(typeBuilder, configInterface);
}

Type configType = typeBuilder.CreateType();

JsonSchema schema = JsonSchema.FromType(configType);

foreach (var def in schema.Definitions)
{
if(def.Value.Enumeration is { Count: > 0 })
{
def.Value.Type = JsonObjectType.String;
def.Value.Enumeration.Clear();
def.Value.Enumeration.AddRange(def.Value.EnumerationNames);
}
}

Console.WriteLine(schema.ToJson());

void CreateProperty(TypeBuilder typeBuilder, Type classType)
{
Type interfaceType = classType.GetInterfaces().First(i => iConfigType.IsAssignableFrom(i) && i != iConfigType);
string propertyName = interfaceType.Name.Substring(1, interfaceType.Name.Length - 7);
FieldBuilder fieldBuilder = typeBuilder.DefineField($"_{propertyName}", interfaceType, FieldAttributes.Private);
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, interfaceType, null);
MethodBuilder getMethodBuilder = typeBuilder.DefineMethod($"get_{propertyName}",
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
interfaceType,
Type.EmptyTypes);

ILGenerator getIL = getMethodBuilder.GetILGenerator();
getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, fieldBuilder);
getIL.Emit(OpCodes.Ret);

// Define the 'set' accessor method
MethodBuilder setMethodBuilder = typeBuilder.DefineMethod($"set_{propertyName}",
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
null,
[interfaceType]);

ILGenerator setIL = setMethodBuilder.GetILGenerator();
setIL.Emit(OpCodes.Ldarg_0);
setIL.Emit(OpCodes.Ldarg_1);
setIL.Emit(OpCodes.Stfld, fieldBuilder);
setIL.Emit(OpCodes.Ret);

// Map the get and set methods to the property
propertyBuilder.SetGetMethod(getMethodBuilder);
propertyBuilder.SetSetMethod(setMethodBuilder);
}

IEnumerable<Type> GetConfigTypes(Assembly assembly)
{
return assembly.GetTypes().Where(t => iConfigType.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract);
}
20 changes: 20 additions & 0 deletions tools/SchemaGenerator/SchemaGenerator.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="NJsonSchema" Version="11.0.2" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Nethermind\Nethermind.Api\Nethermind.Api.csproj" />
<ProjectReference Include="..\..\src\Nethermind\Nethermind.Init.Snapshot\Nethermind.Init.Snapshot.csproj" />
<ProjectReference Include="..\..\src\Nethermind\Nethermind.Optimism\Nethermind.Optimism.csproj" />
</ItemGroup>

</Project>
Loading

0 comments on commit 73170da

Please sign in to comment.