TypedPaths.Generator
1.3.0
dotnet add package TypedPaths.Generator --version 1.3.0
NuGet\Install-Package TypedPaths.Generator -Version 1.3.0
<PackageReference Include="TypedPaths.Generator" Version="1.3.0" />
<PackageVersion Include="TypedPaths.Generator" Version="1.3.0" />
<PackageReference Include="TypedPaths.Generator" />
paket add TypedPaths.Generator --version 1.3.0
#r "nuget: TypedPaths.Generator, 1.3.0"
#:package TypedPaths.Generator@1.3.0
#addin nuget:?package=TypedPaths.Generator&version=1.3.0
#tool nuget:?package=TypedPaths.Generator&version=1.3.0
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 defining a top-level static class in the TypedPaths namespace:
// TypedPaths.Src.g.cs
// <auto-generated/>
namespace TypedPaths;
public static class Src
{
public const string Value = "src";
public static class Template1
{
public const string Value = "src/Template1.anyext";
}
public static class FolderA
{
public const string Value = "src/folderA";
public static class Template2
{
public const string Value = "src/folderA/Template2.anyext";
}
}
public static class FolderB
{
public const string Value = "src/folderB";
public static class Template3
{
public const string Value = "src/folderB/Template3.anyext";
}
public static class Template4
{
public const string Value = "src/folderB/Template4.anyext";
}
}
}
// TypedPaths.Template.g.cs
// <auto-generated/>
namespace TypedPaths;
public static class Template
{
public const string Value = "template";
public static class Email
{
public const string Value = "template/email";
public static class Welcome
{
public const string Value = "template/email/welcome.txt";
}
}
public static class Sms
{
public const string Value = "template/sms";
public static class Otp
{
public const string Value = "template/sms/otp.txt";
}
}
}
With using TypedPaths; you can use Src.FolderA.Template2.Value and 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
Add using TypedPaths; and use the generated classes directly. Each configured root folder becomes a top-level static class (e.g. Src, Template):
using TypedPaths;
// Always read .Value (works for both folder and file nodes)
string folderPath = Src.FolderA.Value; // "src/folderA"
string filePath = Src.FolderA.Template2.Value; // "src/folderA/Template2.anyext"
string emailTemplate = Template.Email.Welcome.Value; // "template/email/welcome.txt"
// e.g. resolve to full path
var fullPath = Path.Combine(projectRoot, 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.