Ivy.Analyser
1.2.44
dotnet add package Ivy.Analyser --version 1.2.44
NuGet\Install-Package Ivy.Analyser -Version 1.2.44
<PackageReference Include="Ivy.Analyser" Version="1.2.44"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="Ivy.Analyser" Version="1.2.44" />
<PackageReference Include="Ivy.Analyser"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add Ivy.Analyser --version 1.2.44
#r "nuget: Ivy.Analyser, 1.2.44"
#:package Ivy.Analyser@1.2.44
#addin nuget:?package=Ivy.Analyser&version=1.2.44
#tool nuget:?package=Ivy.Analyser&version=1.2.44
Ivy.Analyser
A Roslyn-based .NET analyzer that enforces proper usage of Ivy framework hooks, similar to React's "Rules of Hooks".
Overview
This analyzer ensures that Ivy hook functions (such as UseState, UseEffect, etc.) are used only directly inside the Build() method of classes that inherit from ViewBase, following the same rules as React's Rules of Hooks. Violating these rules may cause runtime errors, so they are enforced at compile time.
The analyzer enforces that hooks must be called:
- ✅ At the top level of the
Build()method - ✅ Unconditionally (not inside if statements, loops, or switch statements)
- ✅ In the same order on every render
Installation
Using Package Manager Console
Install-Package Ivy.Analyser
Using .NET CLI
dotnet add package Ivy.Analyser
Using PackageReference
Add the following to your .csproj file:
<PackageReference Include="Ivy.Analyser" Version="1.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
Rules Enforced
✅ Valid Usage
Hook functions must be invoked directly inside the top level of the Build() method:
public class MyView : ViewBase
{
public override object? Build()
{
var state = UseState(false); // ✅ Valid
UseEffect(() => { /* ... */ }); // ✅ Valid
var memo = UseMemo(() => 42); // ✅ Valid
return new Button();
}
}
❌ Invalid Usage
The analyzer will report errors and warnings for these violations:
1. Hook calls inside lambdas (Error IVYHOOK001)
public override object? Build()
{
var handler = (Event<Button> e) =>
{
var s = UseState(false); // ❌ Error IVYHOOK001
};
return new Button().OnClick(handler);
}
2. Hook calls inside local functions (Error IVYHOOK001)
public override object? Build()
{
void LocalFunction()
{
var s = UseState(false); // ❌ Error IVYHOOK001
}
LocalFunction();
return new Button();
}
3. Hook calls in other methods (Error IVYHOOK001)
public override object? Build()
{
Initialize();
return new Button();
}
private void Initialize()
{
var s = UseState(false); // ❌ Error IVYHOOK001
}
4. Hook calls in anonymous methods (Error IVYHOOK001)
public override object? Build()
{
Action action = delegate()
{
var s = UseState(false); // ❌ Error IVYHOOK001
};
return new Button();
}
5. Hook calls conditionally (Warning IVYHOOK002)
public override object? Build()
{
if (someCondition)
{
var state = UseState(false); // ⚠️ Warning IVYHOOK002
}
var result = condition ? UseState(0) : UseState(1); // ⚠️ Warning IVYHOOK002 (ternary)
return new Button();
}
6. Hook calls in loops (Warning IVYHOOK003)
public override object? Build()
{
for (int i = 0; i < 10; i++)
{
var state = UseState(i); // ⚠️ Warning IVYHOOK003
}
foreach (var item in items)
{
var state = UseState(item); // ⚠️ Warning IVYHOOK003
}
while (condition)
{
var state = UseState(false); // ⚠️ Warning IVYHOOK003
}
return new Button();
}
7. Hook calls in switch statements (Warning IVYHOOK004)
public override object? Build()
{
switch (value)
{
case 1:
var state = UseState(false); // ⚠️ Warning IVYHOOK004
break;
}
return new Button();
}
8. Hook calls not at the top of Build() method (Warning IVYHOOK005)
public override object? Build()
{
var x = SomeMethod(); // Non-hook statement
var state = UseState(false); // ⚠️ Warning IVYHOOK005 - hook must be at the top
int y = 10; // Another non-hook statement
var state2 = UseState(0); // ⚠️ Warning IVYHOOK005
return new Button();
}
Hook Detection
The analyzer automatically detects hooks by their naming convention:
- Method name must start with
Use - The fourth character must be an uppercase letter
Examples:
- ✅
UseState,UseEffect,UseCustomHook,UseMyFeature - ❌
Use,Useless,useState,useEffect
This means any custom hooks you create following the UseX pattern will be automatically validated by the analyzer.
Diagnostic Details
IVYHOOK001 - Invalid Hook Usage (Error)
Severity: Error
Message: Ivy hook '{hookName}' can only be used directly inside the Build() method
Description: Hooks must be called directly inside the Build() method, not inside lambdas, local functions, or other methods.
IVYHOOK002 - Hook Called Conditionally (Warning)
Severity: Warning
Message: Ivy hook '{hookName}' cannot be called conditionally. Hooks must be called in the same order on every render.
Description: Hooks must be called unconditionally at the top level of the Build() method. Do not call hooks inside if statements, ternary operators, or other conditional logic.
IVYHOOK003 - Hook Called in Loop (Warning)
Severity: Warning
Message: Ivy hook '{hookName}' cannot be called inside a loop. Hooks must be called in the same order on every render.
Description: Hooks must be called unconditionally at the top level of the Build() method. Do not call hooks inside for, foreach, while, or do-while loops.
IVYHOOK004 - Hook Called in Switch Statement (Warning)
Severity: Warning
Message: Ivy hook '{hookName}' cannot be called inside a switch statement. Hooks must be called in the same order on every render.
Description: Hooks must be called unconditionally at the top level of the Build() method. Do not call hooks inside switch statements.
IVYHOOK005 - Hook Not at Top of Build Method (Warning)
Severity: Warning
Message: Ivy hook '{hookName}' must be called at the top of the Build() method, before any other statements.
Description: All hooks must be called at the very top of the Build() method, before any other non-hook statements. This ensures hooks are called in a consistent order on every render.
IVYHOOK007 - Hook Called Inline in Expression (Warning)
Severity: Warning
Message: '{hookName}' should be assigned to a local variable at the top of the Build method, not called inline in an expression.
Description: Hooks must be assigned to a top-level local variable or called as a standalone expression statement. Do not call hooks inline within widget construction expressions, pipe chains, constructor arguments, or return statements.
Quick Fix
The analyzer includes a CodeFixProvider that can automatically extract inline hook calls to variables.
How to use:
- Place your cursor on the warning (yellow squiggle on the hook call)
- Trigger the quick action menu:
- Visual Studio: Press
Ctrl+.or click the lightbulb icon - VS Code: Press
Ctrl+.or click the lightbulb icon - Rider: Press
Alt+Enteror click the lightbulb icon
- Visual Studio: Press
- Select "Extract hook to variable" from the menu
- The hook call will be moved to the top of the Build() method and assigned to a variable
Example:
// Before fix:
public override object Build()
{
return new Text(UseState(0).Value.ToString()); // ⚠️ Warning IVYHOOK007
}
// After applying quick fix:
public override object Build()
{
var state = UseState(0); // ✅ Extracted
return new Text(state.Value.ToString());
}
Note: The quick fix generates variable names automatically (UseState → state, UseEffect → effect, etc.). If a variable with that name already exists, it will append a number (state2, state3, etc.).
IVYAPP001 - App Missing Parameterless Constructor (Error)
Severity: Error
Message: App '{AppName}' must have a parameterless constructor, use UseService<T>() inside Build() instead of constructor injection.
Description: App classes are instantiated via Activator.CreateInstance and require a parameterless constructor. Use UseService<T>() inside Build() for dependency injection.
Quick Fix
The analyzer includes a CodeFixProvider that can automatically add a parameterless constructor.
How to use:
- Place your cursor on the error (red squiggle on the class name)
- Trigger the quick action menu:
- Visual Studio: Press
Ctrl+.or click the lightbulb/screwdriver icon - VS Code: Press
Ctrl+.or click the lightbulb icon - Rider: Press
Alt+Enteror click the lightbulb icon
- Visual Studio: Press
- Select "Add parameterless constructor" from the menu
- An empty
public ClassName() { }constructor will be added to your class
Example:
// Before fix:
[App]
public class MyApp // ❌ Error IVYAPP001
{
public MyApp(IConfigService config) { }
public override object Build() => new Text("Hello");
}
// After applying quick fix:
[App]
public class MyApp // ✅ Fixed
{
public MyApp() { } // Added automatically
public MyApp(IConfigService config) { }
public override object Build() => new Text("Hello");
}
Note: The quick fix adds an empty parameterless constructor. You'll need to manually update your code to use UseService<T>() inside the Build() method instead of constructor injection.
IVYSERVICE001 - UseService Should Use Interface (Warning)
Severity: Warning
Message: UseService<{ConcreteType}> should use interface I{ConcreteType} instead. Using concrete types breaks testability and violates dependency inversion.
Description: When calling UseService<T>(), always prefer interface types over concrete types when an interface is available. This ensures proper dependency injection, testability, and adherence to SOLID principles.
✅ Valid Usage
public override object? Build()
{
var config = UseService<IConfigService>(); // ✅ Valid - using interface
var job = UseService<IJobService>(); // ✅ Valid - using interface
var git = UseService<IGitService>(); // ✅ Valid - using interface
return new Button();
}
❌ Invalid Usage
public override object? Build()
{
var config = UseService<ConfigService>(); // ⚠️ Warning IVYSERVICE001 - use IConfigService
var job = UseService<JobService>(); // ⚠️ Warning IVYSERVICE001 - use IJobService
return new Button();
}
Note: This warning only appears when a corresponding interface (prefixed with 'I') exists in the same namespace. If no interface exists, no warning is shown.
Quick Fix
The analyzer includes a CodeFixProvider that can automatically fix IVYSERVICE001 warnings with a single click.
How to use:
- Place your cursor on the warning (red/yellow squiggle)
- Trigger the quick action menu:
- Visual Studio: Press
Ctrl+.or click the lightbulb/screwdriver icon - VS Code: Press
Ctrl+.or click the lightbulb icon - Rider: Press
Alt+Enteror click the lightbulb icon
- Visual Studio: Press
- Select "Use interface I{ConcreteType}" from the menu
- The concrete type will be automatically replaced with its interface
Example:
// Before fix:
var config = UseService<ConfigService>(); // ⚠️ Warning IVYSERVICE001
// After applying quick fix:
var config = UseService<IConfigService>(); // ✅ Fixed
Fix All: You can apply the fix to multiple violations at once using "Fix All" in Visual Studio:
- Fix All in Document: Fixes all IVYSERVICE001 warnings in the current file
- Fix All in Project: Fixes all IVYSERVICE001 warnings in the project
- Fix All in Solution: Fixes all IVYSERVICE001 warnings in the solution
Note: The quick fix only appears when the corresponding interface (prefixed with 'I') exists in the same namespace. If no interface exists, the warning will still appear but no automatic fix will be offered.
Configuration
The analyzer runs automatically when you build your project. No additional configuration is needed.
Suppressing Warnings (Not Recommended)
If you need to suppress the analyzer for specific cases, you can use:
#pragma warning disable IVYHOOK001 // Suppress error
#pragma warning disable IVYHOOK002 // Suppress conditional warning
#pragma warning disable IVYHOOK003 // Suppress loop warning
#pragma warning disable IVYHOOK004 // Suppress switch warning
#pragma warning disable IVYHOOK005 // Suppress not-at-top warning
#pragma warning disable IVYSERVICE001 // Suppress UseService interface warning
var state = UseState(false); // This will not trigger the analyzer
#pragma warning restore IVYHOOK001
#pragma warning restore IVYHOOK002
#pragma warning restore IVYHOOK003
#pragma warning restore IVYHOOK004
#pragma warning restore IVYHOOK005
#pragma warning restore IVYSERVICE001
However, this is not recommended as it may lead to runtime errors.
IDE Integration
The analyzer works with:
- Visual Studio 2019/2022
- Visual Studio Code with C# extension
- JetBrains Rider
- Any IDE that supports Roslyn analyzers
Violations will be highlighted in your IDE with red squiggly lines and appear in the Error List.
Building from Source
git clone <repository-url>
cd Ivy.Analyser
dotnet build
dotnet test
dotnet pack
License
This project is licensed under the same license as the Ivy Framework.
Related
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- Microsoft.CodeAnalysis.CSharp (>= 5.0.0)
- Microsoft.CodeAnalysis.CSharp.Workspaces (>= 5.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.2.44 | 231 | 4/16/2026 |
| 1.2.43 | 233 | 4/16/2026 |
| 1.2.42 | 233 | 4/15/2026 |
| 1.2.42-pre-20260414163705 | 92 | 4/14/2026 |
| 1.2.40 | 344 | 4/14/2026 |
| 1.2.39-pre-20260414141311 | 79 | 4/14/2026 |
| 1.2.37-pre-20260414092333 | 81 | 4/14/2026 |
| 1.2.37-pre-20260414091731 | 75 | 4/14/2026 |
| 1.2.37-pre-20260414084831 | 89 | 4/14/2026 |
| 1.2.37-pre-20260414084740 | 80 | 4/14/2026 |
| 1.2.37-pre-20260412104447 | 187 | 4/12/2026 |
| 1.2.37-pre-20260410110521 | 85 | 4/10/2026 |
| 1.2.37-pre-20260410104611 | 90 | 4/10/2026 |
| 1.2.37-pre-20260409163352 | 80 | 4/9/2026 |
| 1.2.37-pre-20260408144108 | 87 | 4/8/2026 |
| 1.2.37-pre-20260408132826 | 78 | 4/8/2026 |
| 1.2.36 | 1,761 | 4/8/2026 |
| 1.2.36-pre-20260408100712 | 81 | 4/8/2026 |
| 1.2.36-pre-20260407134014 | 81 | 4/7/2026 |
| 1.2.35 | 987 | 4/6/2026 |