A Roslyn source generator that turns a folder tree into strongly typed path constants at compile time.
$ dotnet add package TypedPaths.GeneratorA 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.
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.
<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.
<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.
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:
Value = relative folder pathValue = relative file path (including extension)Nested child classes are emitted only for folders (because only folders can contain files/subfolders).
_ prefix._2, _3, etc.FileName + ExtensionWithoutDot (example: report/ + report.txt -> Report and ReportTxt);File suffix (example: data/ + data -> Data and DataFile).| 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. |
dotnet restore
dotnet build
dotnet test
Run the sample:
dotnet run --project TypedPaths.Generator.Sample
See the repository for license information.