ktsu.Schema 1.4.0

ktsu.Schema

A C# library for defining, managing, and editing data structure schemas with a rich type system, type-safe identifiers, and polymorphic JSON serialization.

NuGet License: MIT

Overview

ktsu.Schema lets you define structured data models programmatically or visually, then serialize them to .schema.json files. It provides a foundation for code generation, data validation, and tooling that needs to understand your data structures at a metadata level.

The solution contains three projects:

  • Schema - Core library with schema definition types, a rich type system, and JSON serialization
  • Schema.Test - Unit tests for the core library
  • SchemaEditor - ImGui-based desktop application for visual schema editing

Installation

Install via NuGet:

dotnet add package ktsu.Schema

Or add to your project file:

<PackageReference Include="ktsu.Schema" />

Requirements

  • .NET 7.0, 8.0, 9.0, or 10.0

Quick Start

Create a Schema

using ktsu.Schema.Models;
using ktsu.Schema.Models.Names;
using ktsu.Schema.Models.Types;
using ktsu.Semantics.Strings;
using SchemaTypes = ktsu.Schema.Models.Types;

// Create a new schema
Schema schema = new();

// Add an enum
SchemaEnum? roleEnum = schema.AddEnum("UserRole".As<EnumName>());
roleEnum?.TryAddValue("Admin".As<EnumValueName>());
roleEnum?.TryAddValue("User".As<EnumValueName>());
roleEnum?.TryAddValue("Guest".As<EnumValueName>());

// Add a class with typed members
SchemaClass? userClass = schema.AddClass("User".As<ClassName>());
if (userClass != null)
{
    SchemaMember? id = userClass.AddMember("Id".As<MemberName>());
    id?.SetType(new SchemaTypes.Int());

    SchemaMember? name = userClass.AddMember("Name".As<MemberName>());
    name?.SetType(new SchemaTypes.String());

    SchemaMember? email = userClass.AddMember("Email".As<MemberName>());
    email?.SetType(new SchemaTypes.String());

    SchemaMember? role = userClass.AddMember("Role".As<MemberName>());
    role?.SetType(new SchemaTypes.Enum { EnumName = "UserRole".As<EnumName>() });

    SchemaMember? createdAt = userClass.AddMember("CreatedAt".As<MemberName>());
    createdAt?.SetType(new SchemaTypes.DateTime());
}

Work with Arrays and Object References

// Add a Project class
SchemaClass? projectClass = schema.AddClass("Project".As<ClassName>());
SchemaMember? projectId = projectClass?.AddMember("Id".As<MemberName>());
projectId?.SetType(new SchemaTypes.Int());
SchemaMember? projectName = projectClass?.AddMember("Name".As<MemberName>());
projectName?.SetType(new SchemaTypes.String());

// Add an array of projects to the User class
SchemaMember? projects = userClass?.AddMember("Projects".As<MemberName>());
projects?.SetType(new SchemaTypes.Array
{
    ElementType = new SchemaTypes.Object { ClassName = "Project".As<ClassName>() },
    Container = "vector".As<ContainerName>()
});

// Use a keyed collection (map)
SchemaMember? projectsMap = userClass?.AddMember("ProjectsById".As<MemberName>());
projectsMap?.SetType(new SchemaTypes.Array
{
    ElementType = new SchemaTypes.Object { ClassName = "Project".As<ClassName>() },
    Container = "map".As<ContainerName>(),
    Key = "Id".As<MemberName>()
});

Create a Schema from .NET Types

// Generate a schema class from an existing .NET type using reflection
schema.AddClass(typeof(MyExistingClass));

Serialize and Deserialize

// Serialize to JSON
string json = SchemaSerializer.Serialize(schema);

// Deserialize from JSON (automatically calls Reassociate())
if (SchemaSerializer.TryDeserialize(json, out Schema? loaded))
{
    Console.WriteLine($"Loaded {loaded.Classes.Count} classes");
}

Query the Schema

