ktsu.CodeBlocker 2.0.1

Prefix Reserved
dotnet add package ktsu.CodeBlocker --version 2.0.1
                    
NuGet\Install-Package ktsu.CodeBlocker -Version 2.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ktsu.CodeBlocker" Version="2.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ktsu.CodeBlocker" Version="2.0.1" />
                    
Directory.Packages.props
<PackageReference Include="ktsu.CodeBlocker" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ktsu.CodeBlocker --version 2.0.1
                    
#r "nuget: ktsu.CodeBlocker, 2.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ktsu.CodeBlocker@2.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ktsu.CodeBlocker&version=2.0.1
                    
Install as a Cake Addin
#tool nuget:?package=ktsu.CodeBlocker&version=2.0.1
                    
Install as a Cake Tool

ktsu.CodeBlocker

An IndentedTextWriter that makes generating code blocks easier.

License NuGet Version NuGet Version NuGet Downloads GitHub commit activity GitHub contributors GitHub Actions Workflow Status

Introduction

CodeBlocker is a specialized utility built on top of IndentedTextWriter that simplifies the process of programmatically generating structured code. It provides automatic indentation management and a fluent interface for creating code blocks with proper nesting, making it ideal for code generation tasks, template engines, and dynamic source code creation.

Features

  • Automatic Indentation: Properly manages indentation levels as you create nested code blocks
  • Configurable Indentation: Support for custom indent strings (tabs, spaces, or any custom pattern)
  • Deterministic Line Endings: Lines end with LF by default, so the same calls produce byte-identical output on every platform; pin CRLF or the host terminator when you want them
  • Scope Management: Uses C# using statements for clean, readable scope creation with automatic brace handling powered by ktsu.ScopedAction, with optional trailing semicolons via ScopeWithTrailingSemicolon
  • More Than Braces: Parenthesis, bracket, bare-indent, #region, #if and #pragma warning scopes, each balanced by disposal
  • Preamble Helpers: One call each for the auto-generated marker, the nullable context, the namespace declaration, and the using directives
  • Template Object Model: Describe a whole source file as objects — types, members, operators, generics, XML docs — and let the model own the punctuation, spacing and indentation
  • Flexible API: Write individual lines or entire code blocks with proper formatting
  • Any TextWriter: Buffer into a StringWriter, or stream straight to a file or any other TextWriter
  • Cross-Platform: Supports .NET 10.0, 9.0, 8.0, 7.0, 6.0, 5.0, .NET Standard 2.0 and 2.1
  • Lightweight: Minimal dependencies, built on top of ktsu.ScopedAction for robust scope management
  • Well-Tested: Includes comprehensive unit and integration tests

Installation

Package Manager Console

Install-Package ktsu.CodeBlocker

.NET CLI

dotnet add package ktsu.CodeBlocker

Package Reference

<PackageReference Include="ktsu.CodeBlocker" Version="1.1.5" />

Usage Examples

Basic Example

namespace CodeBlockerExample;

using ktsu.CodeBlocker;

internal class Example
{
	public static void GenerateCode()
	{
		// Create a new CodeBlocker instance with default tab indentation
		using var codeBlocker = CodeBlocker.Create();

		// Write using statements and namespace
		codeBlocker.WriteLine("using System;");
		codeBlocker.NewLine(); // Add empty line without indentation
		codeBlocker.WriteLine("namespace Example");
		
		// Use Scope for automatic brace and indentation management
		using (new Scope(codeBlocker))
		{
			codeBlocker.WriteLine("public class Example");
			using (new Scope(codeBlocker))
			{
				codeBlocker.WriteLine("public static void Main()");
				using (new Scope(codeBlocker))
				{
					codeBlocker.WriteLine("Console.WriteLine(\"Hello, World!\");");
				} // Scope automatically writes closing brace and manages indentation
			}
		}

		// Output the generated code
		Console.WriteLine(codeBlocker.ToString());
	}
}

The above example generates the following code:

using System;

namespace Example
{
	public class Example
	{
		public static void Main()
		{
			Console.WriteLine("Hello, World!");
		}
	}
}

