### Test NuGet Package Installation Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/PUBLISHING.md Commands to create a new console project, add the published package, and build it to verify the installation and functionality. ```bash # Create test project mkdir test-installation cd test-installation dotnet new console dotnet add package MapsterChecker.Analyzer --version 1.0.0 dotnet build ``` -------------------------------- ### Mapster Fluent API Configuration Example Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/MAPSTER_ANALYZER_DEEP_DIVE.md Demonstrates configuring Mapster mappings using a fluent API chain. Includes mapping properties, calculating values, ignoring properties, and custom construction. ```csharp // The analyzer handles complex fluent chains: TypeAdapterConfig .NewConfig() .Map(dest => dest.FullName, src => $"{src.FirstName} {src.LastName}") .Map(dest => dest.Age, src => DateTime.Now.Year - src.BirthYear) .Ignore(dest => dest.InternalId) .MapWith(src => new PersonDto { /* custom construction */ }); ``` -------------------------------- ### Inspect NuGet Package Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/PUBLISHING.md Optional steps to install NuGet Package Explorer and open a generated .nupkg file for inspection. Verify the contents and metadata of the package. ```bash # Install NuGet Package Explorer (if not already installed) dotnet tool install --global NuGetPackageExplorer # Open the package for inspection nuget-package-explorer ../nupkgs/MapsterChecker.Analyzer.1.0.0.nupkg ``` -------------------------------- ### Initialize Mapster Configuration Discovery Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/requirements/2025-07-21-1454-mapster-config-support/06-requirements-spec.md Register syntax node actions to discover Mapster configurations during analyzer initialization. This setup should be performed once. ```csharp var registry = new MappingConfigurationRegistry(); var discovery = new MapsterConfigurationDiscovery(registry); context.RegisterSyntaxNodeAction(discovery.DiscoverConfiguration, SyntaxKind.InvocationExpression); context.RegisterSyntaxNodeAction(ctx => AnalyzeInvocation(ctx, registry), SyntaxKind.InvocationExpression); ``` -------------------------------- ### Example Mapster Custom Configuration and Usage Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/requirements/2025-07-21-1454-mapster-config-support/06-requirements-spec.md Demonstrates a custom Mapster configuration that allows mapping between incompatible types, and how the analyzer should interpret this. ```csharp // Custom configuration makes this valid TypeAdapterConfig.NewConfig() .Map(dest => dest.Id, src => int.Parse(src.Id)); // But analyzer currently reports MAPSTER002 error var dto = person.Adapt(); // Should be valid due to custom config ``` -------------------------------- ### Install MapsterChecker Analyzer via Package Manager Console Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/README.md Use this command in the Package Manager Console within Visual Studio to install the MapsterChecker.Analyzer NuGet package. ```powershell Install-Package MapsterChecker.Analyzer ``` -------------------------------- ### Lifecycle Hooks - Before Mapping Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/requirements/2025-07-21-1454-mapster-config-support/03-context-findings.md Example of using the `.BeforeMapping()` hook in Mapster to execute logic before a mapping operation. ```csharp .BeforeMapping() ``` -------------------------------- ### Mapster Configuration Discovery Patterns Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/MAPSTER_ANALYZER_DEEP_DIVE.md These examples demonstrate how the Mapster configuration discovery system identifies custom mapping configurations. It recognizes both generic TypeAdapterConfig with fluent APIs and global settings configurations. ```csharp // Pattern 1: Generic TypeAdapterConfig with fluent API TypeAdapterConfig .NewConfig() .Map(dest => dest.Id, src => src.Id.ToString()) .Ignore(dest => dest.InternalId); ``` ```csharp // Pattern 2: GlobalSettings configuration TypeAdapterConfig.GlobalSettings .NewConfig() .Map(dest => dest.Name, src => src.FullName); ``` -------------------------------- ### MAPSTER002: Incompatible Type Mapping Example Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/README.md This C# code shows incompatible type mappings that will trigger a MAPSTER002 error. It includes examples of mapping an int to a DateTime and a string to a Guid. A safe compatible numeric type conversion is also provided. ```csharp // ❌ MAPSTER002: Error int number = 42; var dateTime = number.Adapt(); // Incompatible types // ❌ MAPSTER002: Error string text = "hello"; var guid = text.Adapt(); // Cannot convert arbitrary string to Guid // ✅ Safe: Compatible numeric types int number = 42; long longNumber = number.Adapt(); // Valid widening conversion ``` -------------------------------- ### Lifecycle Hooks - After Mapping Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/requirements/2025-07-21-1454-mapster-config-support/03-context-findings.md Example of using the `.AfterMapping()` hook in Mapster to execute logic after a mapping operation. ```csharp .AfterMapping() ``` -------------------------------- ### Sample Custom Mapster Configuration Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/requirements/2025-07-21-1454-mapster-config-support/03-context-findings.md Example of a custom Mapster configuration that maps a string Id to an int Id. This pattern is intended to be supported by the new analysis. ```csharp TypeAdapterConfig.NewConfig().Map(dest => dest.Id, src => int.Parse(src.Id)) ``` -------------------------------- ### MAPSTER001: Nullable to Non-Nullable Mapping Example Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/README.md This C# code demonstrates a nullable to non-nullable mapping that will trigger a MAPSTER001 warning. It highlights the potential for null reference exceptions if the source is null. A safe non-nullable to nullable mapping is also shown. ```csharp // ⚠️ MAPSTER001: Warning string? nullableString = GetNullableString(); var result = nullableString.Adapt(); // May throw if nullableString is null // ⚠️ MAPSTER001: Warning int? nullableInt = GetNullableInt(); var number = nullableInt.Adapt(); // May throw if nullableInt is null // ✅ Safe: Non-nullable to nullable string nonNullableString = "test"; var result = nonNullableString.Adapt(); // Safe conversion ``` -------------------------------- ### Conditional Mapping Pattern Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/requirements/2025-07-21-1454-mapster-config-support/03-context-findings.md Example of applying a condition to a property mapping in Mapster, ensuring the mapping only occurs if the condition is met. ```csharp .Map(dest => dest.Property, src => src.Property, srcCond => srcCond.Condition) ``` -------------------------------- ### Configure Diagnostic Severities Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Set the severity level for Mapster-related diagnostics in your .editorconfig file. This example disables MAPSTER003 and MAPSTER003P while keeping others at default levels. ```ini dotnet_diagnostic.MAPSTER003.severity = none dotnet_diagnostic.MAPSTER003P.severity = none dotnet_diagnostic.MAPSTER004.severity = warning dotnet_diagnostic.MAPSTER005.severity = error dotnet_diagnostic.MAPSTER006.severity = warning ``` -------------------------------- ### Write Analyzer Unit Tests for Mapster Adaptations Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Create unit tests for MapsterAdaptAnalyzer using CSharpAnalyzerTest. This example demonstrates testing for MAPSTER001 (NullableInt to NonNullableInt) and MAPSTER002 (IncompatibleTypes). Ensure to add Mapster assembly references. ```csharp using MapsterChecker.Analyzer; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Testing; using Microsoft.CodeAnalysis.Testing; public class MyAnalyzerTests { [Fact] public async Task NullableInt_To_NonNullableInt_ReportsMapster001() { const string code = @" using Mapster; public class C { public void M() { int? n = 42; var r = {|MAPSTER001:n.Adapt()|}; } }"; var test = new CSharpAnalyzerTest { TestCode = code, ReferenceAssemblies = ReferenceAssemblies.Net.Net80 }; test.TestState.AdditionalReferences.Add( MetadataReference.CreateFromFile(typeof(Mapster.TypeAdapter).Assembly.Location)); await test.RunAsync(); } [Fact] public async Task IncompatibleTypes_ReportsMapster002WithSpan() { const string code = @" using Mapster; public class C { public void M() { int n = 42; var r = {|MAPSTER002:n.Adapt()|}; } }"; await VerifyAsync(code, DiagnosticResult.CompilerError("MAPSTER002") .WithSpan(6, 17, 6, 40) .WithArguments("int", "System.DateTime", "Mapster cannot automatically convert integers to DateTime. " + "Consider using custom mapping...")); } private static async Task VerifyAsync(string source, params DiagnosticResult[] expected) { var test = new CSharpAnalyzerTest { TestCode = source, ReferenceAssemblies = ReferenceAssemblies.Net.Net80 }; test.TestState.AdditionalReferences.Add( MetadataReference.CreateFromFile(typeof(Mapster.TypeAdapter).Assembly.Location)); test.ExpectedDiagnostics.AddRange(expected); await test.RunAsync(); } } ``` -------------------------------- ### Remap Properties with .Map() in Mapster Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Use .Map() to explicitly define how source properties map to destination properties, including type conversions like Guid to string. Register configurations before using Adapt. ```csharp using Mapster; public class Person { public Guid Id { get; set; } public string? Name { get; set; } } public class PersonDto { public string Id { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; } // Register before any Adapt calls (e.g., in a static constructor or startup) TypeAdapterConfig .NewConfig() .Map(dest => dest.Id, src => src.Id.ToString()) // Guid → string .Map(dest => dest.Name, src => src.Name); // suppresses MAPSTER001 on Name var person = new Person { Id = Guid.NewGuid(), Name = "Alice" }; var dto = person.Adapt(); // no diagnostics — custom mapping registered Console.WriteLine(dto.Id); // "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" Console.WriteLine(dto.Name); // "Alice" ``` -------------------------------- ### Build and Run Sample Application Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/README.md Navigate to the sample application directory, build it to see analyzer warnings/errors, and then run the application. ```bash cd samples/SampleApp dotnet build # This will show analyzer warnings/errors dotnet run # Run the sample application ``` -------------------------------- ### Build MapsterChecker from Source Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Instructions for cloning the repository, restoring dependencies, building the project, running tests, and packing the analyzer NuGet package. Ensure you are in the project's root directory. ```bash git clone https://github.com/mapsterchecker/mapsterchecker.git cd mapsterchecker dotnet restore dotnet build --configuration Release dotnet test MapsterChecker.Tests/MapsterChecker.Tests.csproj --configuration Release --verbosity normal dotnet pack MapsterChecker.Analyzer/MapsterChecker.Analyzer.csproj --configuration Release --output ./nupkg ``` -------------------------------- ### Build and Test .NET Project Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/PUBLISHING.md Commands to clean, restore dependencies, run tests, and build the project in Release mode. Ensure all steps are completed successfully before publishing. ```bash # Navigate to the solution directory cd /Users/miloshegr/Documents/Playgound/MapsterChecker # Clean previous builds dotnet clean # Restore dependencies dotnet restore # Run all tests dotnet test # Build in Release mode dotnet build --configuration Release ``` -------------------------------- ### Clone and Build MapsterChecker Repository Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/README.md Clone the repository, navigate to the directory, restore dependencies, build the solution, run tests, and create a NuGet package. ```bash git clone https://github.com/mapsterchecker/mapsterchecker.git cd mapsterchecker dotnet restore dotnet build dotnet test dotnet pack --configuration Release ``` -------------------------------- ### Create and Push Symbol Packages Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/PUBLISHING.md Commands to create both the main package and a symbols package (including source) using 'dotnet pack', and then push both to their respective NuGet sources. ```bash # Create symbols package dotnet pack --configuration Release --include-symbols --include-source # Push both packages dotnet nuget push nupkgs/MapsterChecker.Analyzer.1.0.0.nupkg --source https://api.nuget.org/v3/index.json dotnet nuget push nupkgs/MapsterChecker.Analyzer.1.0.0.symbols.nupkg --source https://nuget.smbsrc.net/ ``` -------------------------------- ### Create NuGet Package Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/PUBLISHING.md Command to create a .nupkg file for the analyzer project. The package will be placed in the specified output directory. ```bash # Navigate to the analyzer project cd MapsterChecker.Analyzer # Create the package dotnet pack --configuration Release --output ../nupkgs ``` -------------------------------- ### Publish NuGet Package Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/PUBLISHING.md Command to push the created NuGet package to the specified source. Ensure you are in the solution directory and the package path is correct. ```bash # Navigate back to solution directory cd .. # Publish the package dotnet nuget push nupkgs/MapsterChecker.Analyzer.1.0.0.nupkg --source https://api.nuget.org/v3/index.json ``` -------------------------------- ### MapsterAdaptAnalyzer Initialization and Analysis Flow Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/MAPSTER_ANALYZER_DEEP_DIVE.md This code outlines the initialization and two-phase analysis process within the MapsterAdaptAnalyzer. It first collects all invocations, then discovers configurations, and finally analyzes Adapt calls using the populated registry. This approach ensures all configurations are found before analysis begins. ```csharp public override void Initialize(AnalysisContext context) { // Phase 1: Collect all invocations from all syntax trees var allInvocations = CollectAllInvocations(compilation); // Phase 2: Discovery - find all custom configurations foreach (var (invocation, semanticModel) in allInvocations) { discovery.DiscoverConfiguration(invocation, semanticModel); } // Phase 3: Analysis - analyze Adapt calls with populated registry foreach (var (invocation, semanticModel) in allInvocations) { if (!IsMapsterConfigurationCall(invocation)) AnalyzeInvocation(invocation, semanticModel, registry); } } ``` -------------------------------- ### Constructor Mapping Pattern Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/requirements/2025-07-21-1454-mapster-config-support/03-context-findings.md Shows how to map source properties to a destination object's constructor parameters using Mapster. ```csharp .MapWith(src => new Destination(src.Param)) ``` -------------------------------- ### Publish Pre-release NuGet Version Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/PUBLISHING.md Update the PackageVersion in the .csproj file with a pre-release tag (e.g., -alpha.1) and push the package using the dotnet nuget push command. ```xml 1.1.0-alpha.1 ``` ```bash dotnet nuget push nupkgs/MapsterChecker.Analyzer.1.1.0-alpha.1.nupkg --source https://api.nuget.org/v3/index.json ``` -------------------------------- ### Global Settings Configuration Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/requirements/2025-07-21-1454-mapster-config-support/03-context-findings.md Illustrates how to configure Mapster globally using `TypeAdapterConfig.GlobalSettings`. ```csharp TypeAdapterConfig.GlobalSettings.NewConfig<>() ``` -------------------------------- ### Configure PackageReference for Analyzer Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Recommended PackageReference configuration for including the analyzer without a runtime dependency. Ensure 'PrivateAssets' and 'IncludeAssets' are set correctly. ```xml all runtime; build; native; contentfiles; analyzers ``` -------------------------------- ### Register SyntaxNodeAction for Configuration Discovery Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/requirements/2025-07-21-1454-mapster-config-support/06-requirements-spec.md Extends the analyzer's initialization to register a syntax node action for discovering Mapster configurations. ```csharp RegisterSyntaxNodeAction(DiscoverConfiguration, SyntaxKind.InvocationExpression) ``` -------------------------------- ### Compatible Collection Mappings in C# Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Demonstrates compatible collection conversions where element types are the same or have common properties. No diagnostics are reported for these cases. ```csharp using Mapster; using System.Collections.Generic; // ✅ Compatible collection conversions (same element type) var list = new List { "a", "b" }; var arr = list.Adapt(); // List → string[] var hs = list.Adapt>(); // List → HashSet var iEnum = list.Adapt>(); // List → IEnumerable ``` ```csharp // ✅ Complex element types with common properties public record PersonSrc(int Id, string Name); public record PersonDst(string Id, string Name); var srcList = new List { new(1, "Alice") }; var dstList = srcList.Adapt>(); // no diagnostics ``` -------------------------------- ### GitHub Actions Workflow for NuGet Publishing Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/PUBLISHING.md A GitHub Actions workflow configuration to automate the .NET project build, test, pack, and push process to NuGet upon a release being published. ```yaml name: Publish to NuGet on: release: types: [published] jobs: publish: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup .NET uses: actions/setup-dotnet@v3 with: dotnet-version: '9.0.x' - name: Restore dependencies run: dotnet restore - name: Build run: dotnet build --configuration Release --no-restore - name: Test run: dotnet test --configuration Release --no-build - name: Pack run: dotnet pack --configuration Release --no-build --output nupkgs - name: Publish to NuGet run: dotnet nuget push nupkgs/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json ``` -------------------------------- ### Set NuGet API Key Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/PUBLISHING.md Command to set your NuGet API key for pushing packages. It's recommended to use environment variables for security. ```bash # Set your NuGet API key (replace with your actual key) dotnet nuget setapikey [YOUR-API-KEY] --source https://api.nuget.org/v3/index.json ``` ```bash # Set as environment variable export NUGET_API_KEY="your-api-key-here" # Use in command dotnet nuget setapikey $NUGET_API_KEY --source https://api.nuget.org/v3/index.json ``` -------------------------------- ### Bidirectional Configuration Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/requirements/2025-07-21-1454-mapster-config-support/03-context-findings.md Demonstrates how to configure Mapster for bidirectional mapping using the `.TwoWays()` option. ```csharp .TwoWays() ``` -------------------------------- ### Git Workflow for Contributions Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/README.md Standard Git commands for forking a repository, creating a feature branch, committing changes, pushing to the branch, and opening a Pull Request. ```bash git checkout -b feature/amazing-feature git commit -m 'Add amazing feature' git push origin feature/amazing-feature ``` -------------------------------- ### Tag and Push Git Release Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/PUBLISHING.md Create a Git tag for the published version and push it to the remote repository. ```bash git tag v1.0.0 git push origin v1.0.0 ``` -------------------------------- ### Basic Property Mapping Pattern Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/requirements/2025-07-21-1454-mapster-config-support/03-context-findings.md Demonstrates the fundamental Mapster pattern for mapping a property from a source object to a destination object. ```csharp .Map(dest => dest.Property, src => src.SourceProperty) ``` -------------------------------- ### Field Mapping Support in C# Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Demonstrates how Mapster and its analyzer recognize and map public instance fields, ignoring readonly, const, and static fields. ```csharp using Mapster; public class SourceWithFields { public string Name; // public field — mappable public int Age; // public field — mappable public readonly int Version = 1; // readonly — ignored by Mapster and analyzer public static string Kind = "human"; // static — ignored } public class DestWithProperties { public string Name { get; set; } = string.Empty; public int Age { get; set; } } var src = new SourceWithFields { Name = "Carol", Age = 28 }; var dest = src.Adapt(); // ✅ no diagnostics Console.WriteLine(dest.Name); // "Carol" Console.WriteLine(dest.Age); // 28 ``` -------------------------------- ### Assembly Scanning Configuration Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/requirements/2025-07-21-1454-mapster-config-support/03-context-findings.md Shows how to configure Mapster to scan a specific assembly for mapping configurations. ```csharp TypeAdapterConfig.GlobalSettings.Scan(assembly) ``` -------------------------------- ### Analyze Property Mapping with Cache and Circular Reference Checks Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/MAPSTER_ANALYZER_DEEP_DIVE.md This method orchestrates the property mapping analysis by first checking the cache, then detecting circular references, and finally performing the analysis. It caches results to avoid redundant computations. ```csharp public PropertyAnalysisResult AnalyzePropertyMapping(ITypeSymbol sourceType, ITypeSymbol destinationType) { // Step 1: Check cache if (_analysisCache.TryGetValue(cacheKey, out var cachedResult)) return cachedResult; // Step 2: Circular reference detection if (_currentAnalysisStack.Contains(cacheKey)) return CircularReferenceResult(); // Step 3: Perform analysis _currentAnalysisStack.Add(cacheKey); var result = PerformPropertyAnalysis(sourceType, destinationType, "", 0); _analysisCache[cacheKey] = result; _currentAnalysisStack.Remove(cacheKey); return result; } ``` -------------------------------- ### Property Mapping Analysis with Custom Expression Validation Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/requirements/2025-07-21-1454-mapster-config-support/06-requirements-spec.md Before applying default compatibility checks, verify if a custom property mapping exists. If so, validate the custom expression; otherwise, fall back to existing checks. ```csharp if (_configurationRegistry.HasPropertyMapping(sourceType, destType, propertyName)) { var customMapping = _configurationRegistry.GetPropertyMapping(sourceType, destType, propertyName); return ValidateCustomExpression(customMapping); // New validation logic } // Fall back to existing compatibility checks ``` -------------------------------- ### Expression Mapping Pattern Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/requirements/2025-07-21-1454-mapster-config-support/03-context-findings.md Illustrates how to use Mapster for mapping properties where a transformation or parsing is required, such as converting a string ID to an integer ID. ```csharp .Map(dest => dest.Id, src => int.Parse(src.Id)) ``` -------------------------------- ### Add MapsterChecker Analyzer via NuGet Package Manager Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/README.md Use this command to add the MapsterChecker.Analyzer NuGet package to your project using the .NET CLI. ```bash dotnet add package MapsterChecker.Analyzer ``` -------------------------------- ### Perform Compilation-Level Analysis with Mapster Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/MAPSTER_ANALYZER_DEEP_DIVE.md Analyzes the entire compilation to discover and validate Mapster configurations. It first collects all invocations, then performs discovery, and finally analyzes each invocation. ```csharp private void AnalyzeCompilation(CompilationAnalysisContext compilationContext) { var registry = new MappingConfigurationRegistry(); var discovery = new MapsterConfigurationDiscovery(registry); // Collect all invocations first var allInvocations = CollectAllInvocations(compilationContext.Compilation); // Discovery phase foreach (var (invocation, semanticModel) in allInvocations) discovery.DiscoverConfiguration(CreateContext(invocation, semanticModel)); // Analysis phase foreach (var (invocation, semanticModel) in allInvocations) if (!IsMapsterConfigurationCall(invocation, semanticModel)) AnalyzeInvocation(CreateContext(invocation, semanticModel), registry); } ``` -------------------------------- ### Mapster Extension Method Usage Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/README.md This C# code illustrates using Mapster's Adapt method as an extension method, requiring the 'Mapster' namespace to be imported. ```csharp using Mapster; var result = sourceObject.Adapt(); ``` -------------------------------- ### Discover Mapster Configuration Calls Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/MAPSTER_ANALYZER_DEEP_DIVE.md Identifies and extracts Mapster configuration calls from C# code using Roslyn syntax analysis. This method is the entry point for discovering mapping configurations. ```csharp public void DiscoverConfiguration(SyntaxNodeAnalysisContext context) { var invocation = (InvocationExpressionSyntax)context.Node; // Step 1: Check if this is a configuration call if (!IsMapsterConfigurationCall(invocation, semanticModel)) return; // Step 2: Extract type information (source/destination types) var configInfo = ExtractConfigurationInfo(invocation, semanticModel); // Step 3: Process the entire method chain ProcessConfigurationChain(invocation, configInfo, semanticModel); } ``` -------------------------------- ### Combine Property Paths for Nested Objects Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/MAPSTER_ANALYZER_DEEP_DIVE.md Constructs a property path string by combining a base path with a property name. Handles cases where the base path is empty. ```csharp // Example: "Address.Street" for person.Address.Street private string CombinePropertyPath(string basePath, string propertyName) { return string.IsNullOrEmpty(basePath) ? propertyName : $"{basePath}.{propertyName}"; } ``` -------------------------------- ### Incompatible Collection Mappings in C# Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Illustrates incompatible collection conversions, including element type mismatches and collection-to-scalar mappings, which trigger MAPSTER002 errors. ```csharp // ❌ MAPSTER002 — incompatible element types var strList = new List { "2024-01-01" }; var badList = strList.Adapt>(); // string → DateTime incompatible ``` ```csharp // ❌ MAPSTER002 — collection ↔ scalar int scalar = 42; var badArr = scalar.Adapt(); // MAPSTER002 ``` -------------------------------- ### Mapster Non-Generic Adapt Method Usage Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/README.md This C# snippet demonstrates using the non-generic Adapt method in Mapster, where a destination object is first created and then populated from the source. ```csharp var destination = new DestinationType(); source.Adapt(destination); ``` -------------------------------- ### Property Mapping Analyzer Cache and Stack Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/MAPSTER_ANALYZER_DEEP_DIVE.md Defines the structure for the PropertyMappingAnalyzer, including a cache for analysis results and a stack to prevent circular references during analysis. Max recursion depth is set to 5. ```csharp public class PropertyMappingAnalyzer { private readonly Dictionary _analysisCache = new(); private readonly HashSet _currentAnalysisStack = new(); private const int MaxRecursionDepth = 5; } ``` -------------------------------- ### Custom mapping expression may throw exception (MAPSTER004) Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Reports a warning when a custom mapping lambda calls a method known to throw, like `int.Parse`. Use `TryParse` for safer conversions. ```csharp using Mapster; public class OrderSource { public string Quantity { get; set; } = "10"; } public class OrderDest { public int Quantity { get; set; } } // ⚠️ MAPSTER004: Custom mapping expression for property 'Quantity' // contains method call 'Parse' that may throw exceptions TypeAdapterConfig .NewConfig() .Map(dest => dest.Quantity, src => int.Parse(src.Quantity)); // risky // ✅ Use TryParse to avoid potential exceptions TypeAdapterConfig .NewConfig() .Map(dest => dest.Quantity, src => int.TryParse(src.Quantity, out var q) ? q : 0); ``` -------------------------------- ### Update Package Version in .csproj Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/PUBLISHING.md Increment the PackageVersion in the .csproj file to reflect changes. Use semantic versioning guidelines (patch, minor, major) for updates. ```xml 1.0.1 ``` -------------------------------- ### Reference MapsterChecker Analyzer via PackageReference Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/README.md Include this XML snippet in your project file to reference the MapsterChecker.Analyzer NuGet package. ```xml all runtime; build; native; contentfiles; analyzers ``` -------------------------------- ### Missing property mapping (MAPSTER003P) Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Reports an info diagnostic when a destination property has no corresponding source property. These properties will receive their default value. ```csharp using Mapster; public class Source { public string Name { get; set; } = string.Empty; } public class Dest { public string Name { get; set; } = string.Empty; public int Score { get; set; } } // no source counterpart // ℹ️ MAPSTER003P: Property 'Score' in destination type has no corresponding // property in source type var dest = new Source { Name = "Eve" }.Adapt(); // dest.Score == 0 (default) ``` -------------------------------- ### Register MapsterAdaptAnalyzer with Roslyn Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/MAPSTER_ANALYZER_DEEP_DIVE.md Registers the MapsterAdaptAnalyzer as a DiagnosticAnalyzer for C# code. Configures generated code analysis and enables concurrent execution. ```csharp [DiagnosticAnalyzer(LanguageNames.CSharp)] public class MapsterAdaptAnalyzer : DiagnosticAnalyzer { public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(/* all diagnostic descriptors */); public override void Initialize(AnalysisContext context) { context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.EnableConcurrentExecution(); context.RegisterCompilationAction(AnalyzeCompilation); } } ``` -------------------------------- ### Mapster Generic Adapt Method Usage Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/README.md This C# snippet shows the basic usage of the generic Adapt method from Mapster to convert a source object to a destination type. ```csharp var destination = source.Adapt(); ``` -------------------------------- ### Ignore Mapping Pattern Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/requirements/2025-07-21-1454-mapster-config-support/03-context-findings.md Demonstrates how to exclude specific properties from being mapped by Mapster. ```csharp .Ignore(dest => dest.PropertyToIgnore) ``` -------------------------------- ### Check Type Compatibility in Mapster Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/MAPSTER_ANALYZER_DEEP_DIVE.md Performs type compatibility analysis between source and destination types, considering custom mappings, direct type compatibility, and property-level analysis. ```csharp public TypeCompatibilityResult CheckCompatibility(ITypeSymbol sourceType, ITypeSymbol destinationType) { // Step 1: Check for custom type-level mapping if (registry?.HasCustomMapping(sourceType, destinationType) == true) return TypeCompatibilityResult.Compatible(); // Step 2: Direct type compatibility var directResult = CheckDirectTypeCompatibility(sourceType, destinationType); // Step 3: Property-level analysis for complex types var propertyResult = propertyAnalyzer.AnalyzePropertyMapping(sourceType, destinationType); return CombineResults(directResult, propertyResult); } ``` -------------------------------- ### Perform Recursive Property Analysis Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/MAPSTER_ANALYZER_DEEP_DIVE.md This method iterates through destination properties, finds matching source properties, and applies custom mapping rules or standard compatibility checks. It recursively analyzes nested complex types. ```csharp private PropertyAnalysisResult PerformPropertyAnalysis(ITypeSymbol sourceType, ITypeSymbol destinationType, string propertyPath, int currentDepth) { var issues = new List(); // Get mappable properties from both types var sourceProperties = GetMappableProperties(sourceType); var destinationProperties = GetMappableProperties(destinationType); foreach (var destProp in destinationProperties) { var sourceProp = FindMatchingProperty(sourceProperties, destProp); // Check for custom property mapping first if (HasCustomPropertyMapping(destProp.Name)) { ValidateCustomMapping(destProp, sourceProp); continue; // Skip default validation } // Perform standard compatibility checks if (sourceProp == null) issues.Add(CreateMissingPropertyIssue(destProp)); else issues.AddRange(CheckPropertyCompatibility(sourceProp, destProp)); // Recursive analysis for complex types if (IsComplexType(sourceProp?.Type) && IsComplexType(destProp.Type)) issues.AddRange(AnalyzeNestedProperties(sourceProp.Type, destProp.Type)); } return new PropertyAnalysisResult { Issues = issues.ToImmutableArray() }; } ``` -------------------------------- ### MAPSTER001: Nullable to Non-Nullable Top-Level Mapping Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Reports a warning when mapping from a nullable source type to a non-nullable destination type. Use the null-forgiving operator (!) to suppress warnings, but note that errors will still be raised. ```csharp using Mapster; string? nullableString = GetNullableValue(); // ⚠️ MAPSTER001: Mapping from nullable type 'string?' to non-nullable type 'string' // may result in null reference exceptions var result = nullableString.Adapt(); int? nullableInt = GetNullableInt(); // ⚠️ MAPSTER001 var number = nullableInt.Adapt(); // ✅ Safe — widening nullability string nonNull = "hello"; var safe = nonNull.Adapt(); // ✅ Suppress with null-forgiving operator (warnings only; errors are still raised) var forced = nullableString.Adapt()!; ``` -------------------------------- ### Configure Rule Severity via EditorConfig Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/README.md This INI configuration shows how to set the severity for MapsterChecker diagnostic rules (MAPSTER001, MAPSTER002, MAPSTER003) in an .editorconfig file. ```ini [*.cs] # Set MAPSTER001 to error instead of warning dotnet_diagnostic.MAPSTER001.severity = error # Disable MAPSTER002 completely dotnet_diagnostic.MAPSTER002.severity = none # Set MAPSTER003 to suggestion dotnet_diagnostic.MAPSTER003.severity = suggestion ``` -------------------------------- ### Property-level incompatible type mapping (MAPSTER002P) Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Reports an error when a property maps to a fundamentally incompatible type. Ensure source and destination property types are compatible or use custom mapping. ```csharp using Mapster; public class NodeA { public int Value { get; set; } public NodeA? Next { get; set; } } public class NodeB { public DateTime Value { get; set; } public NodeB? Next { get; set; } } var node = new NodeA { Value = 42 }; // ❌ MAPSTER002P: Property 'Value' — int → DateTime incompatible // ❌ MAPSTER002P: Property 'Next.Value' — int → DateTime incompatible // ❌ MAPSTER002P: Property 'Next.Next.Value' — ... (recursion up to depth 5) var bad = node.Adapt(); public class ClassA { public string Id { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; } public class ClassB { public string Id { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; } // ✅ No diagnostics — compatible property types var ok = new ClassA { Id = "1", Name = "Alice" }.Adapt(); ``` -------------------------------- ### Post-Mapping Logic with .AfterMapping() in Mapster Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Implement custom logic after a mapping operation completes using .AfterMapping(). This is useful for handling property mismatches or performing final adjustments, and it suppresses related analyzer warnings. ```csharp using Mapster; public class SourceObj { public int Id { get; set; } public string[] Tags { get; set; } = Array.Empty(); } public class DestObj { public int Id { get; set; } public string Tags { get; set; } = string.Empty; } // Without AfterMapping, the string[] → string property mismatch triggers MAPSTER002P. // With AfterMapping registered, the analyzer trusts you to handle it. TypeAdapterConfig .NewConfig() .AfterMapping((src, dest) => { dest.Tags = string.Join(", ", src.Tags); }); var source = new SourceObj { Id = 1, Tags = new[] { "csharp", "roslyn" } }; var dest = source.Adapt(); // no MAPSTER002P — AfterMapping registered Console.WriteLine(dest.Tags); // "csharp, roslyn" ``` -------------------------------- ### Nullable Field to Non-Nullable Field Mapping in C# Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Highlights a nullable field being mapped to a non-nullable field, triggering a MAPSTER001P warning. ```csharp // ⚠️ MAPSTER001P — nullable field → non-nullable field public class SrcNullable { public string? Name; public int Age; } public class DstNonNull { public string Name; public int Age; } var s2 = new SrcNullable { Name = null, Age = 25 }; var d2 = s2.Adapt(); // ⚠️ MAPSTER001P on 'Name' ``` -------------------------------- ### Process Chained Mapster Configuration Calls Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/MAPSTER_ANALYZER_DEEP_DIVE.md Processes entire fluent API chains of Mapster configuration calls within a single statement. It iterates through all invocations to ensure complete configuration analysis. ```csharp private void ProcessConfigurationChain(InvocationExpressionSyntax initialCall, TypeConfigurationInfo configInfo, SemanticModel semanticModel) { // Find the complete statement containing all chained calls var statement = initialCall.FirstAncestorOrSelf(); // Process all invocations in the statement var invocations = statement.DescendantNodes().OfType(); foreach (var invocation in invocations) { ProcessSingleConfigurationCall(invocation, configInfo, semanticModel); } } ``` -------------------------------- ### Type Compatibility Check with Custom Mapping Override Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/requirements/2025-07-21-1454-mapster-config-support/06-requirements-spec.md Check for custom mappings before applying default incompatibility rules. If a custom mapping exists, skip default checks but still validate nullability and custom expression safety. ```csharp if (_configurationRegistry.HasCustomMapping(sourceType, destinationType)) { // Skip default incompatibility checks, but still check nullability // Validate custom mapping expressions instead } ``` -------------------------------- ### Report Mapster Diagnostics Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/MAPSTER_ANALYZER_DEEP_DIVE.md This method reports various diagnostic issues identified during the analysis, including nullability conflicts and property-level incompatibilities. It uses specific descriptors for each diagnostic category. ```csharp private static void ReportDiagnostics(SyntaxNodeAnalysisContext context, InvocationExpressionSyntax invocation, TypeCompatibilityResult compatibilityResult, AdaptCallInfo adaptCallInfo) { // Top-level nullability issues if (compatibilityResult.HasNullabilityIssue) { var diagnostic = Diagnostic.Create( DiagnosticDescriptors.NullableToNonNullableMapping, adaptCallInfo.Location, adaptCallInfo.SourceType.ToDisplayString(), adaptCallInfo.DestinationType.ToDisplayString()); context.ReportDiagnostic(diagnostic); } // Property-level issues foreach (var propertyIssue in compatibilityResult.PropertyIssues) { var descriptor = GetDiagnosticDescriptorForPropertyIssue(propertyIssue.IssueType); var diagnostic = Diagnostic.Create(descriptor, adaptCallInfo.Location, propertyIssue.PropertyPath, propertyIssue.SourceType, propertyIssue.DestinationType); context.ReportDiagnostic(diagnostic); } } ``` -------------------------------- ### Mapster MappingConfigurationRegistry Data Structures Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/MAPSTER_ANALYZER_DEEP_DIVE.md Defines the data structures used by MappingConfigurationRegistry for storing discovered custom mapping configurations. It supports both type-level and property-level mappings. ```csharp public class MappingConfigurationRegistry { // Type-level mappings: "SourceType→DestinationType" -> Set private readonly Dictionary> _typeMappings; // Property-level mappings: "SourceType→DestinationType" -> PropertyName -> CustomMappingInfo private readonly Dictionary> _propertyMappings; } ``` -------------------------------- ### Recursive Type Safety in C# Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Demonstrates Mapster's ability to handle self-referencing, mutually recursive, and deeply nested types without causing stack overflows. ```csharp using Mapster; using System.Collections.Generic; // ✅ Self-referencing types — no stack overflow public record BinaryTree(string Value, BinaryTree? Left, BinaryTree? Right); public record BinaryTreeDto(string Value, BinaryTreeDto? Left, BinaryTreeDto? Right); var tree = new BinaryTree("root", new BinaryTree("left", null, null), new BinaryTree("right", null, null)); var dto = tree.Adapt(); // no diagnostics, no StackOverflowException ``` ```csharp // ✅ Mutually recursive — no stack overflow public class NodeA { public string Name { get; set; } public NodeB? Child { get; set; } } public class NodeB { public string Name { get; set; } public NodeA? Child { get; set; } } public class NodeADto { public string Name { get; set; } public NodeBDto? Child { get; set; } } public class NodeBDto { public string Name { get; set; } public NodeADto? Child { get; set; } } var nodeA = new NodeA { Name = "a", Child = new NodeB { Name = "b" } }; var nodeADto = nodeA.Adapt(); // no diagnostics ``` ```csharp // ✅ Self-referencing list public class Category { public string Name { get; set; } public List Sub { get; set; } = new(); } public class CategoryDto { public string Name { get; set; } public List Sub { get; set; } = new(); } var cat = new Category { Name = "root" }; var catDto = cat.Adapt(); // no diagnostics ``` -------------------------------- ### Mapster CustomMappingInfo Class Source: https://github.com/gwynbleid85/mapsterchecker/blob/master/MAPSTER_ANALYZER_DEEP_DIVE.md Represents detailed information about a custom mapping, including its type, associated properties, expressions, and semantic model data for analysis. ```csharp public class CustomMappingInfo { public CustomMappingType MappingType { get; set; } // Map, Ignore, MapWith, etc. public string? PropertyName { get; set; } // For property-level mappings public ExpressionSyntax? MappingExpression { get; set; } // The mapping expression public ExpressionSyntax? DestinationExpression { get; set; } // dest => dest.Property public ExpressionSyntax? SourceExpression { get; set; } // src => src.Value public SemanticModel? SemanticModel { get; set; } // For expression analysis public Location? Location { get; set; } // For diagnostic reporting } ``` -------------------------------- ### Custom mapping return type incompatible (MAPSTER005) Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Reports an error when a custom mapping lambda returns a type incompatible with the destination property. Ensure the lambda's return type matches the property type. ```csharp using Mapster; public class Src { public string CreatedAt { get; set; } = "2024-01-01"; } public class Dst { public int CreatedAt { get; set; } } // ❌ MAPSTER005: Custom mapping expression for property 'CreatedAt' // returns type 'string' which is incompatible with destination type 'int' TypeAdapterConfig .NewConfig() .Map(dest => dest.CreatedAt, src => src.CreatedAt); // string returned, int expected // ✅ Correct return type TypeAdapterConfig .NewConfig() .Map(dest => dest.CreatedAt, src => int.TryParse(src.CreatedAt, out var v) ? v : 0); ``` -------------------------------- ### MAPSTER001P: Property-Level Nullable to Non-Nullable Mapping Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Reports a warning when a property in the source object is nullable, but the corresponding property in the destination object is non-nullable. Suppress all property-level nullability warnings using the null-forgiving operator on the Adapt call. ```csharp #nullable enable using Mapster; public class Person { public string? Name { get; set; } public int? Age { get; set; } public DateTime? BirthDate { get; set; } } public class PersonDto { public string Name { get; set; } = string.Empty; // non-nullable public int Age { get; set; } // non-nullable public DateTime BirthDate { get; set; } // non-nullable } var person = new Person { Name = "Alice", Age = 30 }; // ⚠️ MAPSTER001P on properties: Name, Age, BirthDate var dto = person.Adapt(); // ✅ Suppress all property-level nullability warnings var dtoSafe = person.Adapt()!; ``` -------------------------------- ### Custom mapping expression may produce null value (MAPSTER006) Source: https://context7.com/gwynbleid85/mapsterchecker/llms.txt Reports a warning when a custom mapping expression might yield null for a non-nullable destination property. Provide a fallback value to prevent this. ```csharp using Mapster; public class UserSrc { public string? MiddleName { get; set; } } public class UserDst { public string MiddleName { get; set; } = string.Empty; } // ⚠️ MAPSTER006: Custom mapping expression for property 'MiddleName' // may produce null value for non-nullable destination type 'string' TypeAdapterConfig .NewConfig() .Map(dest => dest.MiddleName, src => src.MiddleName); // may be null // ✅ Provide a fallback TypeAdapterConfig .NewConfig() .Map(dest => dest.MiddleName, src => src.MiddleName ?? string.Empty); ```