// Retrieve classes and enums
if (schema.TryGetClass("User".As<ClassName>(), out SchemaClass? foundClass))
{
    foreach (SchemaMember member in foundClass.Members)
    {
        Console.WriteLine($"  {member.Name}: {member.Type.DisplayName}");
    }
}

if (schema.TryGetEnum("UserRole".As<EnumName>(), out SchemaEnum? foundEnum))
{
    foreach (EnumValueName value in foundEnum.Values)
    {
        Console.WriteLine($"  {value}");
    }
}

Type System

The schema supports a rich set of types through the SchemaTypes class, all inheriting from BaseType with polymorphic JSON serialization via System.Text.Json:

Category Types
Numeric Int, Long, Float, Double
Text String
Logic Bool
Temporal DateTime, TimeSpan
Vectors Vector2, Vector3, Vector4
Colors ColorRGB, ColorRGBA
Complex Array, Object, Enum
Special None

Types expose classification properties like IsPrimitive, IsNumeric, IsIntegral, IsDecimal, IsArray, IsObject, IsContainer, and IsBuiltIn.

Strong String Types

All identifiers use type-safe semantic string wrappers from ktsu.Semantics.Strings to prevent mixing up different kinds of names at compile time:

  • ClassName - Schema class names
  • MemberName - Class member names
  • EnumName - Enumeration names
  • EnumValueName - Enumeration value names
  • BaseTypeName - Type names
  • ContainerName - Container type names
  • DataSourceName - Data source names
  • CodeGeneratorName - Code generator names

Convert strings using the .As<T>() extension method: "User".As<ClassName>()

JSON Serialization

Use SchemaSerializer for JSON serialization with System.Text.Json. The serializer uses camelCase property names and polymorphic type discrimination via the TypeName discriminator:

{
  "classes": [
    {
      "name": "User",
      "description": "",
      "members": [
        {
          "name": "Id",
          "description": "",
          "type": { "TypeName": "Int" },
          "memberDescription": ""
        },
        {
          "name": "Role",
          "description": "",
          "type": { "TypeName": "Enum", "enumName": "UserRole" },
          "memberDescription": ""
        }
      ]
    }
  ],
  "enums": [
    {
      "name": "UserRole",
      "description": "",
      "values": ["Admin", "User", "Guest"]
    }
  ],
  "dataSources": [],
  "codeGenerators": []
}

SchemaSerializer.TryDeserialize() automatically calls Reassociate() to re-establish parent-child relationships after deserialization.

Schema Editor

The SchemaEditor is an ImGui-based desktop application for visually creating and editing .schema.json files.

Running the Editor

dotnet run --project SchemaEditor

Features

  • Tree view for navigating classes, enums, data sources, and code generators
  • Property panels for editing members and types
  • Type selection dialogs
  • Create, open, and save schema files
  • Resizable split-panel layout with persistent settings

Building

# Build the entire solution
dotnet build

# Run tests
dotnet test

# Build a specific project
dotnet build Schema/Schema.csproj

License

This project is licensed under the MIT License. See LICENSE.md for details.

No packages depend on ktsu.Schema.

