-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add JsonPascalCaseNamingPolicy #100017
Add JsonPascalCaseNamingPolicy #100017
Conversation
Note regarding the
|
@dotnet-policy-service agree |
{ | ||
public override string ConvertName(string name) | ||
{ | ||
if (string.IsNullOrEmpty(name) || !char.IsLower(name[0])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm guessing this just mirrors the behavior of the camel case converter, but shouldn't we also try to have these convert kebab-case and snake_case renderings to PascalCase? What does Json.NET do in that case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @YohDeadfall
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my honest opinion all converters should behave like kebab and snake case ones, i.e. split an input string into parts, modify them and concatenate. That's exactly how the rest of the world does that, but for historical reasons the camel case policy cannot be changed. Due to that reason I'm thinking that this implementations sounds good, it just mirrors what the snake case does. That's the most expected behavior, I think.
But if it's possible to align the behavior of both camel and pascal case policies to what's going on for snake and camel case policies, then better to do so.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking the same thing, it might be something we could turn on with a feature flag in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey both, sorry for the late replies.
Json.NET doesn't have an implementation for PascalCase exactly, it just returns the name of the property as is in the DefaultNamingStrategy
- see here
There is an implementation of CamelCaseNamingStrategy
- here
and an implementation of KebabCaseNamingStrategy
- here
These call the StringUtils which also doesn't have an implementation for PascalCase - here
I can look into the current kebab and snake case scenarios and try implement that in this PR for the Pascal Case scenario if that works? I might need some help on how to create feature flags as it would be changing the existing camel case scenarios which I guess would be a breaking change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue with the pascal case policy is that it was released as a part of System.Text.Json
and therefore does things very primitively. The kebab and snake policies were added long time after a research I made on how other frameworks handle it outside of .NET world. The origin of these two policies is https://github.com/YohDeadfall/Yoh.Text.Json.NamingPolicies where later today I will push pascal and camel case policies which are done well. There are some deviations from what the SDK since @eiriktsarpalis found a bug which I didn't backported, but that's in plans too. Then that code can be used as is in the SDK once again, but for backward compatibility the current implementation of the camel case policy must be kept untouched. In addition to it a similar policy should be added which will upper case the first word (reverse behavior of the current camel case policy). That "reverse" camel case policy is exactly what you need at the moment.
I might need some help on how to create feature flags as it would be changing the existing camel case scenarios which I guess would be a breaking change?
That goes to @eiriktsarpalis. Perhaps, it needs approval from the .NET design review team first.
@mithileshz thanks for contributing this PR, it looks excellently implemented! Because this is adding new APIs, please note that before we can review or merge this PR an API proposal must be submitted for review (see our API review process document for more details). Essentially, this would involve adding a proposal to the parent issue (#34114) showing the new API surface that is being added (essentially showing the diff of your changes in the ref source file plus a couple of basic usage examples). Would you be able to add a proposal like that? Thanks. |
@eiriktsarpalis of course. Thank you for the information. I wasn't aware as I picked it up just out of curiosity so I'll do that right away. |
I wonder what the expected/intended behavior should be with regard to all-upper case strings/starting words like "UPPER". The camel case policy converts "UPPER" to "upper", changing the letter case not just for the 1st character, but for the whole word. Because camel case and pascal case are typically supposed to be the same except for the first letter, i would therefore intuitively expect the pascal case policy to convert "UPPER" to "Upper", but the current implementation here leaves the word all-upper case. |
I don't remember the exact rule for the camel case policy, but that one shall follow the same logic. Currently it just touches the first character as it was originally implemented by the camel case policy, but later it was improved to handle abbreviations like |
Hey @YohDeadfall, would you be able to point me towards where the abbreviations are set up? As the Camel Case Naming Policy currently is very basic and ToLower's the character based on the next character. |
Let's convert this to a draft while we wait on API review. |
The API has now been approved but please note that |
@mithileshz would you like to give this another go? .NET 9 has now been snapped from |
@eiriktsarpalis yes please. Can I get a bit of a guide on this? I have read through the comments and just to confirm - we want something similar to the rest of the APIs where it converts from one type to another. Rather than something similar to the camelCase one where it only takes the first character? |
That's correct. It should more closely follow the recently added kebab case and camel case converters that tokenize identifiers and then re-splice them together using PascalCase conventions. |
Then I guess, it's not different from having a base class with a virtual method overridden for exact implementations. You can see the same approach in https://github.com/YohDeadfall/Yoh.Text.Json.NamingPolicies/blob/v1.1.2 |
@YohDeadfall how are tokens being split in your pascal case policy? Is casing the only determinant or does it also recognize snake/kebab cased inputs? EDIT Looking at your README seems to have answered my question. The examples listed should be a good guide I think. |
My logic is a bit different than yours because I simply decided to give no shit about the legacy (: If you didn't change the string splitting rules too much to support JSON.NET, then the only thing needed here is a virtual method and a base class. That's due to being close to Unicode segmentation rules, but simplified them a lot just to cover identifiers only. But originally I used an implementation of the Unicode segmentation logic as the Other ecosystems outside use regular expressions, perhaps it's JS or Python, don't remember. You can find all of that in my original unmerged pull request for kebab and snake cases. There were a lot of info on the topic. |
Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it. |
After reading all the discussion on the PR, I realized this can be easily achieved by using the same abstract base class that tokenize identifiers for Snake and Kebab Case namespace System.Text.Json
{
internal sealed class JsonPascalCaseNamingPolicy : JsonSeparatorNamingPolicy
{
public JsonPascalCaseNamingPolicy ()
: base(lowercase: false, separator: '')
{
}
}
} This ensures that Pascal Case is in sync with Snake and Kebab case since they would share the base class which handles the splicing of words and mering them back. Let me know if I have maybe glossed over some key scenarios or discussion since this is my first attempt at trying this out. |
What is |
Hello @elgonzo
One more thing I just now noticed, the first argument in the constructor of ALL_CHARACTER_UPPERCASE, |
Adding a Pascal Case Naming Policy for System.Text.Json.
Fixes #34114
I was exploring the code to get a feel for it and thought I'd give it a go. Please let me know if there are any changes needing to be made!