Praefixum 2.0.1

dotnet add package Praefixum --version 2.0.1
                    
NuGet\Install-Package Praefixum -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="Praefixum" Version="2.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Praefixum" Version="2.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Praefixum" />
                    
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 Praefixum --version 2.0.1
                    
#r "nuget: Praefixum, 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 Praefixum@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=Praefixum&version=2.0.1
                    
Install as a Cake Addin
#tool nuget:?package=Praefixum&version=2.0.1
                    
Install as a Cake Tool

Praefixum - Unique ID Generator for .NET

Build Status NuGet License

Praefixum is a .NET 10 source generator that emits interceptors for automatic unique ID generation. It enables deterministic, human-friendly identifiers to be generated for method parameters marked with the [UniqueId] attribute.

๐Ÿš€ Features

  • Build-time interceptors - Generated code handles IDs without manual wiring
  • Deterministic by call site - Same code location generates stable IDs
  • Multiple parameter support - Handle multiple [UniqueId] parameters in a single method
  • Multiple formats - Support for HTML IDs, GUIDs, timestamps, and hash-based IDs
  • Prefix support - Add custom prefixes to generated IDs
  • Interceptor-based - Uses .NET 10 preview interceptors for seamless integration
  • Thread-safe - Generated IDs are constants, no concurrency issues
  • Zero dependencies - Pure source generator implementation

๐Ÿ“ฆ Installation

Install via NuGet Package Manager:

dotnet add package Praefixum

Or via Package Manager Console:

Install-Package Praefixum

๐ŸŽฏ Quick Start

1. Define a method with UniqueId parameter

using Praefixum;

public static string CreateButton(
    string text,
    [UniqueId(UniqueIdFormat.HtmlId)] string? id = null)
{
    return $"<button id=\"{id}\">{text}</button>";
}

2. Use the method

// Each call generates a unique ID via the generated interceptor
var button1 = CreateButton("Click me");     // <button id="a1b2c3d4">Click me</button>
var button2 = CreateButton("Submit");       // <button id="x9y8z1w2">Submit</button>

3. Compilation magic โœจ

The source generator emits interceptors that replace null [UniqueId] parameters with generated IDs based on the call location.

๐ŸŽจ Supported ID Formats

Format Example Description
HtmlId a1b2c3d4 HTML5-compliant ID (starts with letter, 8 characters)
Guid a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 32-character deterministic GUID (no dashes)
Timestamp 1735052327842 Unix timestamp in milliseconds
ShortHash YWJjZGVm 8-character Base64-encoded hash

๐Ÿ“– Usage Examples

HTML ID Generation

public static string Div(
    string content,
    [UniqueId(UniqueIdFormat.HtmlId, prefix: "div-")] string? id = null)
{
    return $"<div id=\"{id}\">{content}</div>";
}

// Usage
var html = Div("Hello World"); // <div id="div-a1b2c3d4">Hello World</div>

Multiple Parameters

NEW: Praefixum now supports multiple [UniqueId] parameters in a single method!

public static string Form(
    [UniqueId(UniqueIdFormat.HtmlId, prefix: "form-")] string? formId = null,
    [UniqueId(UniqueIdFormat.HtmlId)] string? nameInputId = null,
    [UniqueId(UniqueIdFormat.HtmlId)] string? emailInputId = null,
    [UniqueId(UniqueIdFormat.Guid)] string? submitId = null)
{
    return $@"
        <form id=""{formId}"">
            <input id=""{nameInputId}"" name=""name"" type=""text"" />
            <input id=""{emailInputId}"" name=""email"" type=""email"" />
            <button id=""{submitId}"" type=""submit"">Submit</button>
        </form>";
}

// Usage - all IDs are automatically generated and unique
var form = Form(); 
// Generates: form-x1y2z3w4, a5b6c7d8, e9f0g1h2, i3j4k5l6m7n8o9p0q1r2s3t4u5v6w7x8

Custom Prefixes

public static string Input(
    [UniqueId(UniqueIdFormat.HtmlId, prefix: "input-")] string? id = null)
{
    return $"<input id=\"{id}\" type=\"text\" />";
}

Different Formats in Same Method

public static string Widget(
    [UniqueId(UniqueIdFormat.HtmlId)] string? elementId = null,
    [UniqueId(UniqueIdFormat.Timestamp)] string? timestampId = null,
    [UniqueId(UniqueIdFormat.Guid)] string? uuid = null)
{
    return $@"
        <div id=""{elementId}"" data-timestamp=""{timestampId}"" data-uuid=""{uuid}"">
            Widget Content
        </div>";
}

๐Ÿ—๏ธ How It Works

  1. Attribute Detection: The source generator scans for methods with [UniqueId] parameters
  2. Call Site Analysis: Identifies calls to methods with [UniqueId] parameters
  3. Interceptor Generation: Creates interceptor methods for each call site using .NET 10 preview interceptors
  4. ID Generation: Generates IDs from call-site location data at build time
  5. Invocation: The interceptor fills null parameters with literal IDs and calls the original method

Generated Code Example

For this source code:

var form = CreateFormWithMultipleIds(); // Line 42, Column 12

The generator creates an interceptor that:

  1. Checks if all [UniqueId] parameters are provided
  2. If any are null, generates unique IDs based on call site + parameter index
  3. Calls the original method with generated or provided IDs
