ktsu.Coder.Graph
2.0.0
Prefix Reserved
See the version list below for details.
dotnet add package ktsu.Coder.Graph --version 2.0.0
NuGet\Install-Package ktsu.Coder.Graph -Version 2.0.0
<PackageReference Include="ktsu.Coder.Graph" Version="2.0.0" />
<PackageVersion Include="ktsu.Coder.Graph" Version="2.0.0" />
<PackageReference Include="ktsu.Coder.Graph" />
paket add ktsu.Coder.Graph --version 2.0.0
#r "nuget: ktsu.Coder.Graph, 2.0.0"
#:package ktsu.Coder.Graph@2.0.0
#addin nuget:?package=ktsu.Coder.Graph&version=2.0.0
#tool nuget:?package=ktsu.Coder.Graph&version=2.0.0
ktsu.Coder
A flexible and extensible .NET library for representing code as Abstract Syntax Trees (AST), serializing to YAML, and generating code in multiple programming languages.
Overview
ktsu.Coder provides a language-agnostic way to represent code structures using Abstract Syntax Trees. The library allows you to:
- Build AST structures programmatically
- Serialize AST to human-readable YAML format
- Generate code in supported programming languages
- Perform round-trip serialization/deserialization
This makes it ideal for code generation tools, transpilers, and any application that needs to work with code structures in a language-independent way.
Features
- Language-Agnostic AST: Represent code structures without being tied to a specific programming language
- YAML Serialization: Human-readable serialization format that's perfect for version control and diffs
- Extensible Language Support: Plugin-based architecture for adding new target languages
- Deep Cloning: Full support for cloning AST structures
- Type Safety: Strongly-typed AST nodes with compile-time safety
- Metadata Support: Attach custom metadata to any AST node
Supported AST Node Types
- ClassDeclaration: A named class with an optional base type, holding methods, fields and nested classes
- FunctionDeclaration: Represents function/method declarations with parameters and body
- Parameter: Function parameters with optional default values
- ReturnStatement: Return statements with optional expressions
- VariableDeclaration: Variable declarations, optionally constant or type-inferred
- AssignmentStatement: Assignments, including the compound operators (
+=,<<=, …) - BinaryExpression: Two operands and an operator (
a + b,x == y,p && q) - UnaryExpression: One operator applied to one operand (
-x,!ready,~mask) - VariableReference: A reference to a variable by name
- LiteralExpression<T>: Typed literals (string, int, bool, double)
- AstLeafNode<T>: Generic leaf nodes for literals (strings, numbers, booleans)
Every operator in UnaryOperator and BinaryOperator exists in all four target languages, so no
AST built from them is untranslatable. Only the spelling varies — Python's not/and/or,
JavaScript's strict ===/!== — and each generator overrides just the operators it spells
differently.
Increment and decrement are deliberately absent from UnaryOperator: Python has no spelling for
them, and an AssignmentStatement with AssignmentOperator.AddAssign expresses the same effect in
every target language.
Visual graph editor
ktsu.Coder.Graph renders an AST as an editable node graph, built on
ktsu.ImGui.NodeEditor with its force-directed layout.
AstGraphEditor editor = new(functionDeclaration);
// once per frame, inside your ImGui render loop
editor.Draw(new Vector2(1200, 800), deltaTime);
foreach (AstGraphProblem problem in editor.Problems)
{
Console.WriteLine(problem.Message);
}
Each AST node becomes one editor node with a single output pin — itself — and one input pin per slot it can hold a child in, so a link reads "this node fills that slot of that parent". Right-click for the palette, drag between pins to connect, Delete to remove, and Undo/Redo on the toolbar. The palette lists every binary, unary and assignment operator, so which expression to create is a choice made when creating it.
Selecting a node opens it in the inspector — the panel under the canvas — which edits everything
about it that a link cannot express — a literal's value, a declaration's name and type, an expression's operator — and each edit
is one step on the undo stack. AstFields is the model behind it: a node's editable properties as
named fields of a kind, so a caller building its own UI does not need a panel per node type.
foreach (AstField field in AstFields.Of(node))
{
Console.WriteLine($"{field.Name} = {field.Value} ({field.Kind})");
}
AstFields.TryWrite(node, "Operator", nameof(BinaryOperator.Multiply));
A slot that holds a sequence — a function's parameters, its body, a class's members — has + and
- buttons in the inspector, so the number of them is changed without dragging nodes in from the
palette. "Convert to" replaces a node with a different kind in place, moving the operands the new
one can take across and keeping the rest rather than discarding them.
The origin of the graph's space is the middle of the canvas, and it follows the window as that is resized. Everything measured against it agrees as a result: gravity holds an untouched arrangement in the middle of the view, a document arrives centred on the frame it first appears, a node with no position of its own is seeded near the middle rather than in a corner, and "Fit" re-centres an arrangement that has been dragged away without disturbing its shape.
The AST is the document and the graph is a view of it: every edit is applied to the AST and the
graph rebuilt from it, preserving on-screen positions by node identity. A graph is allowed to be
incomplete while you work — AstGraphEditor.Problems (or AstGraph.Validate()) lists outstanding
operands and disconnected nodes rather than throwing, so consult it before handing the AST to a
generator.
The package targets net10.0 only, since the node editor does. ktsu.Coder itself has no UI
dependency and continues to cross-target.
Editor application
Coder.Editor is a desktop application built on ktsu.ImGui.App: the document as a node graph on
the left, the code it generates on the right, and a File menu for New function / New class / Open /
Save / Export with a recent files list. Ctrl+Z, Ctrl+Shift+Z, Ctrl+Y and Ctrl+S work wherever the
keyboard focus is.
dotnet run --project Coder.Editor
Documents are .coder.yaml files — the same YAML the serializer already round-trips, so anything the
library can write, the editor can open. The code pane follows the document live and lists what is
outstanding instead of generating while an operand is unfilled; clicking one of those selects the
node it is about. Generated source can be copied to the clipboard or exported beside the document in
the extension of whichever language is being previewed.
It uses the ktsu.Essentials providers where they fit rather than reaching for System.IO directly:
IFileSystemProvider for reading and writing documents, and an IPersistenceProvider over the XDG
config directory for the recent-files list and the preview language. Neither location is a decision
the editor makes for itself.
Supported Target Languages
Resolve IEnumerable<ILanguageGenerator> and select on LanguageId, or construct a generator
directly.
LanguageId |
Generator | Extension | Notes |
|---|---|---|---|
python |
PythonGenerator |
py |
Type hints, None for void, pass for an empty body or class; self on methods |
csharp |
CSharpGenerator |
cs |
Mapped type names, var for inferred declarations, declared access modifiers |
javascript |
JavaScriptGenerator |
js |
Untyped; const/let; strict === and !==; method and field syntax inside a class |
cpp |
CppGenerator |
cpp |
Mapped type spellings (str → std::string); auto for inferred declarations; public: and a terminating ; on a class |
Installation
Add the NuGet package:
dotnet add package ktsu.Coder
Releases through 1.8.2 were published as ktsu.Coder.Core; from 2.0.0 the package ID is
ktsu.Coder. The namespaces (ktsu.Coder.Ast, ktsu.Coder.Languages, ktsu.Coder.Serialization)
are unchanged, so migrating is a package reference edit and nothing more.
Quick Start
Creating an AST
using ktsu.Coder.Ast;
using ktsu.Coder.Languages;
using ktsu.Coder.Serialization;
// Create a function declaration
var function = new FunctionDeclaration("calculate_sum")
{
ReturnType = "int"
};
// Add parameters
function.Parameters.Add(new Parameter("a", "int"));
function.Parameters.Add(new Parameter("b", "int"));
function.Parameters.Add(new Parameter("debug", "bool")
{
IsOptional = true,
DefaultValue = "False"
});
// Add function body
function.Body.Add(new ReturnStatement(new AstLeafNode<string>("a + b")));
Serializing to YAML
var serializer = new YamlSerializer();
string yamlContent = serializer.Serialize(function);
Console.WriteLine(yamlContent);
Output:
functionDeclaration:
name: calculate_sum
returnType: int
parameters:
- name: a
type: int
- name: b
type: int
- name: debug
type: bool
isOptional: true
defaultValue: False
body:
- returnStatement:
expression:
Leaf<String>: a + b
Generating Code
var pythonGenerator = new PythonGenerator();
string pythonCode = pythonGenerator.Generate(function);
Console.WriteLine(pythonCode);
Output:
def calculate_sum(a: int, b: int, debug: bool = False) -> int:
return "a + b"
Round-trip Serialization
// Deserialize from YAML
var deserializer = new YamlDeserializer();
AstNode deserializedAst = deserializer.Deserialize(yamlContent);
// Generate code from deserialized AST
string regeneratedCode = pythonGenerator.Generate(deserializedAst);
Architecture
The library follows SOLID principles with a clean separation of concerns:
- AST Layer: Language-agnostic representation of code structures
- Serialization Layer: YAML serialization/deserialization
- Language Layer: Pluggable code generators for specific languages
Extending with New Languages
To add support for a new language, implement the ILanguageGenerator interface:
public class JavaScriptGenerator : LanguageGeneratorBase
{
public override string LanguageId => "javascript";
public override string DisplayName => "JavaScript";
public override string FileExtension => "js";
protected override void GenerateInternal(AstNode node, StringBuilder builder, int indentLevel)
{
// Implementation for JavaScript code generation
}
}
Examples
The repository includes a sample console application:
- Coder.Cli: Command-line tool demonstrating the AST, YAML round-tripping and code generation
Run it to see the library in action:
dotnet run --project Coder.Cli
For the interactive experience, run the desktop editor instead:
dotnet run --project Coder.Editor
Contributing
Contributions are welcome! Please feel free to submit pull requests or open issues for:
- New language generators
- Additional AST node types
- Bug fixes and improvements
- Documentation enhancements
License
MIT License. Copyright (c) ktsu.dev
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Hexa.NET.ImGui (>= 2.2.9)
- Hexa.NET.ImNodes (>= 2.2.9)
- ktsu.Coder (>= 2.0.0)
- ktsu.ForceDirectedLayout (>= 3.21.0)
- ktsu.ImGui.NodeEditor (>= 3.21.0)
- ktsu.UndoRedo.Core (>= 1.0.19)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.2.0 | 10 | 9/9/2026 |
| 3.1.3 | 26 | 9/9/2026 |
| 3.1.2 | 36 | 9/9/2026 |
| 3.1.1 | 33 | 9/9/2026 |
| 3.1.0 | 41 | 9/8/2026 |
| 3.0.0 | 52 | 9/8/2026 |
| 2.1.3 | 52 | 9/8/2026 |
| 2.1.2 | 47 | 9/8/2026 |
| 2.1.1 | 54 | 9/8/2026 |
| 2.1.0 | 48 | 9/8/2026 |
| 2.0.0 | 50 | 9/8/2026 |
| 1.8.3 | 53 | 9/8/2026 |
| 1.8.2 | 58 | 9/8/2026 |
| 1.8.1 | 50 | 9/8/2026 |
| 1.8.0 | 49 | 9/8/2026 |
| 1.7.0 | 49 | 9/8/2026 |
| 1.6.0 | 53 | 9/8/2026 |
| 1.5.0 | 68 | 9/7/2026 |
| 1.4.0 | 62 | 9/7/2026 |
| 1.3.0 | 66 | 9/7/2026 |
## v2.0.0 (major)
Changes since v1.0.0:
- fix: keep the Coder.Cli sample out of the SonarCloud analysis [patch] ([@Claude](https://github.com/Claude))
- chore: remove the Coder.App sample [patch] ([@Claude](https://github.com/Claude))
- refactor!: publish the library as ktsu.Coder [major] ([@Claude](https://github.com/Claude))
- Take the ImGui suite at 3.21.0 ([@Claude](https://github.com/Claude))
- refactor: take the zoom from the node editor rather than doing it here [patch] ([@Claude](https://github.com/Claude))
- Update ktsu.ImGui.App and related packages to version 3.20.0 ([@matt-edmondson](https://github.com/matt-edmondson))
- Merge main into the ktsu.ImGui.NodeEditor rename ([@Claude](https://github.com/Claude))
- Move to the renamed ktsu.ImGui.NodeEditor package ([@Claude](https://github.com/Claude))
- fix: reference the package WindowState actually lives in [patch] ([@Claude](https://github.com/Claude))
- feat: resizable panes, zoom, and a window that opens where it was left [minor] ([@Claude](https://github.com/Claude))
- feat: highlight the generated source in the preview pane [minor] ([@Claude](https://github.com/Claude))
- feat: separate overlapping nodes, inspect on the right, adopt the root [minor] ([@Claude](https://github.com/Claude))
- feat: make the origin the middle of the canvas [minor] ([@Claude](https://github.com/Claude))
- fix: assert the layout's bounds one edge at a time [patch] ([@Claude](https://github.com/Claude))
- fix: declare the physics package the graph now uses directly [patch] ([@Claude](https://github.com/Claude))
- fix: give the inspector room, and keep the layout inside the view [patch] ([@Claude](https://github.com/Claude))
- feat: convert nodes in place, export generated source, and document it [minor] ([@Claude](https://github.com/Claude))
- feat: animate the layout, edit node properties, and declare classes [minor] ([@Claude](https://github.com/Claude))
- refactor: use ktsu.UndoRedo for the graph editor's history [minor] ([@Claude](https://github.com/Claude))
- feat: add the Coder editor application [minor] ([@Claude](https://github.com/Claude))
- test: run the graph editor's ImGui surface headlessly [patch] ([@Claude](https://github.com/Claude))
- feat: add a visual AST graph editor library [minor] ([@Claude](https://github.com/Claude))
- refactor: emit generated code through ktsu.CodeBlocker [minor] ([@Claude](https://github.com/Claude))
- feat: add unary operator support to the AST and every generator [minor] ([@Claude](https://github.com/Claude))
- fix: make the new code's string comparisons explicit [patch] ([@Claude](https://github.com/Claude))
- fix: clear the Sonar findings on the new generator code [patch] ([@Claude](https://github.com/Claude))
- refactor: finish de-duplicating the generators [patch] ([@Claude](https://github.com/Claude))
- refactor: single-source the generator logic the four languages share [patch] ([@Claude](https://github.com/Claude))
- feat: implement the JavaScript and C++ language generators [minor] ([@Claude](https://github.com/Claude))
- ci: make the SonarQube quality gate opt in [patch] ([@matt-edmondson](https://github.com/matt-edmondson))
- ci: adopt the unified dotnet workflow [patch] ([@matt-edmondson](https://github.com/matt-edmondson))
- chore: store icon.png in LFS as .gitattributes declares ([@matt-edmondson](https://github.com/matt-edmondson))
- docs: scope build badge to the default branch ([@matt-edmondson](https://github.com/matt-edmondson))
- docs: correct README, DESCRIPTION and TAGS metadata ([@matt-edmondson](https://github.com/matt-edmondson))
- Stop Update SDKs failing when there is nothing to update ([@matt-edmondson](https://github.com/matt-edmondson))
- Fix ktsu.Sdk 2.27 analyzer errors: Polyfill PrivateAssets, InternalsVisibleTo [patch] ([@matt-edmondson](https://github.com/matt-edmondson))
- Sync .editorconfig ([@KtsuTools](https://github.com/KtsuTools))
- Sync global.json ([@KtsuTools](https://github.com/KtsuTools))
- chore: update ktsu.Sdk to 2.21.1 [patch] ([@matt-edmondson](https://github.com/matt-edmondson))
- fix: standardize null checks and exact exception assertions ([@matt-edmondson](https://github.com/matt-edmondson))
- chore: modernize project SDKs and target frameworks ([@matt-edmondson](https://github.com/matt-edmondson))
- Remove serena/cursor files ([@matt-edmondson](https://github.com/matt-edmondson))
- Regenerate TAGS.md with NuGet package tags ([@matt-edmondson](https://github.com/matt-edmondson))
- Remove legacy build scripts ([@matt-edmondson](https://github.com/matt-edmondson))
- Enhance test assertions with descriptive messages in ExpressionTests and ExpressionIntegrationTests ([@matt-edmondson](https://github.com/matt-edmondson))
- Refactor codebase to replace all instances of 'ktsu.Coder.Core' with 'ktsu.Coder' across files, enhancing consistency. Updated .runsettings for coverage configuration and modified .gitattributes for clarity. Removed obsolete test-expression-demo.cs file. Added new scripts for updating winget manifests and improved PSBuild.psm1 for better package publishing support. ([@matt-edmondson](https://github.com/matt-edmondson))
- Update configuration files and scripts for improved build and test processes ([@matt-edmondson](https://github.com/matt-edmondson))
- Enhance expression system integration and serialization support ([@matt-edmondson](https://github.com/matt-edmondson))
- Enhance YAML serialization and deserialization for new node types ([@matt-edmondson](https://github.com/matt-edmondson))
- Enhance YAML serialization and deserialization handling ([@matt-edmondson](https://github.com/matt-edmondson))
- Refactor project structure and enhance expression handling ([@matt-edmondson](https://github.com/matt-edmondson))
- Enhance expression handling in ExpressionDemo ([@matt-edmondson](https://github.com/matt-edmondson))
- Refactor expression handling and improve code consistency ([@matt-edmondson](https://github.com/matt-edmondson))
- Refactor AST expression handling and enhance visual editor support ([@matt-edmondson](https://github.com/matt-edmondson))
- Implement dependency injection and enhance AST expression handling ([@matt-edmondson](https://github.com/matt-edmondson))
- Update implementation and design documents to reflect current project status ([@matt-edmondson](https://github.com/matt-edmondson))