Add JsonNamingPolicy.PascalCase and JsonKnownNamingPolicy.PascalCase#124644
Add JsonNamingPolicy.PascalCase and JsonKnownNamingPolicy.PascalCase#124644
Conversation
…se support Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com>
Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com>
...braries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/NamingPolicyUnitTests.cs
Outdated
Show resolved
Hide resolved
...braries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/NamingPolicyUnitTests.cs
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
This PR implements the approved API for JsonNamingPolicy.PascalCase and JsonKnownNamingPolicy.PascalCase = 6 to support PascalCase naming conventions in System.Text.Json. The implementation generalizes the existing word-boundary tokenizer used by snake_case and kebab_case naming policies to support PascalCase transformation, which capitalizes the first letter of each word while removing separators.
Changes:
- Adds
JsonNamingPolicy.PascalCasestatic property andJsonKnownNamingPolicy.PascalCase = 6enum value - Generalizes
JsonSeparatorNamingPolicywith aWordCasingenum and nullable separator to support PascalCase alongside existing separator-based policies - Includes comprehensive test coverage with 60+ test cases covering edge cases including Unicode, whitespace, numbers, and mixed casing patterns
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/System.Text.Json/Common/JsonSeparatorNamingPolicy.cs | Generalizes word-boundary tokenizer with WordCasing enum (LowerCase/UpperCase/PascalCase) and nullable char? separator to support PascalCase mode |
| src/libraries/System.Text.Json/Common/JsonPascalCaseNamingPolicy.cs | New sealed class extending JsonSeparatorNamingPolicy with WordCasing.PascalCase and no separator |
| src/libraries/System.Text.Json/Common/JsonNamingPolicy.cs | Adds PascalCase static property with XML documentation |
| src/libraries/System.Text.Json/Common/JsonKnownNamingPolicy.cs | Adds PascalCase = 6 enum member with XML documentation |
| src/libraries/System.Text.Json/ref/System.Text.Json.cs | Updates reference assembly with new API surface |
| src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs | Adds JsonKnownNamingPolicy.PascalCase case to naming policy switch expression |
| src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs | Adds JsonKnownNamingPolicy.PascalCase case to emitter's naming policy switch expression |
| src/libraries/System.Text.Json/src/System.Text.Json.csproj | Registers JsonPascalCaseNamingPolicy.cs for compilation |
| src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets | Registers JsonPascalCaseNamingPolicy.cs for source generator compilation |
| src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/NamingPolicyUnitTests.cs | Adds comprehensive ToPascalCase test with 60+ test cases covering transformations, edge cases, Unicode, and boundary conditions |
| src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNamingPolicyTests.cs | Adds basic PascalCase_ConvertName test with 6 common transformation examples |
| src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/PropertyNameTests.cs | Adds JsonNamingPolicy.PascalCase to JsonSeparatorNamingPolicyInstances test data |
…se test data Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com>
src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNamingPolicyTests.cs
Outdated
Show resolved
Hide resolved
...braries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/NamingPolicyUnitTests.cs
Show resolved
Hide resolved
...braries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/NamingPolicyUnitTests.cs
Show resolved
Hide resolved
...braries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/NamingPolicyUnitTests.cs
Show resolved
Hide resolved
…dResult) and add initialism/numeronym test cases Co-authored-by: jeffhandley <1031940+jeffhandley@users.noreply.github.com>
...braries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/NamingPolicyUnitTests.cs
Show resolved
Hide resolved
…yUnitTests Co-authored-by: jeffhandley <1031940+jeffhandley@users.noreply.github.com>
| [InlineData("camelCase", "CamelCase")] | ||
| [InlineData("A", "A")] | ||
| [InlineData("", "")] | ||
| public static void PascalCase_ConvertName(string input, string expected) |
There was a problem hiding this comment.
@copilot how do these tests differ from the ToPascalCase test in JsonNamingPolicyTests.cs? This seems to be testing the same thing but with fewer inputs.
There was a problem hiding this comment.
@copilot please address this feedback. How does the testing strategy here compare to snake case or kebab case?
There was a problem hiding this comment.
Fixed in f6e6a7f. PascalCase_ConvertName in JsonNamingPolicyTests.cs now has 6 test cases matching the pattern of the other policies' smoke tests in that file (CamelCase has 5, Snake/Kebab each have 6). The exhaustive 60+ test cases live exclusively in ToPascalCase in NamingPolicyUnitTests.cs, which matches how snake_case and kebab_case are structured (simple smoke tests in JsonNamingPolicyTests.cs, exhaustive coverage in NamingPolicyUnitTests.cs).
There was a problem hiding this comment.
@eiriktsarpalis why do these tests exist at all? This PascalCase_ConvertName test:
string result = JsonNamingPolicy.PascalCase.ConvertName(input);
Assert.Equal(expected, result);
is identical to ToPascalCase test:
JsonNamingPolicy policy = JsonNamingPolicy.PascalCase;
string value = policy.ConvertName(name);
Assert.Equal(expectedResult, value);
which has many more inputs.
There was a problem hiding this comment.
Accidental duplication? I think we could try rolling up the smaller suite into the larger one, but in the past this wasn't considered good practice due to the potential of it impacting test run data.
There was a problem hiding this comment.
Test run data meaning tests that no longer exist? I'd prefer we prioritize keeping the code base clean rather than trying to maintain tests purely because they used to exist. (I know there were some concerns about this specifically in dotnet/performance in order to be able to validate perf over time, but even there I'd prefer we just take the hit in the name of maintainability.)
There was a problem hiding this comment.
I was told at the time it was mostly around tracking flaky tests. These tests however are as deterministic as tests get, so I agree we could just roll them up with into a single suite.
There was a problem hiding this comment.
Removed PascalCase_ConvertName from JsonNamingPolicyTests.cs in 91562a5. The exhaustive 57-case ToPascalCase test in NamingPolicyUnitTests.cs is the only PascalCase test now.
…licies Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com>
🤖 Copilot Code Review — PR #113289Holistic AssessmentMotivation: This implements approved API Approach: Generalizes the existing Summary: Detailed Findings✅ API Surface — Matches approved proposal exactly
✅ Source Generator Integration — Correct
✅ Implementation —
|
|
Hello in description I see this conversion: but in tests Is it expected behavior with spaces? Also, what is the intension of |
|
Question about implementation, why did you choose this approach -- adding fake separator to |
...braries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/NamingPolicyUnitTests.cs
Outdated
Show resolved
Hide resolved
…ant PascalCase smoke test Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com>
| [InlineData("person", "Person")] | ||
| [InlineData("iPhone", "iPhone")] | ||
| [InlineData("iPhone", "IPhone")] | ||
| [InlineData("i Phone", "I Phone")] |
There was a problem hiding this comment.
@copilot Please ensure all test inputs from this theory are copied over to all the other naming policies.
There was a problem hiding this comment.
Done in a82736b — added "A11y" and "k8s" test inputs (the two inputs unique to the PascalCase theory) to all four separator-based policies: SnakeCaseLower, SnakeCaseUpper, KebabCaseLower, and KebabCaseUpper. All 471 naming policy tests pass.
There was a problem hiding this comment.
What about all the iphone variants?
There was a problem hiding this comment.
Added in 29dcd69f — all 26 CamelCase-origin inputs (iPhone, IPhone, I Phone, I Phone, IsCIA, VmQ, Xml2Json, SnAkEcAsE, SnA__kEcAsE, IsJSONProperty, SHOUTING_CASE, BUILDING, URL, URLValue, ID, I, etc.) are now present in all five separator-based policies. All 447 NamingPolicyUnitTests pass.
Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com>
…or-based naming policies Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com>
Description
Implements the approved API for
JsonNamingPolicy.PascalCaseandJsonKnownNamingPolicy.PascalCase = 6.API Surface
Implementation
Generalizes the word-boundary tokenizer in
JsonSeparatorNamingPolicy(used by snake_case/kebab_case) to also support PascalCase:WordCasingenum replaces thebool lowercaseparameter — addsPascalCasemode (word-initial uppercase, rest lowercase) alongside existingLowerCase/UpperCasechar?) — whennull, no separator is emitted between word groups; word boundary detection logic is unchanged and shared across all modesJsonPascalCaseNamingPolicy— thin subclass wiringWordCasing.PascalCasewith no separatorThis is intentionally distinct from
JsonCamelCaseNamingPolicy(which naively lowercases leading capitals) and cannot be changed for backward compatibility reasons.Behavior examples
camelCaseCamelCaseXMLHttpRequestXmlHttpRequestIOIoAIProviderAiProvidersnake_caseSnake_CaseSHOUTING_CASEShouting_Casei18nI18nA11yA11yk8sK8sdouble spaceDoubleSpaceChanges
Common/JsonSeparatorNamingPolicy.cs— generalized tokenizer withWordCasingenum andchar?separatorCommon/JsonPascalCaseNamingPolicy.cs— new policy classCommon/JsonNamingPolicy.cs— addedPascalCasestatic propertyCommon/JsonKnownNamingPolicy.cs— addedPascalCase = 6ref/System.Text.Json.cs— ref assembly updatecsproj/targets— new file registrationNamingPolicyUnitTests.cshas an exhaustive 57-case[Theory]ToPascalCasetest covering 2-letter initialisms (IO, AI), numeronyms (A11y, k8s, i18n), iPhone variants, Unicode edge cases, and boundary strings. The new test follows the existing(string expectedResult, string name)parameter convention used by the sibling CamelCase/SnakeCase/KebabCase tests in that file. All test inputs from the PascalCase and CamelCase theories (including iPhone, IPhone, IsCIA, VmQ, Xml2Json, SnAkEcAsE, IsJSONProperty, BUILDING, URL, URLValue, ID, A11y, k8s, etc.) were also added to the SnakeCaseLower, SnakeCaseUpper, KebabCaseLower, and KebabCaseUpper theories with correct expected outputs, ensuring consistent input coverage across all naming policy test theories. No pre-existing test outputs were changed.JsonNamingPolicyTests.csis unchanged — no redundant PascalCase smoke test was added since the exhaustive coverage inNamingPolicyUnitTests.csis sufficient.💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.