[InterceptsLocation(1, "D:\\MyProject\\Program.cs(42,12)")]
public static string CreateFormWithMultipleIds_0(
    string? formId = null,
    string? nameInputId = null, 
    string? emailInputId = null,
    string? submitButtonId = null)
{
    // Check if all parameters provided
    if (formId != null && nameInputId != null && emailInputId != null && submitButtonId != null)
        return OriginalClass.CreateFormWithMultipleIds(formId, nameInputId, emailInputId, submitButtonId);
    
    // Generate IDs for null parameters
    var formIdFinal = formId ?? GenerateId("key:0", 1, UniqueIdFormat.HtmlId, "form-");
    var nameInputIdFinal = nameInputId ?? GenerateId("key:1", 1, UniqueIdFormat.HtmlId, null);
    var emailInputIdFinal = emailInputId ?? GenerateId("key:2", 1, UniqueIdFormat.HtmlId, null);  
    var submitButtonIdFinal = submitButtonId ?? GenerateId("key:3", 1, UniqueIdFormat.Guid, null);
    
    return OriginalClass.CreateFormWithMultipleIds(formIdFinal, nameInputIdFinal, emailInputIdFinal, submitButtonIdFinal);
}

๐Ÿงช Testing

The project includes a comprehensive test suite covering:

  • Basic functionality - Core ID generation and validation
  • Multiple parameter support - Methods with multiple [UniqueId] parameters
  • Format compliance - Each format meets its specification
  • Edge cases - Error conditions and unusual scenarios
  • Performance - Concurrency and load testing
  • Integration - Real-world usage patterns with actual [UniqueId] attributes

Run tests with:

dotnet test

๐Ÿ”ง Requirements

  • .NET 10.0 or later (for interceptor support)
  • C# preview (interceptors are preview)
  • EnablePreviewFeatures and InterceptorsNamespaces enabled in your project
<PropertyGroup>
  <TargetFramework>net10.0</TargetFramework>
  <LangVersion>preview</LangVersion>
  <EnablePreviewFeatures>true</EnablePreviewFeatures>
  <InterceptorsNamespaces>$(InterceptorsNamespaces);Praefixum</InterceptorsNamespaces>
</PropertyGroup>

๐Ÿค Contributing

We welcome contributions! Please see CONTRIBUTING.md for guidelines.

Development Setup

  1. Clone the repository
  2. Run dotnet restore
  3. Run dotnet build to build all projects
  4. Run dotnet test to execute the test suite

๐Ÿ“‹ Project Structure

Praefixum/
โ”œโ”€โ”€ Praefixum/                    # Main source generator project
โ”‚   โ”œโ”€โ”€ UniqueIdGenerator.cs      # Core source generator logic
โ”‚   โ””โ”€โ”€ UniqueIdAttribute.cs      # Attribute definitions
โ”œโ”€โ”€ Praefixum.Demo/              # Demo application
โ”‚   โ”œโ”€โ”€ Program.cs               # Console demo
โ”‚   โ””โ”€โ”€ Html.cs                  # HTML generation examples
โ”œโ”€โ”€ Praefixum.Tests/             # Comprehensive test suite
โ”‚   โ”œโ”€โ”€ UniqueIdGeneratorBasicTests.cs
โ”‚   โ”œโ”€โ”€ UniqueIdGeneratorEdgeCaseTests.cs
โ”‚   โ”œโ”€โ”€ UniqueIdFormatTests.cs
โ”‚   โ”œโ”€โ”€ UniqueIdGeneratorPerformanceTests.cs
โ”‚   โ””โ”€โ”€ TestHelpers.cs
โ””โ”€โ”€ docs/                        # Documentation

๐Ÿ“ˆ Performance

  • No runtime ID generation - IDs are compile-time literals in generated code
  • Fast compilation - Minimal impact on build time
  • Memory efficient - No runtime allocations for ID generation
  • Thread-safe - Generated constants are inherently thread-safe

๐Ÿ› Troubleshooting

Common Issues

Q: IDs are not being generated A: Ensure you're using .NET 10 and have enabled preview features and interceptors in your project.

Q: Duplicate ID errors A: This indicates the same call site is generating multiple IDs. Check your code structure.

Q: Build errors with interceptors A: Verify your project targets .NET 10, LangVersion is preview, and preview features are enabled.

๐Ÿ“„ License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

๐Ÿ™ Acknowledgments

  • Built with Roslyn source generators
  • Uses .NET 10 preview interceptor feature
  • Inspired by compile-time code generation patterns

Made with โค๏ธ for the .NET community

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 was computed.  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 was computed.  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 was computed.  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 was computed. 
.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.
  • .NETStandard 2.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Praefixum:

Package Downloads
Picea.Abies

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.1 6,434 2/25/2026
2.0.0 112 2/18/2026
1.2.1-tags-v1-2-0.1 1,993 1/22/2026
1.1.9-tags-v1-1-8.1 148 1/21/2026
1.1.8-tags-v1-1-7.1 76 1/21/2026
1.1.6-tags-v1-1-5.1 189 6/23/2025
1.1.5-tags-v1-1-4.1 349 6/6/2025
1.1.4-tags-v1-1-3.2 169 6/5/2025
1.1.3-tags-v1-1-2.1 174 6/4/2025
1.1.2-tags-v1-1-1.1 173 6/4/2025
1.1.1-tags-v1-1-0.1 178 6/4/2025
1.0.19-tags-v1-0-18.1 174 5/27/2025
1.0.12-tags-v1-0-11.1 188 5/26/2025
1.0.11-tags-v1-0-10.1 133 5/23/2025

v2.0.1 โ€” Bugfix: emit correct C# literals for bool, char, float, double, decimal, long, ulong, and enum default parameter values in generated interceptors (#6).