feat(mappers): add nested object mapping support with reusable helper methods#72
Merged
ncipollina merged 18 commits intomainfrom Feb 18, 2026
Merged
feat(mappers): add nested object mapping support with reusable helper methods#72ncipollina merged 18 commits intomainfrom
ncipollina merged 18 commits intomainfrom
Conversation
Introduced `HelperMethodEmitter` for generating reusable helper methods for nested object mappings: - `ToItem` and `FromItem` helper methods are now extracted into separate methods. - Updated `HelperMethodRegistry` to manage these reusable methods. - Enhanced `MapperClassInfo` to include helper methods for better organization. Updated test snapshots to reflect these changes.
…pacity - Updated `FormatToItemChainedCalls` to preallocate dictionary capacity based on `.Set*` method calls. - Introduced `CountSetMethodCalls` to calculate the number of `.Set*` calls for capacity estimation. - Adjusted generated `ToItem` methods in test snapshots to use preallocated dictionary capacity.
- Introduced `NestedObject_MultipleLevels` test to verify mappings for deeply nested objects. - Added sample classes (`Level1` to `Level4`) to test `ToItem` and `FromItem` methods. - Updated test assertions to validate mappings across multiple levels.
…d mappings - Extended `HelperMethodRegistry` to manage registration of reusable helper methods. - Refactored `RenderInlineNestedToItem` and `RenderInlineNestedFromItem` to utilize the helper registry. - Enhanced support for iterative rendering of helper methods in `MapperEmitter`. - Updated snapshots to align with new helper methods for deeply nested mapping scenarios.
… address mappings - Refactored `ToItem_Customer` and `FromItem_Customer` to delegate address mappings to new helper methods. - Added `ToItem_Address` and `FromItem_Address` for better modularity and reuse. - Updated dictionary initialization to reflect more accurate capacity.
…mbers - Replaced block-bodied methods with arrow syntax for cleaner code. - Updated snapshots to align with the new method formatting. - Removed unnecessary braces and adjusted formatting accordingly.
…edness support - Integrated `PropertyAnalyzer` for detailed property analysis in `NestedObjectTypeAnalyzer`. - Added support to track nullability, requiredness, getters, setters, and default values. - Enhanced handling of requiredness in nested object mappings with fallback management. - Updated `NestedPropertySpec` to include new analysis properties. - Refactored code rendering logic to leverage enhanced property analysis. - Added a test case to validate correct requiredness handling for nested properties. - Updated test snapshots to reflect changes in generated mapping code.
…ction assignments - Updated nested object mappings to separate properties into initialization vs post-construction setup. - Enhanced handling of `Requiredness.InferFromNullability` for dynamic property assignment. - Refactored `RenderInlineNestedFromItem` to support conditional property assignments post-construction. - Adjusted helper method generation to align with new assignment logic. - Updated test snapshots to reflect changes in requiredness handling and assignment patterns.
ncipollina
requested changes
Feb 17, 2026
Contributor
ncipollina
left a comment
There was a problem hiding this comment.
Feedback from Claude:
High Priority
- Incremental pipeline equality broken — MapperInfo stores mutable GeneratorContext and HelperMethodRegistry in a record used by the incremental pipeline. Since these are reference types without value equality, the generator will re-execute on every keystroke, defeating caching. This is the most architecturally significant concern.
- Unbounded while(true) loop in MapperEmitter.Generate (line 55-81) — If a bug causes helper methods to register under different names, this becomes an infinite loop inside the compiler/IDE. Add a maxIterations safety bound.
Medium Priority
- Missing brace depth tracking — HelperMethodEmitter.SplitPropertiesRespectingNesting tracks () and <> depth but ignores {}. Any future code producing commas inside braces will silently corrupt output.
- .Set over-counting — CountSetMethodCalls counts every .Set substring including those inside arguments (e.g., source.Settings), inflating dictionary capacity in generated code.
- Unconditional null-checks for non-nullable types — RenderInlineNestedToItem always emits is null ? checks even for struct/required properties, generating dead code and potential compiler warnings.
- Duplicated type-name sanitization — Three near-identical implementations of type-name extraction across HelperMethodEmitter, HelperMethodRegistry, and PropertyMappingCodeRenderer.
Low Priority
- Re-parsing own output — Rendering a single-line string then re-parsing it character by character to format it. Follow-up refactor candidate.
- Minor style inconsistencies — Mix of string.Empty vs "" patterns.
Recommended Follow-ups (quick wins)
- Add {/} to SplitPropertiesRespectingNesting depth tracking
- Add maxIterations guard to the helper rendering loop
- Consolidate type-name extraction into a shared utility
- Conditionally emit null-checks based on Nullability.IsNullableType
Refactor RFC: Extract transient state from MapperInfo
The GeneratorContext and HelperMethodRegistry should be passed separately to MapperEmitter.Generate() rather than stored in the pipeline record, to restore proper incremental caching behavior. Estimated ~2-3 hours, low risk, internal-only change.
…entations - Added `Equals` and `GetHashCode` methods to `MapperInfo` for enhanced comparison logic. - Made `MapperInfo` non-sealed to allow inheritance.
- Introduced `DM0009` diagnostic to detect and report limit exceedance during helper method rendering. - Updated `MapperEmitter` to apply a safety bound of 1,000 iterations for helper rendering loops. - Modified the rendering logic to report `DM0009` when the iteration limit is reached. - Enhanced `DiagnosticDescriptors` with a descriptor for `HelperRenderingLimitExceeded`.
- Updated `HelperMethodEmitter` to account for `{` and `}` in depth calculations.
- Prevented potential mismatches in helper method generation involving block delimiters.
- Added `FindNextSetMethodCall` to streamline `.Set*` method call detection. - Replaced direct `.Set` index searches with the new utility method for consistency. - Enhanced support for generic type and nested method parsing in `.Set*` calls.
…ion logic - Introduced `TypeNameHelper` utility to extract and sanitize type names from fully qualified strings. - Replaced redundant extraction logic in `HelperMethodEmitter` and `PropertyMappingCodeRenderer`. - Unified `GenerateToItemHelperName` and `GenerateFromItemHelperName` methods into `GenerateHelperName`. - Improved maintainability by removing duplicate code for type sanitization. - Updated relevant method calls to leverage the new `TypeNameHelper` utility.
- Improved dictionary initialization with capacity pre-allocation in `HelperMethodEmitter`. - Simplified and modularized property mapping rendering logic with reusable helper methods. - Introduced `RenderToItemPropertyCall` and `RenderPropertyInitAssignment` as reusable utilities. - Removed redundant formatting methods (`FormatToItemChainedCalls` and `FormatFromItemObjectInitializer`). - Enhanced handling of nested and scalar property mappings with streamlined syntax.
Collaborator
Author
Resolved 1, 2, 3, 4, 6, and 7. I did not like the others (at least for now). |
…entation - Changed `MapperInfo` to a sealed record to prevent inheritance. - Removed `virtual` keyword from the `Equals` method for consistency. - Updated equality logic to streamline comparison operations.
…into feature/format-nested-mappings
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🚀 Pull Request
📋 Summary
This PR introduces comprehensive support for mapping nested objects in DynamoMapper, enabling efficient serialization and deserialization of complex object graphs. The implementation uses reusable helper methods to handle nested type mappings, reducing code duplication and improving maintainability.
Key Features
HelperMethodRegistryandHelperMethodInfotypes manage reusable helper methods for nested object mappingsPropertyAnalyzerto track nullability, requiredness, getters, setters, and default values for nested propertiesTechnical Implementation
ToItem_*andFromItem_*helper methods for nested typesExample Generated Code
For a mapper with nested
Addressobjects, the generator now creates:✅ Checklist
🧪 Related Issues or PRs
This PR builds foundational support for nested object mapping, which will be essential for Phase 2 of the DynamoMapper roadmap (collections and complex types).
💬 Notes for Reviewers
Files to Review
HelperMethodRegistry.cs,HelperMethodInfo.cs,HelperMethodEmitter.csNestedObjectTypeAnalyzer.cs(enhanced withPropertyAnalyzerintegration)PropertyMappingCodeRenderer.cs(refactored for helper method support)NestedObjectVerifyTests.cs(multi-level nesting, requiredness tests)Design Decisions
Known Limitations