Note: The Scope class writes closing braces without semicolons (}). If you need trailing semicolons after closing braces (};), such as for enum declarations or struct initializers in C/C++, use ScopeWithTrailingSemicolon instead.

Custom Indentation

CodeBlocker supports configurable indentation strings, allowing you to use spaces, tabs, or any custom pattern:

// Using 2 spaces for indentation
using var codeBlocker2Space = CodeBlocker.Create("  ");

// Using 4 spaces for indentation
using var codeBlocker4Space = CodeBlocker.Create("    ");

// Using custom patterns (e.g., for markup generation)
using var customCodeBlocker = CodeBlocker.Create("-->");

// With existing StringWriter and custom indentation
using var stringWriter = new StringWriter();
using var codeBlocker = new CodeBlocker(stringWriter, "  ");

codeBlocker.WriteLine("function example() {");
codeBlocker.Indent();
codeBlocker.WriteLine("console.log('Hello with 2 spaces!');");
codeBlocker.Outdent();
codeBlocker.WriteLine("}");

Console.WriteLine(codeBlocker.ToString());
// Output:
// function example() {
//   console.log('Hello with 2 spaces!');
// }

// Check current indent configuration
Console.WriteLine($"Current indent: '{codeBlocker.IndentString}'"); // "  "

// Custom indentation works seamlessly with Scope
using var scopeCodeBlocker = CodeBlocker.Create("    "); // 4 spaces
scopeCodeBlocker.WriteLine("public class Example");
using (new Scope(scopeCodeBlocker))
{
    scopeCodeBlocker.WriteLine("public void Method()");
    using (new Scope(scopeCodeBlocker))
    {
        scopeCodeBlocker.WriteLine("// 4-space indented code");
    }
}

Describing Code as Templates

Writing a generator against WriteLine means owning every brace, comma and blank line yourself, and re-deriving the same layout decisions in every generator you write. The ktsu.CodeBlocker.Templates namespace lets you describe the file instead:

namespace CodeBlockerExample;

using ktsu.CodeBlocker;
using ktsu.CodeBlocker.Templates;

internal class TemplateExample
{
	public static string GenerateCode()
	{
		SourceFileTemplate file = new()
		{
			FileName = "Money.g.cs",
			Namespace = "Contoso.Billing",
			Usings = { "System" },
		};

		ClassTemplate money = new()
		{
			Kind = TypeKind.RecordStruct,
			Name = "Money",
			Keywords = { "public", "readonly" },
			PositionalParameters = { new ParameterTemplate { Type = "decimal", Name = "Amount" } },
			Documentation = new DocComment { Summary = "An amount of money." },
		};

		money.Members.Add(new OperatorTemplate
		{
			Type = "Money",
			Keywords = { "public", "static" },
			Symbol = "+",
			Parameters =
			{
				new ParameterTemplate { Type = "Money", Name = "left" },
				new ParameterTemplate { Type = "Money", Name = "right" },
			},
			BodyFactory = codeBlocker => codeBlocker.Write("=> new(left.Amount + right.Amount);"),
		});

		file.Classes.Add(money);

		using CodeBlocker codeBlocker = CodeBlocker.Create();
		codeBlocker.AddSourceFile(file);
		return codeBlocker.ToString();
	}
}

Produces:

namespace Contoso.Billing;

using System;

/// <summary>An amount of money.</summary>
public readonly record struct Money(decimal Amount)
{
	public static Money operator +(Money left, Money right) => new(left.Amount + right.Amount);
}

Note what you did not have to decide: that the attribute goes on its own line, that the operator is indented one level, that members are separated by a blank line, that a positional record with a body still needs braces while one without gets a semicolon.

Collection properties are read-only, so use collection-initializer syntax — Keywords = { "public" } — rather than assignment.

Bodies

A member body is written by a callback into a nested CodeBlocker and then spliced in, re-indented line by line to wherever it lands. Nest it as deeply as you like:

