FxMap.Analyzers
1.0.3
dotnet add package FxMap.Analyzers --version 1.0.3
NuGet\Install-Package FxMap.Analyzers -Version 1.0.3
<PackageReference Include="FxMap.Analyzers" Version="1.0.3"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="FxMap.Analyzers" Version="1.0.3" />
<PackageReference Include="FxMap.Analyzers"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add FxMap.Analyzers --version 1.0.3
#r "nuget: FxMap.Analyzers, 1.0.3"
#:package FxMap.Analyzers@1.0.3
#addin nuget:?package=FxMap.Analyzers&version=1.0.3
#tool nuget:?package=FxMap.Analyzers&version=1.0.3
FxMap.Analyzers
Roslyn Code Analyzer for validating FxMap Expression syntax at compile-time.
Overview
FxMap.Analyzers provides comprehensive syntax validation for FxMap Expression strings used in ProfileOf<T> configurations. It catches expression syntax errors during compilation, preventing runtime failures.
Diagnostic Rules
OFX001: Expression Syntax Invalid
Severity: Error Category: Syntax
This analyzer validates FxMap Expression strings for correct syntax including:
1. Balanced Delimiters
- Brackets
[]for indexers - Braces
{}for projections - Parentheses
()for filters
2. Property Navigation
- Projection requires dot:
Country.{Id, Name}notCountry{Id, Name} - Navigation after filter requires dot:
Orders(Status = 'Done').ItemsnotOrders(Status = 'Done')Items - Navigation after indexer requires dot:
Provinces[0 asc Name].NamenotProvinces[0 asc Name]Name
3. Function Validation
- Function names must be valid (count, sum, avg, min, max, upper, lower, etc.)
- Functions requiring arguments must have them (e.g.,
substring,replace)
4. Computed Expressions
- Computed expressions in projections must have alias:
{Id, (Name:upper) as UpperName}not{Id, (Name:upper)}
5. Operators
- Must use valid operators:
=,!=,>,<,>=,<=,contains,startswith,endswith - Logical operators:
&&,||,!,and,or,not
Examples
Valid Expressions
// In a ProfileOf<T> configuration:
public class ProvinceResponseProfile : ProfileOf<ProvinceResponse>
{
protected override void Configure()
{
// Simple property navigation
UseDistributedKey<CountryOfAttribute>()
.Of(x => x.CountryId)
.For(x => x.CountryName, "Country.Name");
// Projection with proper dot
UseDistributedKey<CountryOfAttribute>()
.Of(x => x.CountryId)
.For(x => x.CountryInfo, "Country.{Id, Name}");
}
}
// Root projection
.For(x => x.MemberInfo, "{Id, Name, Email}")
// Projection with alias
.For(x => x.Data, "{Id, Country.Name as CountryName}")
// Filter with proper navigation
.For(x => x.OrderItems, "Orders(Status = 'Done').Items")
// Indexer with proper navigation
.For(x => x.ProvinceName, "Provinces[0 asc Name].Name")
// Complex filter with string operations
.For(x => x.ProvinceName, "Provinces(Name endswith 'a')[0 desc Name].Name")
// Functions with arguments
.For(x => x.ShortName, "{Id, Name:substring(0, 3) as Short}")
// Computed expressions with alias
.For(x => x.Data, "{Id, (Name:upper) as UpperName}")
// Ternary with alias
.For(x => x.Status, "{Id, (Active = true ? 'Yes' : 'No') as StatusText}")
Invalid Expressions (Analyzer Errors)
// Missing closing brace
.For(x => x.CountryInfo, "Country.{Id, Name")
// Error: Expected '}' after projection
// Missing closing bracket
.For(x => x.ProvinceInfo, "Provinces[asc Name")
// Error: Expected ']' after indexer
// Missing closing parenthesis
.For(x => x.OrderInfo, "Orders(Status = 'Done'")
// Error: Expected ')' after filter condition
// Missing dot before projection
.For(x => x.CountryInfo, "Country{Id, Name}")
// Error: Projection requires '.' before '{'
// Missing dot after filter
.For(x => x.OrderItems, "Orders(Status = 'Done')Items")
// Error: Property navigation requires '.' before identifier
// Missing dot after indexer
.For(x => x.ProvinceName, "Provinces[0 asc Name]Name")
// Error: Property navigation requires '.' before identifier
// Unknown function
.For(x => x.Name, "Name:invalid")
// Error: Unknown function 'invalid'
// Function missing required arguments
.For(x => x.Name, "Name:substring")
// Error: Function 'substring' requires arguments
// Computed expression without alias
.For(x => x.Data, "{Id, (Name:upper)}")
// Error: Expected 'as' keyword after computed expression - alias is required
// Invalid operator
.For(x => x.Users, "Users(Age >> 18)")
// Error: Expected value ('>>' is not a valid operator)
Installation
Via NuGet Package
dotnet add package FxMap.Analyzers
Via Project Reference
Add to your .csproj:
<ItemGroup>
<ProjectReference Include="../path/to/FxMap.Analyzers/FxMap.Analyzers.csproj" />
</ItemGroup>
How It Works
- Compile-Time Analysis: The analyzer runs during compilation and inspects all FluentAPI configurations
- Expression Parsing: Each expression string passed to
.For(),.Expression(), or.Else()is validated using the full FxMap ExpressionParser - Immediate Feedback: Syntax errors are reported as compiler errors with detailed messages including position information
Features
Current Validations
- Syntax Structure: All brackets, braces, parentheses must be balanced
- Navigation Syntax: Dot requirements for property navigation
- Function Names: Validates against known function list
- Function Arguments: Ensures required arguments are provided
- Operator Validation: Only valid operators are allowed
- Alias Requirements: Computed expressions must have aliases in projections
- Position Information: Error messages include exact position of syntax errors
Current Limitations
This is a syntax-only analyzer. It does NOT validate:
- Whether property names exist in your entities
- Whether navigation paths are valid for your data model
- Data types or type compatibility
- Semantic correctness of expressions
These semantic validations happen at runtime when expressions are executed.
Demo Project
See the demo project at sample/Service1.Contract for comprehensive examples of both valid and invalid expressions.
cd sample/Service1.Contract
dotnet build
The demo build will show analyzer errors for all invalid expressions.
Error Message Format
error OFX001: Expression '{expression}' is invalid: {detailed-error-message}
Example:
error OFX001: Expression 'Country{Id, Name}' is invalid: Projection requires '.' before '{' at position 7
Supported FxMap Expression Features
- Property navigation:
Country.Name,Country.Province.Name - Projections:
Country.{Id, Name},{Id, Name as UserName} - Root projections:
{Id, Email, Country.Name as CountryName} - Filters:
Countries(Active = true),Provinces(Name contains 'land') - Indexers:
Provinces[0 10 asc Name],Items[0 10 desc Price] - Functions:
Name:upper,Price:round(2),Items:count - String functions:
upper,lower,trim,substring,replace,concat,split - Math functions:
round,floor,ceil,abs,add,subtract,multiply,divide - Date functions:
year,month,day,format - Aggregate functions:
count,sum,avg,min,max,distinct - Collection functions:
any,all,groupBy - Boolean functions:
any(condition),all(condition) - Ternary operator:
(Status = 'Active' ? 'Yes' : 'No') as StatusText - Null coalescing:
(Nickname ?? Name) as DisplayName - Chained functions:
Name:trim:upper,Price:add(10):round(2)
Contributing
Found a bug or want to contribute? Please visit GitHub Repository.
License
This project is licensed under the Apache-2.0 license.
| 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 is compatible. 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 is compatible. 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. |
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.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.