noxrat.analyzers
2.0.0
dotnet add package noxrat.analyzers --version 2.0.0
NuGet\Install-Package noxrat.analyzers -Version 2.0.0
<PackageReference Include="noxrat.analyzers" Version="2.0.0" />
<PackageVersion Include="noxrat.analyzers" Version="2.0.0" />
<PackageReference Include="noxrat.analyzers" />
paket add noxrat.analyzers --version 2.0.0
#r "nuget: noxrat.analyzers, 2.0.0"
#:package noxrat.analyzers@2.0.0
#addin nuget:?package=noxrat.analyzers&version=2.0.0
#tool nuget:?package=noxrat.analyzers&version=2.0.0
Noxrat.Analyzers
Roslyn analyzers + generator for namespace conventions, attribute constraints, and compile-time baked string constants.
Namespace Rule Configuration (.editorconfig)
EditorConfig-only schema for namespace enforcement.
Keys
noxrat_namespace_root(required): root namespace for matched files.noxrat_namespace_scope_dir(optional, default.): project-relative scope anchor.noxrat_namespace_folder_traversal_depth(optional, default0, clamped0..5): number of directory segments appended from file path relative toscope_dir.
Computation
- Resolve
scope_diragainstProjectDir. - If file not under
scope_dir, rule is inactive for that file. - Compute file-directory relative path from
scope_dir. - Take first
depthsegments. - Expected namespace =
root+.+ taken segments (if any segments).
Section precedence
- Standard
.editorconfigprecedence applies (more specific/later match wins).
Configuration example
root = true
[*.cs]
noxrat_namespace_root = Project1
noxrat_namespace_scope_dir = .
noxrat_namespace_folder_traversal_depth = 0
[addons/SomeAddon/**/*.cs]
noxrat_namespace_root = SomeAddon
noxrat_namespace_scope_dir = addons/SomeAddon
noxrat_namespace_folder_traversal_depth = 2
[Scripts/**/*.cs]
noxrat_namespace_root = Project1.Core
noxrat_namespace_scope_dir = Scripts
noxrat_namespace_folder_traversal_depth = 2
Path mapping example
| File Path | Matching Section | Expected Namespace |
|---|---|---|
addons/SomeAddon/File.cs |
[addons/SomeAddon/**/*.cs] |
SomeAddon |
addons/SomeAddon/Utils/TestUtil.cs |
[addons/SomeAddon/**/*.cs] |
SomeAddon.Utils |
Scripts/DTOs/ServiceDTO.cs |
[Scripts/**/*.cs] |
Project1.Core.DTOs |
Program.cs |
[*.cs] |
Project1 |
Attributes
Enforcing Type Attribute Contracts [RequiresAttributeAttribute]
Coding impact: Compile-time contract / constraint enforcement.
Attribute: RequiresAttributeAttribute
- Target: Parameters + generic type parameters.
- AllowMultiple:
true - Parameters:
anyOf(paramsType[], required) → target type must have any one listed attribute.
Usage:
void Serialize<[RequiresAttribute(typeof(SerializableAttribute))] T>(T value) { }
void Process([RequiresAttribute(typeof(MarkerA), typeof(MarkerB))] object input) { }
Behavior:
- Enforced at call sites (
invocation,new), not declaration. - OR semantics inside one attribute instance.
- AND semantics across multiple attribute instances.
- Checks inheritance chain and derived attribute matches.
- Unwraps arrays and nullable before checking.
Diagnostic:
| ID | Severity | Message |
|---|---|---|
Noxrat0001 |
Warning | Type {0} does not contain required attributes: {1} |
Baking Compile-Time String Constants [BakeStringConstantAttribute]
Coding impact: Compile-time source generation + validation.
Attribute: BakeStringConstantAttribute
- Target: Classes
- AllowMultiple:
true - Parameters:
format(required)listOfFields(required)- optional
variableNameoverload
Usage:
[BakeStringConstant("{field,separator:', '}", listOfFields: [KEY1, KEY2, KEY3])]
[BakeStringConstant("PACK", "[{field,separator:', '}] has {field_count}", listOfFields: [KEY1, KEY2])]
public static partial class Keys
{
public const string KEY1 = "spawn_point";
public const string KEY2 = "body_strength";
public const string KEY3 = "body_count";
}
Behavior:
- No field scanning. Only symbols from
listOfFieldsare used. - Supports cross-type constants (
OtherType.KEY). - One generated
public const string <VariableName>per valid attribute instance. - Generated constant field is annotated with
GeneratedCodeAttribute. - Invalid instance reports diagnostics and skips only that instance.
- Class must be
partial. - Nested class unsupported.
- Name collisions reported.
- Uses Noxrat Format Schema tokens:
field,field_count.
Diagnostic:
| ID Range | Severity |
|---|---|
Noxrat0002 - Noxrat0010 |
Error |
Noxrat Format Schema
Standalone template schema for codegen formatting.
Supported specifiers
{field}{field_count}{field,separator:'...'}{field,separator:'...',prefix:'...',suffix:'...'}
Supported field options
separatorprefixsuffix
No other options accepted.
Escape rules
- In literal text:
\{,\},\\ - In option strings (
'...'):\\,\',\",\{,\},\n,\r,\t
Semantics
{field}joins resolved field values.- Default separator is
", ". prefixandsuffixapply per item.{field_count}outputs number of resolved field values.- Format must contain at least one token (
fieldorfield_count).
Examples
field1, field2, field3
"{field,separator:', '}"
[field1, field2, field3]
"[{field,separator:', '}]"
{"expected":["field1", "field2", "field3"]}
"\\{\"expected\":[{field,separator:', ',prefix:\\\",suffix:\\\"}]\\}"
[field1, field2, field3] has 3
"[{field,separator:', '}] has {field_count}"
Diagnostic Reports
Noxrat0000 Namespace mismatch
Example
.editorconfig[Scripts/**/*.cs]noxrat_namespace_root = Project1.Corenoxrat_namespace_scope_dir = Scriptsnoxrat_namespace_folder_traversal_depth = 1Scripts/DTOs/ServiceDTO.cs
namespace Project1.Core.DTOs.More;
public class SomeClass { } // will report: expected Project1.Core.DTOs
Fix
namespace Project1.Core.DTOs;
public class SomeClass { } // acceptable
Noxrat0001 Required attribute missing
Example
[MyMarker]
public class Marked {}
public class Unmarked {}
public static class Api
{
public static void Run<[RequiresAttribute(typeof(MyMarkerAttribute))] T>() {}
public static void Test()
{
Run<Unmarked>(); // will report: Unmarked missing MyMarkerAttribute
}
}
Fix
[MyMarker]
public class Marked {}
public static class Api
{
public static void Run<[RequiresAttribute(typeof(MyMarkerAttribute))] T>() {}
public static void Test()
{
Run<Marked>(); // acceptable
}
}
Noxrat0002 BakeStringConstant field is not const
Example
[BakeStringConstant("{field}", listOfFields: [KEY1])]
public static partial class Keys
{
public static readonly string KEY1 = "v"; // will report: field must be const
}
Fix
[BakeStringConstant("{field}", listOfFields: [KEY1])]
public static partial class Keys
{
public const string KEY1 = "v"; // acceptable
}
Noxrat0003 BakeStringConstant field has invalid type
Example
[BakeStringConstant("{field}", listOfFields: [KEY1])]
public static partial class Keys
{
public const int KEY1 = 7; // will report: field must be string or char
}
Fix
[BakeStringConstant("{field}", listOfFields: [KEY1])]
public static partial class Keys
{
public const string KEY1 = "7"; // acceptable
}
Noxrat0004 Class must be partial
Example
[BakeStringConstant("{field}", listOfFields: [KEY1])]
public static class Keys // will report: class must be partial
{
public const string KEY1 = "v";
}
Fix
[BakeStringConstant("{field}", listOfFields: [KEY1])]
public static partial class Keys // acceptable
{
public const string KEY1 = "v";
}
Noxrat0005 Field list empty
Example
[BakeStringConstant("{field}", listOfFields: [])] // will report: empty field list
public static partial class Keys {}
Fix
[BakeStringConstant("{field}", listOfFields: [KEY1])]
public static partial class Keys
{
public const string KEY1 = "v"; // acceptable
}
Noxrat0006 Invalid variable name
Example
[BakeStringConstant("123_BAD", "{field}", listOfFields: [KEY1])] // will report: invalid identifier
public static partial class Keys
{
public const string KEY1 = "v";
}
Fix
[BakeStringConstant("GOOD_NAME", "{field}", listOfFields: [KEY1])]
public static partial class Keys
{
public const string KEY1 = "v"; // acceptable
}
Noxrat0007 Variable name collision
Example
[BakeStringConstant("PACK", "{field}", listOfFields: [KEY1])]
public static partial class Keys
{
public const string PACK = "already"; // will collide with generated PACK
public const string KEY1 = "v";
}
Fix
[BakeStringConstant("PACK_KEYS", "{field}", listOfFields: [KEY1])]
public static partial class Keys
{
public const string PACK = "already";
public const string KEY1 = "v"; // acceptable
}
Noxrat0008 Nested class unsupported
Example
public static class Outer
{
[BakeStringConstant("{field}", listOfFields: [KEY1])] // will report: nested class unsupported
public static partial class Inner
{
public const string KEY1 = "v";
}
}
Fix
[BakeStringConstant("{field}", listOfFields: [KEY1])]
public static partial class Keys
{
public const string KEY1 = "v"; // acceptable
}
Noxrat0009 Field reference invalid
Example
[BakeStringConstant("{field}", listOfFields: [nameof(KEY1)])] // will report: expression not a field symbol
public static partial class Keys
{
public const string KEY1 = "v";
}
Fix
[BakeStringConstant("{field}", listOfFields: [KEY1])]
public static partial class Keys
{
public const string KEY1 = "v"; // acceptable
}
Noxrat0010 Format schema invalid
Example
[BakeStringConstant("{field_json}", listOfFields: [KEY1])] // will report: unsupported token
public static partial class Keys
{
public const string KEY1 = "v";
}
Fix
[BakeStringConstant("{field,separator:', ',prefix:'\"',suffix:'\"'}", listOfFields: [KEY1])]
public static partial class Keys
{
public const string KEY1 = "v"; // acceptable
}
Installation
<PackageReference Include="Noxrat.Analyzers" Version="1.0.0" />
| Product | Versions 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. |
-
.NETStandard 2.0
- 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.