Skip to content

Selectorlyzer is a configurable Roslyn Analyzer that uses CSS selector-like syntax for enforcing project specific conventions.

License

Notifications You must be signed in to change notification settings

rlgnak/Selectorlyzer.Analyzers

Repository files navigation

Selectorlyzer Analyzers for the .NET Compiler Platform

NuGet Build Status

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.

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

  1. Install the NuGet Package Selectorlyzer.Analyzers.
dotnet add package Selectorlyzer.Analyzers
  1. 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"
    }
  ]
}
  1. 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 named InvalidClassName
  • :class:has([Name^='InvalidPrefix']) - Classes should not start with InvalidPrefix
  • :class:has([Name$='InvalidSuffix']) - Classes should not end with InvalidSuffix
  • :method:has([Name='InvalidMethodName']) - Methods should not be named InvalidMethodName
  • :method[Modifiers~='async']:not([Name$='Async']) - Async method names should end with Async
  • :method[Modifiers~='async'][Name$='Async'] - Async method names should not end with Async
  • PropertyDeclaration[Type^='bool']:not([Identifier$='Flag']) - Boolean property names should end with Flag

Custom Project Conventions

  • InvocationExpression[Expression='Console.WriteLine'] - Console.WriteLine should not be used.
  • InvocationExpression[Expression^='Assert.\'] - Methods starting with Assert. 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 in Controller should not return void.
  • :class[Name$='Controller'] :method[Modifiers~='public'] Attribute[Name^='Http'] - Public methods within classes with names ending in Controller should have an attribute that starts with Http
  • :class:implements([Name='BaseRepository']) with a rule of :implements([Name='I{Name}']) - Classes that implement BaseRepository 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 ...
  • SyntaxNode Univarsal: *
  • SyntaxNode pseudo-classes (for short-hand)
    • :method
    • :class
    • :interface
    • :lambda
  • Combinators
  • Pseudo-class
  • 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 property
      • Name is a special property for convenience that can be used in MethodDeclaration, ClassDeclaration ... etc
    • [TypeParameters.Count > 0]: Conditions
      • Parameters.Count
      • TypeParameters.Count

License

MIT License

Selectorlyzer.Analyzers Copyright © 2023-present Richard Graves <[email protected]>

About

Selectorlyzer is a configurable Roslyn Analyzer that uses CSS selector-like syntax for enforcing project specific conventions.

Resources

License

Stars

Watchers

Forks

Packages

No packages published