new MethodTemplate
{
	Type = "int",
	Name = "Add",
	Keywords = { "public" },
	Parameters =
	{
		new ParameterTemplate { Type = "int", Name = "a" },
		new ParameterTemplate { Type = "int", Name = "b" },
	},
	BodyFactory = codeBlocker =>
	{
		using Scope scope = new(codeBlocker);
		codeBlocker.WriteLine("return a + b;");
	},
}

A callback that writes a single line becomes an expression body on the declaration line; one that writes several becomes a braced body on the following lines; one that writes nothing becomes { }; and a null BodyFactory declares the member with no body at all, for an abstract, partial or interface declaration.

XML documentation

DocComment models documentation as data rather than as pre-formatted comment lines, so the content is escaped, the tags come out in canonical order, and a multi-line description is prefixed correctly:

Documentation = new DocComment
{
	Summary = "Clamps a ratio to the range <0, 1>.",
	Params = { new DocTag { Name = "value", Text = "The ratio." } },
	Returns = "The clamped ratio.",
}
/// <summary>Clamps a ratio to the range &lt;0, 1&gt;.</summary>
/// <param name="value">The ratio.</param>
/// <returns>The clamped ratio.</returns>

Set EscapeText = false when the text deliberately embeds markup such as <see cref="…"/>. Validate(parameterNames, typeParameterNames) returns one message per mismatched or missing <param>/<typeparam> entry, so a generator can report them as build diagnostics instead of letting CS1572 and CS1573 surface inside the generated file.

More Than Braces

Scope and ScopeWithTrailingSemicolon cover braces. The same pattern covers the other shapes that recur in generated code, and every one of them is balanced by disposal — so an unbalanced #pragma warning disable or a stray #endregion is not something you can leave behind.

Scope Opens with Closes with Indents the body
Scope { } Yes
ScopeWithTrailingSemicolon { }; Yes
ParenScope ( ) Yes
BracketScope [ ] Yes
IndentScope Yes
RegionScope #region name #endregion No
DirectiveScope #if condition #endif No
PragmaScope #pragma warning disable … #pragma warning restore … No

The three directive scopes do not indent, because a directive does not nest code. DelimiterScope is the shared base if you need a pair of delimiters the library does not name.

namespace CodeBlockerExample;

using ktsu.CodeBlocker;

internal class ScopesExample
{
	public static string GenerateCode()
	{
		using CodeBlocker codeBlocker = CodeBlocker.Create();

		codeBlocker.WriteLine("public class Example");
		using (new Scope(codeBlocker))
		{
			using (new RegionScope(codeBlocker, "Constructors"))
			{
				codeBlocker.WriteLine("public Example");
				using (new ParenScope(codeBlocker))
				{
					codeBlocker.WriteLine("int first,");
					codeBlocker.WriteLine("int second");
				}

				codeBlocker.WriteLine("{ }");
			}

			using (new PragmaScope(codeBlocker, "CS1591"))
			{
				codeBlocker.WriteLine("public int Undocumented;");
			}
		}

		return codeBlocker.ToString();
	}
}

Produces:

public class Example
{
	#region Constructors
	public Example
	(
		int first,
		int second
	)
	{ }
	#endregion
	#pragma warning disable CS1591
	public int Undocumented;
	#pragma warning restore CS1591
}

File Preambles

The lines at the top of a generated file are the same every time, so they get one call each. Every helper that conventionally has a blank line after it writes that blank line, which keeps the spacing consistent no matter which parts a given generator emits.

using CodeBlocker codeBlocker = CodeBlocker.Create();

codeBlocker
	.WriteAutoGeneratedHeader("Copyright (c) 2023-2026 ktsu-dev contributors")
	.WriteNullableEnable()
	.WriteFileScopedNamespace("Contoso.Widgets")
	.WriteUsings("System", "System.Collections.Generic");

Produces:

// Copyright (c) 2023-2026 ktsu-dev contributors
// <auto-generated />

#nullable enable
namespace Contoso.Widgets;

using System;
using System.Collections.Generic;

WriteFileScopedNamespace writes nothing for a null or empty namespace, and WriteUsings writes nothing — not even the blank line — for an empty sequence, so a generator can call them unconditionally.

