TypedPaths.Generator
1.2.1
See the version list below for details.
dotnet add package TypedPaths.Generator --version 1.2.1
NuGet\Install-Package TypedPaths.Generator -Version 1.2.1
<PackageReference Include="TypedPaths.Generator" Version="1.2.1" />
<PackageVersion Include="TypedPaths.Generator" Version="1.2.1" />
<PackageReference Include="TypedPaths.Generator" />
paket add TypedPaths.Generator --version 1.2.1
#r "nuget: TypedPaths.Generator, 1.2.1"
#:package TypedPaths.Generator@1.2.1
#addin nuget:?package=TypedPaths.Generator&version=1.2.1
#tool nuget:?package=TypedPaths.Generator&version=1.2.1
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 buildTransitive) 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\buildTransitive\TypedPaths.Generator.targets"
Condition="Exists('..\TypedPaths.Generator\buildTransitive\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.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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 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. |
-
net8.0
- Microsoft.CodeAnalysis.CSharp (>= 4.10.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.