TypedPaths.Generator
1.2.8
See the version list below for details.
dotnet add package TypedPaths.Generator --version 1.2.8
NuGet\Install-Package TypedPaths.Generator -Version 1.2.8
<PackageReference Include="TypedPaths.Generator" Version="1.2.8" />
<PackageVersion Include="TypedPaths.Generator" Version="1.2.8" />
<PackageReference Include="TypedPaths.Generator" />
paket add TypedPaths.Generator --version 1.2.8
#r "nuget: TypedPaths.Generator, 1.2.8"
#:package TypedPaths.Generator@1.2.8
#addin nuget:?package=TypedPaths.Generator&version=1.2.8
#tool nuget:?package=TypedPaths.Generator&version=1.2.8
TypedPaths.Generator
A Roslyn source generator that turns configured folder trees into strongly typed path constants at compile time. Each configured folder becomes a nested static class (for example Src, Template) so you can avoid magic strings.
What you get
Given a structure like:
/src
Template1.anyext
folderA/
Template2.anyext
folderB/
Template3.anyext
Template4.anyext
/template
email/
welcome.txt
sms/
otp.txt
the generator emits one file per root folder (TypedPaths.Src.g.cs, TypedPaths.Template.g.cs, ...), each contributing to the same partial root class:
// TypedPaths.Src.g.cs
// <auto-generated/>
namespace TypedPaths;
public static partial class TypedPaths
{
public static partial class Src
{
public const string Value = "src";
public static partial class Template1
{
public const string Value = "src/Template1.anyext";
}
public static partial class FolderA
{
public const string Value = "src/folderA";
public static partial class Template2
{
public const string Value = "src/folderA/Template2.anyext";
}
}
public static partial class FolderB
{
public const string Value = "src/folderB";
public static partial class Template3
{
public const string Value = "src/folderB/Template3.anyext";
}
public static partial class Template4
{
public const string Value = "src/folderB/Template4.anyext";
}
}
}
}
// TypedPaths.Template.g.cs
// <auto-generated/>
namespace TypedPaths;
public static partial class TypedPaths
{
public static partial class Template
{
public const string Value = "template";
public static partial class Email
{
public const string Value = "template/email";
public static partial class Welcome
{
public const string Value = "template/email/welcome.txt";
}
}
public static partial class Sms
{
public const string Value = "template/sms";
public static partial class Otp
{
public const string Value = "template/sms/otp.txt";
}
}
}
}
So you can use TypedPaths.Src.FolderA.Template2.Value and TypedPaths.Template.Email.Welcome.Value instead of raw string paths.
Requirements
- .NET 8 (or the TFM your project uses; the generator targets .NET Standard 2.0)
- MSBuild / SDK-style projects
Setup
Option A: consume from NuGet (recommended)
<ItemGroup>
<PackageReference Include="TypedPaths.Generator" Version="1.0.0" />
</ItemGroup>
<ItemGroup>
<TypedPathsFolder Include="src" ClassName="Src" />
<TypedPathsFolder Include="template" />
</ItemGroup>
That is the only configuration needed in consumer projects.
TypedPaths.Generator.targets (from package build) automatically maps each TypedPathsFolder to AdditionalFiles for source generation.
Option B: local project reference (repository development)
<ItemGroup>
<ProjectReference Include="..\TypedPaths.Generator\TypedPaths.Generator.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>
<ItemGroup>
<TypedPathsFolder Include="src" ClassName="Src" />
<TypedPathsFolder Include="template" />
</ItemGroup>
<Import Project="..\TypedPaths.Generator\build\TypedPaths.Generator.targets"
Condition="Exists('..\TypedPaths.Generator\build\TypedPaths.Generator.targets')" />
The explicit <Import /> is required only for local project-reference scenarios.
Build the project; the generator runs and adds TypedPaths.*.g.cs files to the compilation.
Usage in code
The generated type is in namespace TypedPaths, and the root class is also named TypedPaths. To avoid name clashes, use an alias:
using TypedPathsRoot = TypedPaths.TypedPaths;
// Always read .Value (works for both folder and file nodes)
string folderPath = TypedPathsRoot.Src.FolderA.Value; // "src/folderA"
string filePath = TypedPathsRoot.Src.FolderA.Template2.Value; // "src/folderA/Template2.anyext"
string emailTemplate = TypedPathsRoot.Template.Email.Welcome.Value; // "template/email/welcome.txt"
// e.g. resolve to full path
var fullPath = Path.Combine(projectRoot, TypedPathsRoot.Src.FolderA.Template2.Value);
Value is always a path relative to the project root:
- Folder node
Value= relative folder path - File node
Value= relative file path (including extension)
Nested child classes are emitted only for folders (because only folders can contain files/subfolders).
Naming rules
- Folder and file names become PascalCase identifiers.
- Invalid identifier characters are dropped or split; leading digits get a
_prefix. - Duplicate names in the same scope get suffixes:
_2,_3, etc. - Extensions are stripped from member names but kept in the path string.
- If a folder name and file name conflict in the same scope:
- the folder keeps the base name;
- the file name becomes
FileName + ExtensionWithoutDot(example:report/+report.txt→ReportandReportTxt); - if the conflicting file has no extension, use
Filesuffix (example:data/+data→DataandDataFile).
Repository layout
| Project | Description |
|---|---|
TypedPaths.Generator |
The source generator (Roslyn incremental generator). |
TypedPaths.Generator.Sample |
Example app that uses the generator and runs a small demo. |
TypedPaths.Generator.Tests |
Unit tests for the generator. |
Build and test
dotnet restore
dotnet build
dotnet test
Run the sample:
dotnet run --project TypedPaths.Generator.Sample
License
See the repository for license information.
Learn more about Target Frameworks and .NET Standard.
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.