Writing Somewhere Other Than a String

CodeBlocker.Create() buffers into a StringWriter it owns, which is what makes ToString() able to hand the code back. You can instead give it any TextWriter — a file, a TextWriter handed to you by a build task, a test double:

namespace CodeBlockerExample;

using ktsu.CodeBlocker;

internal class FileExample
{
	public static void GenerateToFile(string path)
	{
		using StreamWriter file = new(path);
		using CodeBlocker codeBlocker = new(file);

		codeBlocker.WriteLine("public class Example");
		using (new Scope(codeBlocker))
		{
			codeBlocker.WriteLine("public int Value { get; set; }");
		}
	}
}

Two things to know:

  • A writer you supply stays yours. CodeBlocker.Dispose() disposes only the StringWriter that Create() made for itself; it never disposes a writer you passed in.
  • ToString() only works when buffered. A CodeBlocker over a StreamWriter keeps no copy of what it wrote, so ToString() returns the type name rather than the code — check IsBuffered if you need to know which case you are in. Read the generated code from your own writer instead.

Line Endings

CodeBlocker terminates lines with a line feed unless you say otherwise. Generated code is nearly always committed to a repository or compared against a golden file, and both of those want the same bytes out of every machine — so the default is the deterministic terminator rather than the local convention:

namespace CodeBlockerExample;

using ktsu.CodeBlocker;

internal class DeterministicExample
{
	public static string GenerateCode()
	{
		// Byte-identical on every platform: LF, on Windows too.
		using CodeBlocker codeBlocker = CodeBlocker.Create();

		codeBlocker.WriteLine("public class Example");
		using (new Scope(codeBlocker))
		{
			codeBlocker.WriteLine("public int Value { get; set; }");
		}

		return codeBlocker.ToString();
	}
}

This is the one place CodeBlocker departs from the IndentedTextWriter it writes through, which uses Environment.NewLine.

The NewLines class names the usual choices, and any other string works too — the terminator is written verbatim:

Name Value Notes
NewLines.Lf "\n" The default, exposed as CodeBlocker.DefaultNewLineString
NewLines.CrLf "\r\n" Use when the target repository stores .cs files with CRLF
NewLines.Host Environment.NewLine Opt in when the output is for this machine rather than for a repository

To follow the host convention, ask for it:

using CodeBlocker codeBlocker = CodeBlocker.Create(CodeBlocker.DefaultIndentString, NewLines.Host);

Advanced Usage

// Creating a CodeBlocker with a custom StringWriter
using var stringWriter = new StringWriter();
using var codeBlocker = new CodeBlocker(stringWriter);

// Generate a more complex structure
codeBlocker.WriteLine("public interface IExample");
using (new Scope(codeBlocker))
{
    // Define interface methods
    codeBlocker.WriteLine("void Method1();");
    codeBlocker.WriteLine("string Method2(int parameter);");
    
    // Define nested interface
    codeBlocker.NewLine();
    codeBlocker.WriteLine("public interface INestedExample");
    using (new Scope(codeBlocker))
    {
        codeBlocker.WriteLine("void NestedMethod();");
    }
}

// Add implementation
codeBlocker.NewLine();
codeBlocker.WriteLine("public class Implementation : IExample");
using (new Scope(codeBlocker))
{
    // Implement methods
    codeBlocker.WriteLine("public void Method1()");
    using (new Scope(codeBlocker))
    {
        codeBlocker.WriteLine("// Implementation here");
    }
    
    codeBlocker.NewLine();
    codeBlocker.WriteLine("public string Method2(int parameter)");
    using (new Scope(codeBlocker))
    {
        codeBlocker.WriteLine("return parameter.ToString();");
    }
}

// Get the result
string result = codeBlocker.ToString();

API Reference

CodeBlocker Class

The main class for building indented code blocks.

