Awesome
Selectorlyzer Analyzers for the .NET Compiler Platform
Selectorlyzer.Analyzers is a highly customizable Roslyn Analyzer designed to empower developers with the ability to create project-specific analyzers using a CSS selector-like syntax.
<img src="https://github.com/rlgnak/Selectorlyzer.Analyzers/assets/1643317/a56e8fef-1e42-47b4-acbf-7be884f91d6f" width="453" height="250">Getting Started
The preferable way to use the analyzers is to add the NuGet package Selectorlyzer.Analyzers to the project where you want to enforce rules.
A selectorlyzer.json
or .selectorlyzer.json
file is used to specify rules.
Installation
- Install the NuGet Package
Selectorlyzer.Analyzers
.
dotnet add package Selectorlyzer.Analyzers
- Create and configure
selectorlyzer.json
file.
{
"rules": [
{
"selector": ":class:has([Name='InvalidClassName'])",
"message": "Classes should not be named 'InvalidClassName'",
"severity": "error"
},
{
"selector": "InvocationExpression[Expression='Console.WriteLine']",
"message": "Do not use Console.WriteLine",
"severity": "error"
},
{
"selector": ":class:implements([Name='BaseRepository'])",
"rule": ":implements([Name='I{Name}'])",
"message": "Classes that implement 'BaseRepository' should implement an interface with the same name.",
"severity": "error"
}
]
}
- Add the following to your
.csproj
files
<ItemGroup>
<AdditionalFiles Include="selectorlyzer.json" />
</ItemGroup>
Example Rules
Naming Conventions
:class:has([Name='InvalidClassName'])
- Classes should not be namedInvalidClassName
:class:has([Name^='InvalidPrefix'])
- Classes should not start withInvalidPrefix
:class:has([Name$='InvalidSuffix'])
- Classes should not end withInvalidSuffix
:method:has([Name='InvalidMethodName'])
- Methods should not be namedInvalidMethodName
:method[Modifiers~='async']:not([Name$='Async'])
- Async method names should end withAsync
:method[Modifiers~='async'][Name$='Async']
- Async method names should not end withAsync
PropertyDeclaration[Type^='bool']:not([Identifier$='Flag'])
- Boolean property names should end withFlag
Custom Project Conventions
InvocationExpression[Expression='Console.WriteLine']
-Console.WriteLine
should not be used.InvocationExpression[Expression^='Assert.\']
- Methods starting withAssert.
should not be used.:class:implements([Name$='DataTransferObject']) ConstructorDeclaration
- Classes that implement DataTransferObject should not have constructors.:class[Name$='Controller'] :method[Modifiers~='public'][ReturnType='void']
- Public methdos within classes with names ending inController
should not returnvoid
.:class[Name$='Controller'] :method[Modifiers~='public'] Attribute[Name^='Http']
- Public methods within classes with names ending inController
should have an attribute that starts withHttp
:class:implements([Name='BaseRepository'])
with a rule of:implements([Name='I{Name}'])
- Classes that implementBaseRepository
should implement an interface with the same name.:method Block > * ReturnStatement
- Methods should only have on return statment and it should be the last statement in the method.
Selectors
Selectorlyzer uses a query langage for Roslyn Inspired by Qulaly and esquery. These selectors are used to identify speicifc sytax nodes.
Supported Selectors
Selectorlizer supports a subset of CSS selector level 4. The selector engine also supports Selectorlizer-specific extensions to the selector.
- SyntaxNode Type:
MethodDeclaration
,ClassDeclaration
...- See also SyntaxKind enum
- SyntaxNode Univarsal:
*
- SyntaxNode pseudo-classes (for short-hand)
:method
:class
:interface
:lambda
- Combinators
- Descendant:
node descendant
- Child:
node > child
- Next-sibling:
node + next
- Subsequent-sibling:
node ~ sibling
- Descendant:
- Pseudo-class
- Negation:
:not(...)
- Matches-any:
:is(...)
- Relational:
:has(...)
:nth-child
:first-child
:last-child
- Negation:
- Attributes (Properties)
[PropName]
(existance)[PropName = 'Exact']
[PropName ^= 'StartsWith']
[PropName $= 'EndsWith']
[PropName *= 'Contains']
[PropName ~= 'Item']
(ex.[Modifiers ~= 'async']
)
- Extensions
:implements(...)
: Combinator for checking if a class or interface implements a matching selector[Name = 'MethodName']
: Name special propertyName
is a special property for convenience that can be used inMethodDeclaration
,ClassDeclaration
... etc
[TypeParameters.Count > 0]
: ConditionsParameters.Count
TypeParameters.Count
License
MIT License
Selectorlyzer.Analyzers Copyright © 2023-present Richard Graves <rlgnak+selectorlyzer@gmail.com>