Consolidate parameter extraction - Remove IParameterTypeExtractor#1136
Conversation
…ic API - Delete ParameterExtractor.cs (reflection compatibility shim) - Update IdentifierCorrectnessTests to use ParameterShared directly - Rewrite ParameterExtractorPrivateCoverageTests to test through public ParameterShared and ParameterAggregator APIs instead of reflection
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThis PR refactors parameter extraction logic by removing the ChangesParameter Extraction Architecture Refactoring
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
src/Refitter.Core/ParameterAggregator.cs (1)
33-36: ⚖️ Poor tradeoffMutable state on shared extractor instance may cause issues under concurrent use.
GetExtractor<QueryParameterExtractor>()returns the same instance from the sharedextractorslist. SettingDynamicQuerystringParameterTypeon this shared instance before callingExtract()means concurrent calls toExtractParameterson the sameParameterAggregatorcould race, causing one call's type name to be overwritten by another.If
ParameterAggregatoris always instantiated per-operation or the codebase is single-threaded, this is not an immediate problem. However, the pattern couples extraction correctness to external synchronization guarantees.🔧 Alternative: instantiate a fresh QueryParameterExtractor per call
// Query parameters (with dynamic querystring support) - var queryExtractor = GetExtractor<QueryParameterExtractor>(); + var queryExtractor = new QueryParameterExtractor(); queryExtractor.DynamicQuerystringParameterType = dynamicQuerystringParameterType; allParameters.AddRange(queryExtractor.Extract(operationModel, operation, settings)); dynamicQuerystringParameters = queryExtractor.DynamicQuerystringCode;This would make
QueryParameterExtractorno longer need to be inGetDefaultExtractors(), simplifying the design.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/Refitter.Core/ParameterAggregator.cs` around lines 33 - 36, The shared QueryParameterExtractor instance is mutated via its DynamicQuerystringParameterType before calling Extract(), which can race when ExtractParameters is called concurrently; fix by creating a fresh extractor per call instead of using GetExtractor<QueryParameterExtractor>() — e.g. replace the GetExtractor<QueryParameterExtractor>() call with new QueryParameterExtractor(), set its DynamicQuerystringParameterType, call Extract(operationModel, operation, settings) and read DynamicQuerystringCode from that instance; also remove QueryParameterExtractor from GetDefaultExtractors() (or keep it but note it’s no longer used) so the extractor is not treated as shared mutable state.src/Refitter.Core/QueryParameterExtractor.cs (1)
20-23: 💤 Low valueConsider guarding against null
DynamicQuerystringParameterTypebefore entering dynamic extraction.When
settings.UseDynamicQuerystringParametersis true and there are 2+ query parameters,ExtractDynamicis called. Line 32 usesDynamicQuerystringParameterType!with a null-forgiving operator, but the property is nullable and the branch condition doesn't verify it's set.Currently
ParameterAggregatoralways sets this property before callingExtract(), so production usage is safe. However, ifQueryParameterExtractoris instantiated and used directly (e.g., in tests) without settingDynamicQuerystringParameterType, this could pass a null toDynamicQuerystringParameterBuilder.Build().🛡️ Optional: Add a guard clause
if (settings.UseDynamicQuerystringParameters && queryParameters.Count >= 2) + { + if (string.IsNullOrWhiteSpace(DynamicQuerystringParameterType)) + throw new InvalidOperationException($"{nameof(DynamicQuerystringParameterType)} must be set before extracting dynamic querystring parameters."); return ExtractDynamic(queryParameters, settings); + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/Refitter.Core/QueryParameterExtractor.cs` around lines 20 - 23, The code calls ExtractDynamic when settings.UseDynamicQuerystringParameters is true but does not verify settings.DynamicQuerystringParameterType is non-null; update QueryParameterExtractor so either the initial branch checks that settings.DynamicQuerystringParameterType != null before calling ExtractDynamic (falling back to ExtractSimple or throwing a clear ArgumentException), or add a null-check at the start of ExtractDynamic that throws an ArgumentException/InvalidOperationException with a descriptive message; reference the nullable property Settings.DynamicQuerystringParameterType, the method QueryParameterExtractor.ExtractDynamic, and the public entry QueryParameterExtractor.Extract so callers (including tests) get a clear failure rather than passing null into DynamicQuerystringParameterBuilder.Build().src/Refitter.Tests/Parameters/ParameterExtractorPrivateCoverageTests.cs (1)
261-275: ⚡ Quick winStrengthen these delegation tests with behavior-level assertions.
Both tests can pass even if sanitization/reordering regresses (
NotBeNullOrWhiteSpace/NotBeNullare too permissive). Please assert concrete invariants so failures are diagnostic.Suggested test hardening
public void ReplaceUnsafeCharacters_Delegates_To_ParameterShared() { var result = ParameterShared.ReplaceUnsafeCharacters("unsafe-name!"); - result.Should().NotBeNullOrWhiteSpace(); + result.Should().NotBeNullOrWhiteSpace(); + result.Should().NotContain("-"); + result.Should().NotContain("!"); + result.Should().NotBe("unsafe-name!"); } [Test] public void ReOrderNullableParameters_Delegates_To_OptionalParameterReorderer() { var parameterModels = new List<CSharpParameterModel>(); var result = OptionalParameterReorderer.Reorder( new List<string> { "string a", "int? b = default" }, new RefitGeneratorSettings(), - parameterModels); + parameterModels).ToList(); - result.Should().NotBeNull(); + result.Should().ContainInOrder("string a", "int? b = default"); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/Refitter.Tests/Parameters/ParameterExtractorPrivateCoverageTests.cs` around lines 261 - 275, Replace the weak assertions with behavior-level checks: for ParameterShared.ReplaceUnsafeCharacters assert the returned string is not null/whitespace AND matches a safe-character pattern (e.g. Regex.IsMatch(result, "^[A-Za-z0-9_\\-]+$")) and specifically does not contain the original unsafe char(s) (e.g. Assert.False(result.Contains("!"))), and for OptionalParameterReorderer.Reorder assert the returned sequence orders nullable/optional params after non-optional ones (e.g. the "int? b = default" entry appears at the end) and that the passed-in parameterModels is updated/consistent with the returned list (e.g. count and mapped names/types match expected), using ParameterShared.ReplaceUnsafeCharacters and OptionalParameterReorderer.Reorder as the referenced symbols to locate the tests to change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/Refitter.Core/ParameterAggregator.cs`:
- Around line 33-36: The shared QueryParameterExtractor instance is mutated via
its DynamicQuerystringParameterType before calling Extract(), which can race
when ExtractParameters is called concurrently; fix by creating a fresh extractor
per call instead of using GetExtractor<QueryParameterExtractor>() — e.g. replace
the GetExtractor<QueryParameterExtractor>() call with new
QueryParameterExtractor(), set its DynamicQuerystringParameterType, call
Extract(operationModel, operation, settings) and read DynamicQuerystringCode
from that instance; also remove QueryParameterExtractor from
GetDefaultExtractors() (or keep it but note it’s no longer used) so the
extractor is not treated as shared mutable state.
In `@src/Refitter.Core/QueryParameterExtractor.cs`:
- Around line 20-23: The code calls ExtractDynamic when
settings.UseDynamicQuerystringParameters is true but does not verify
settings.DynamicQuerystringParameterType is non-null; update
QueryParameterExtractor so either the initial branch checks that
settings.DynamicQuerystringParameterType != null before calling ExtractDynamic
(falling back to ExtractSimple or throwing a clear ArgumentException), or add a
null-check at the start of ExtractDynamic that throws an
ArgumentException/InvalidOperationException with a descriptive message;
reference the nullable property Settings.DynamicQuerystringParameterType, the
method QueryParameterExtractor.ExtractDynamic, and the public entry
QueryParameterExtractor.Extract so callers (including tests) get a clear failure
rather than passing null into DynamicQuerystringParameterBuilder.Build().
In `@src/Refitter.Tests/Parameters/ParameterExtractorPrivateCoverageTests.cs`:
- Around line 261-275: Replace the weak assertions with behavior-level checks:
for ParameterShared.ReplaceUnsafeCharacters assert the returned string is not
null/whitespace AND matches a safe-character pattern (e.g. Regex.IsMatch(result,
"^[A-Za-z0-9_\\-]+$")) and specifically does not contain the original unsafe
char(s) (e.g. Assert.False(result.Contains("!"))), and for
OptionalParameterReorderer.Reorder assert the returned sequence orders
nullable/optional params after non-optional ones (e.g. the "int? b = default"
entry appears at the end) and that the passed-in parameterModels is
updated/consistent with the returned list (e.g. count and mapped names/types
match expected), using ParameterShared.ReplaceUnsafeCharacters and
OptionalParameterReorderer.Reorder as the referenced symbols to locate the tests
to change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d951231f-7100-4ef6-8907-19bf6f5e1250
📒 Files selected for processing (11)
src/Refitter.Core/BodyParameterExtractor.cssrc/Refitter.Core/FormParameterExtractor.cssrc/Refitter.Core/HeaderParameterExtractor.cssrc/Refitter.Core/IParameterTypeExtractor.cssrc/Refitter.Core/ParameterAggregator.cssrc/Refitter.Core/ParameterExtractor.cssrc/Refitter.Core/QueryParameterExtractor.cssrc/Refitter.Core/RouteParameterExtractor.cssrc/Refitter.Tests/FormParameterExtractorTests.cssrc/Refitter.Tests/Parameters/ParameterExtractorPrivateCoverageTests.cssrc/Refitter.Tests/Scenarios/IdentifierCorrectnessTests.cs
💤 Files with no reviewable changes (7)
- src/Refitter.Core/IParameterTypeExtractor.cs
- src/Refitter.Core/FormParameterExtractor.cs
- src/Refitter.Core/BodyParameterExtractor.cs
- src/Refitter.Tests/FormParameterExtractorTests.cs
- src/Refitter.Core/HeaderParameterExtractor.cs
- src/Refitter.Core/ParameterExtractor.cs
- src/Refitter.Core/RouteParameterExtractor.cs
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1136 +/- ##
==========================================
- Coverage 94.73% 94.57% -0.17%
==========================================
Files 39 38 -1
Lines 2658 2597 -61
==========================================
- Hits 2518 2456 -62
+ Misses 46 44 -2
- Partials 94 97 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…ynamicQuerystringCode paths
|



Changes
Commit 1: Remove CanExtract() from IParameterTypeExtractor
Commit 2: Convert QueryParameterExtractor to IParameterTypeExtractor
Commit 3: Delete ParameterExtractor.cs and rewrite tests
Verification
User Stories Addressed
Summary by CodeRabbit
Summary