Constants
Name Value Description
DefaultIndentString "\t" The indent written per level when none is specified
DefaultNewLineString NewLines.Lf The line terminator used when none is specified
Constructors
Name Description
CodeBlocker(StringWriter stringWriter) Creates a new CodeBlocker with the specified StringWriter using tab indentation and LF line endings
CodeBlocker(StringWriter stringWriter, string indentString) Creates a new CodeBlocker with the specified StringWriter and custom indent string, still LF
CodeBlocker(StringWriter stringWriter, string indentString, string newLineString) As above, and pins the line terminator written at the end of every line
CodeBlocker(TextWriter writer) Creates a new CodeBlocker over any TextWriter using tab indentation and LF line endings
CodeBlocker(TextWriter writer, string indentString) Creates a new CodeBlocker over any TextWriter with a custom indent string, still LF
CodeBlocker(TextWriter writer, string indentString, string newLineString) As above, and pins the line terminator
Properties
Name Type Description
CurrentIndent int Gets or sets the current indentation level
IndentString string Gets the current indent string being used (e.g., "\t", " ", " ")
NewLineString string Gets the line terminator written at the end of every line; DefaultNewLineString (LF) unless one was passed
IsBuffered bool Whether ToString() can return the generated code, i.e. whether the underlying writer is a StringWriter
Methods
Name Return Type Description
WriteLine(string line) void Writes a line of text with appropriate indentation
WriteLine() void Writes an empty line with current indentation
Write(string text) void Writes text without adding a new line
NewLine() void Writes an empty line without indentation
Indent() void Increases the indent level
Outdent() void Decreases the indent level
ToString() string Returns the generated code as a string
Create() CodeBlocker Static factory method to create a new CodeBlocker instance with tab indentation and LF line endings
Create(string indentString) CodeBlocker Static factory method to create a new CodeBlocker instance with custom indentation, still LF
Create(string indentString, string newLineString) CodeBlocker Static factory method to create a new CodeBlocker instance with custom indentation and a pinned line terminator
Dispose() void Disposes of the CodeBlocker and underlying resources

Scope Class

Helper class for managing indentation scopes with automatic brace handling. Built on top of ktsu.ScopedAction for guaranteed resource cleanup and exception safety.

Constructor
Name Description
Scope(CodeBlocker codeBlocker) Creates a new scope that automatically writes opening brace {, increases indentation, and handles cleanup on disposal
Methods
Name Return Type Description
Dispose() void Decreases indentation level and writes closing brace } when scope is exited
Behavior
  • On Creation: Writes { and increases indentation level
  • On Disposal: Decreases indentation level and writes }
  • Exception Safety: Guaranteed cleanup even if exceptions occur within the scope
  • Resource Management: Built on ktsu.ScopedAction for reliable resource handling

Template Object Model

ktsu.CodeBlocker.Templates. See Describing Code as Templates.

Type Describes
SourceFileTemplate A whole file: namespace, usings, types
ClassTemplate A type of any TypeKind, its generics, base list, constraints, members and nested types
FieldTemplate A field, with an optional initializer
PropertyTemplate A property: automatic, expression-bodied, or a full accessor list
AccessorTemplate One accessor, as AccessorKind.Auto, .Expression or .Block, with an optional modifier
MethodTemplate A method, its generics, parameters, constraints and body
ConstructorTemplate A constructor, its parameters, its base/this initializer and body
OperatorTemplate An operator or an implicit/explicit conversion
EnumMemberTemplate One enum member
ParameterTemplate One parameter, with an optional default
DocComment, DocTag XML documentation as data
TemplateBase What every template carries: name, type, modifiers, attributes, comments, documentation
Enum Values
TypeKind Class, Struct, Interface, Record, RecordStruct, Enum
AccessorKind Auto, Expression, Block
OperatorKind Normal, Implicit, Explicit

Rendering entry points: codeBlocker.AddSourceFile(file), codeBlocker.AddClass(type), or template.WriteTo(codeBlocker) for any single template.

CodeBlockerExtensions Class

File-level preamble helpers. Each returns the same CodeBlocker so calls chain.