## v1.4.0 (minor) Changes since v1.3.0: - [minor] Complete DataSource and CodeGenerator models, fix Reassociate ([@matt-edmondson](https://github.com/matt-edmondson)) - [minor] Add SchemaSerializer, JSON serialization support, and comprehensive test suite ([@matt-edmondson](https://github.com/matt-edmondson)) - Remove .github\workflows\project.yml ([@matt-edmondson](https://github.com/matt-edmondson)) - Update project SDK from ktsu.Sdk.App to ktsu.Sdk.ImGuiApp in SchemaEditor.csproj ([@matt-edmondson](https://github.com/matt-edmondson)) - migrate to dotnet 10 ([@matt-edmondson](https://github.com/matt-edmondson)) - Replace StrongStrings and StrongPaths with ktsu.Semantics across the codebase, updating relevant class constraints and references to use ISemanticString. This change enhances type safety and aligns with the latest library standards. ([@matt-edmondson](https://github.com/matt-edmondson)) - Refactor Schema Library Documentation and Examples ([@matt-edmondson](https://github.com/matt-edmondson)) - Update tests to use new SchemaProvider API - remove dependency on obsolete Schema class ([@matt-edmondson](https://github.com/matt-edmondson)) - Update packages ([@matt-edmondson](https://github.com/matt-edmondson)) - Update package references and add XML declaration in project files ([@matt-edmondson](https://github.com/matt-edmondson)) - Refactor schema management by introducing a new Schema class and related models, replacing the previous SchemaProvider and related interfaces. This update enhances type safety and aligns with the latest design principles, removing obsolete classes and improving the overall structure of the schema definitions. ([@matt-edmondson](https://github.com/matt-edmondson)) - Complete Schema refactoring to DI SchemaProvider - remove serialization and filesystem concerns ([@matt-edmondson](https://github.com/matt-edmondson)) - [minor] Add CodeGenerator tree, DataSource property panel, and use SchemaSerializer in editor ([@matt-edmondson](https://github.com/matt-edmondson)) - Remove Directory.Build.props and Directory.Build.targets files; add copyright notices to schema files; refactor variable declarations for consistency. ([@matt-edmondson](https://github.com/matt-edmondson)) - Update README.md with comprehensive project details and usage examples ([@matt-edmondson](https://github.com/matt-edmondson)) - Update package references and restructure project files for improved organization and clarity ([@matt-edmondson](https://github.com/matt-edmondson)) - Update project SDK references and README formatting ([@matt-edmondson](https://github.com/matt-edmondson)) - Add schema contract interfaces for schema definitions, including ISchema, ISchemaChild, ISchemaClass, ISchemaEnum, and related name interfaces. This introduces a structured approach to schema management without serialization concerns. ([@matt-edmondson](https://github.com/matt-edmondson)) - Add CLAUDE.md for project guidance and documentation ([@matt-edmondson](https://github.com/matt-edmondson)) - compatibility suppressions ([@matt-edmondson](https://github.com/matt-edmondson)) ## v1.3.4 (patch) Changes since v1.3.3: - compatibility suppressions ([@matt-edmondson](https://github.com/matt-edmondson)) ## v1.3.4-pre.7 (prerelease) Changes since v1.3.4-pre.6: - Merge remote-tracking branch 'refs/remotes/origin/main' ([@ktsu[bot]](https://github.com/ktsu[bot])) - Sync scripts\update-winget-manifests.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot])) ## v1.3.4-pre.6 (prerelease) Changes since v1.3.4-pre.5: - Sync scripts\PSBuild.psm1 ([@ktsu[bot]](https://github.com/ktsu[bot])) - Sync global.json ([@ktsu[bot]](https://github.com/ktsu[bot])) - Sync scripts\update-winget-manifests.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot])) ## v1.3.4-pre.5 (prerelease) Changes since v1.3.4-pre.4: - Sync scripts\PSBuild.psm1 ([@ktsu[bot]](https://github.com/ktsu[bot])) - Sync global.json ([@ktsu[bot]](https://github.com/ktsu[bot])) - Merge remote-tracking branch 'refs/remotes/origin/main' ([@ktsu[bot]](https://github.com/ktsu[bot])) - Sync scripts\PSBuild.psm1 ([@ktsu[bot]](https://github.com/ktsu[bot])) ## v1.3.4-pre.4 (prerelease) Changes since v1.3.4-pre.3: - Merge remote-tracking branch 'refs/remotes/origin/main' ([@ktsu[bot]](https://github.com/ktsu[bot])) - Sync global.json ([@ktsu[bot]](https://github.com/ktsu[bot])) ## v1.3.4-pre.3 (prerelease) Changes since v1.3.4-pre.2: - Merge remote-tracking branch 'refs/remotes/origin/main' ([@ktsu[bot]](https://github.com/ktsu[bot])) - Sync COPYRIGHT.md ([@ktsu[bot]](https://github.com/ktsu[bot])) - Sync global.json ([@ktsu[bot]](https://github.com/ktsu[bot])) ## v1.3.4-pre.2 (prerelease) Changes since v1.3.4-pre.1: - Sync scripts\PSBuild.psm1 ([@ktsu[bot]](https://github.com/ktsu[bot])) - Merge remote-tracking branch 'refs/remotes/origin/main' ([@ktsu[bot]](https://github.com/ktsu[bot])) ## v1.3.4-pre.1 (prerelease) Incremental prerelease update. ## v1.3.3 (patch) Changes since v1.3.2: - Remove .github\workflows\project.yml ([@matt-edmondson](https://github.com/matt-edmondson)) ## v1.3.2 (patch) Changes since v1.3.1: - Update project SDK from ktsu.Sdk.App to ktsu.Sdk.ImGuiApp in SchemaEditor.csproj ([@matt-edmondson](https://github.com/matt-edmondson)) - migrate to dotnet 10 ([@matt-edmondson](https://github.com/matt-edmondson)) - Replace StrongStrings and StrongPaths with ktsu.Semantics across the codebase, updating relevant class constraints and references to use ISemanticString. This change enhances type safety and aligns with the latest library standards. ([@matt-edmondson](https://github.com/matt-edmondson)) - Update tests to use new SchemaProvider API - remove dependency on obsolete Schema class ([@matt-edmondson](https://github.com/matt-edmondson)) - Update package references and add XML declaration in project files ([@matt-edmondson](https://github.com/matt-edmondson)) - Refactor schema management by introducing a new Schema class and related models, replacing the previous SchemaProvider and related interfaces. This update enhances type safety and aligns with the latest design principles, removing obsolete classes and improving the overall structure of the schema definitions. ([@matt-edmondson](https://github.com/matt-edmondson)) - Complete Schema refactoring to DI SchemaProvider - remove serialization and filesystem concerns ([@matt-edmondson](https://github.com/matt-edmondson)) - Remove Directory.Build.props and Directory.Build.targets files; add copyright notices to schema files; refactor variable declarations for consistency. ([@matt-edmondson](https://github.com/matt-edmondson)) - Update package references and restructure project files for improved organization and clarity ([@matt-edmondson](https://github.com/matt-edmondson)) - Update project SDK references and README formatting ([@matt-edmondson](https://github.com/matt-edmondson)) - Add schema contract interfaces for schema definitions, including ISchema, ISchemaChild, ISchemaClass, ISchemaEnum, and related name interfaces. This introduces a structured approach to schema management without serialization concerns. ([@matt-edmondson](https://github.com/matt-edmondson)) - Add CLAUDE.md for project guidance and documentation ([@matt-edmondson](https://github.com/matt-edmondson)) ## v1.3.2-pre.2 (prerelease) Changes since v1.3.2-pre.1: - Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot])) - Sync .editorconfig ([@ktsu[bot]](https://github.com/ktsu[bot])) - Sync .runsettings ([@ktsu[bot]](https://github.com/ktsu[bot])) ## v1.3.2-pre.1 (prerelease) Incremental prerelease update. ## v1.3.1 (patch) Changes since v1.3.0: - Update packages ([@matt-edmondson](https://github.com/matt-edmondson)) ## v1.3.0 (minor) Changes since v1.2.0: - Update packages ([@matt-edmondson](https://github.com/matt-edmondson)) - Add LICENSE template ([@matt-edmondson](https://github.com/matt-edmondson)) ## v1.2.1 (patch) Changes since v1.2.0: - Update packages ([@matt-edmondson](https://github.com/matt-edmondson)) ## v1.2.1-pre.2 (prerelease) Changes since v1.2.1-pre.1: - Sync scripts\make-changelog.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot])) - Sync scripts\make-version.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot])) ## v1.2.1-pre.1 (prerelease) Incremental prerelease update. ## v1.2.0 (minor) Changes since v1.1.0: - Use the .As() extension method on strong strings instead of casting ([@matt-edmondson](https://github.com/matt-edmondson)) ## v1.1.0 (minor) Changes since v1.0.0: - Add schema editor prototype ([@matt-edmondson](https://github.com/matt-edmondson)) - Dont serialize the readonly collection wrappers ([@matt-edmondson](https://github.com/matt-edmondson)) ## v1.0.0 (patch) Changes since v1.0.0-pre.15: - csharp_style_var_when_type_is_apparent = true:error ([@matt-edmondson](https://github.com/matt-edmondson)) ## v1.0.0-pre.15 (prerelease) Changes since v1.0.0-pre.14: - Bump the ktsu group with 2 updates ([@dependabot[bot]](https://github.com/dependabot[bot])) ## v1.0.0-pre.14 (prerelease) Changes since v1.0.0-pre.13: - Sync scripts\make-version.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot])) - Sync scripts\make-changelog.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot])) ## v1.0.0-pre.13 (prerelease) Changes since v1.0.0-pre.12: - Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot])) ## v1.0.0-pre.12 (prerelease) Changes since v1.0.0-pre.11: - Sync scripts\make-version.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot])) - Sync scripts\make-changelog.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot])) ## v1.0.0-pre.11 (prerelease) Changes since v1.0.0-pre.10: - Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot])) ## v1.0.0-pre.10 (prerelease) Changes since v1.0.0-pre.9: - Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot])) ## v1.0.0-pre.9 (prerelease) Changes since v1.0.0-pre.8: ## v1.0.0-pre.8 (prerelease) Changes since v1.0.0-pre.7: ## v1.0.0-pre.7 (prerelease) Changes since v1.0.0-pre.6: - Bump MSTest from 3.7.2 to 3.7.3 ([@dependabot[bot]](https://github.com/dependabot[bot])) ## v1.0.0-pre.6 (prerelease) Changes since v1.0.0-pre.5: ## v1.0.0-pre.5 (prerelease) Changes since v1.0.0-pre.4: ## v1.0.0-pre.4 (prerelease) Changes since v1.0.0-pre.3: - Bump MSTest from 3.7.1 to 3.7.2 ([@dependabot[bot]](https://github.com/dependabot[bot])) ## v1.0.0-pre.3 (prerelease) Changes since v1.0.0-pre.2: - Bump coverlet.collector from 6.0.3 to 6.0.4 ([@dependabot[bot]](https://github.com/dependabot[bot])) ## v1.0.0-pre.2 (prerelease) Changes since v1.0.0-pre.1: ## v1.0.0-pre.1 (prerelease) Incremental prerelease update. ## v0.0.1-pre.1 (prerelease) Changes since 0.0.1.0: - Whitespace ([@matt-edmondson](https://github.com/matt-edmondson)) - Initial commit ([@matt-edmondson](https://github.com/matt-edmondson)) - Refactor Schema class access modifiers and add extensions ([@matt-edmondson](https://github.com/matt-edmondson)) - Code style ([@matt-edmondson](https://github.com/matt-edmondson)) - Whitespace ([@matt-edmondson](https://github.com/matt-edmondson)) - Change .editorconfig end_of_line from lf to crlf ([@matt-edmondson](https://github.com/matt-edmondson)) - Whitespace ([@matt-edmondson](https://github.com/matt-edmondson)) - epic strict editorconfig ([@matt-edmondson](https://github.com/matt-edmondson))

Version Downloads Last updated
1.4.0 52 02/10/2026
1.3.4 52 02/06/2026
1.3.4-pre.7 52 02/06/2026
1.3.4-pre.6 51 02/05/2026
1.3.4-pre.5 49 02/03/2026
1.3.4-pre.4 52 02/01/2026
1.3.4-pre.3 52 01/31/2026
1.3.4-pre.2 52 01/31/2026
1.3.4-pre.1 51 01/31/2026
1.3.3 53 01/30/2026
1.3.2 55 01/28/2026