Name Description
WriteAutoGeneratedHeader(string? copyright = null) Writes an optional copyright line, then // <auto-generated />, then a blank line
WriteNullableEnable() Writes #nullable enable
WriteNullableDisable() Writes #nullable disable
WriteFileScopedNamespace(string? namespaceName) Writes namespace X; and a blank line, or nothing when the namespace is null or empty
WriteUsings(IEnumerable<string> usings) Writes one using X; per entry and a blank line, or nothing when empty
WriteUsings(params string[] usings) As above

NewLines Class

Named line terminators. See Line Endings.

Name Value
Lf "\n" (the default — see CodeBlocker.DefaultNewLineString)
CrLf "\r\n"
Host Environment.NewLine

DelimiterScope Class

Base class for a scope that writes an opening delimiter, indents the body, and writes a closing delimiter on disposal. ParenScope and BracketScope derive from it; derive your own for a delimiter pair the library does not name.

Constructor
Name Description
DelimiterScope(CodeBlocker codeBlocker, string open, string close) Creates a scope writing open before the body and close after it

ParenScope, BracketScope, IndentScope Classes

Name Description
ParenScope(CodeBlocker codeBlocker) Wraps the body in ( and ), indenting it
BracketScope(CodeBlocker codeBlocker) Wraps the body in [ and ], indenting it
IndentScope(CodeBlocker codeBlocker) Indents the body without writing any delimiters

RegionScope, DirectiveScope, PragmaScope Classes

Preprocessor directive pairs. None of them indents the body.

Name Description
RegionScope(CodeBlocker codeBlocker, string name) Wraps the body in #region name and #endregion; the name may be empty
DirectiveScope(CodeBlocker codeBlocker, string condition) Wraps the body in #if condition and #endif
PragmaScope(CodeBlocker codeBlocker, string warnings) Wraps the body in #pragma warning disable/restore for the same warnings
PragmaScope(CodeBlocker codeBlocker, IEnumerable<string> warnings) As above, joining the identifiers with ,

ScopeWithTrailingSemicolon Class

Variant of Scope that appends a semicolon after the closing brace. Useful for code generation scenarios like C/C++ enum or struct declarations where a trailing semicolon is required.

Constructor
Name Description
ScopeWithTrailingSemicolon(CodeBlocker codeBlocker) Creates a new scope that automatically writes opening brace {, increases indentation, and handles cleanup on disposal
Methods
Name Return Type Description
Dispose() void Decreases indentation level and writes closing brace with semicolon }; when scope is exited
Behavior
  • On Creation: Writes { and increases indentation level
  • On Disposal: Decreases indentation level and writes };
  • Exception Safety: Guaranteed cleanup even if exceptions occur within the scope
  • Resource Management: Built on ktsu.ScopedAction for reliable resource handling

Contributing

Contributions are welcome! Here's how you can help:

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE.md file for details.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on ktsu.CodeBlocker:

Package Downloads
ktsu.Schema

A .NET library for defining, managing, and editing data structure schemas with a rich type system, type-safe identifiers, and polymorphic JSON serialization. Define structured data models programmatically or visually and serialize them to .schema.json files, providing a metadata foundation for code generation, data validation, and tooling that needs to reason about your data structures. Ships with an accompanying Dear ImGui desktop editor for visual schema authoring.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.1 58 8/28/2026
2.0.0 76 8/27/2026
1.3.0 130 8/27/2026
1.2.16 73 8/27/2026
1.2.15 114 8/25/2026
1.2.14 102 8/24/2026
1.2.13 107 8/21/2026
1.2.12 111 8/20/2026
1.2.11 109 8/19/2026
1.2.10 91 8/18/2026
1.2.9 108 8/17/2026
1.2.8 309 7/3/2026
1.2.7 122 7/2/2026
1.2.6 129 7/1/2026
1.2.5 128 6/30/2026
1.2.4 131 6/29/2026
1.2.3 124 6/28/2026
1.2.2 111 6/28/2026
1.2.1 130 6/12/2026
1.2.1-pre.1 94 2/17/2026
Loading failed

## v2.0.1 (patch)

Changes since v2.0.0:

- Bump the ktsu group with 1 update ([@dependabot[bot]](https://github.com/dependabot[bot]))