-
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
Added snake and kebab naming policies to JSON serializer #69613
Conversation
Note regarding the This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change. |
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis Issue DetailsFixes Issue #782 DescriptionAs it was discussed in the issue, I moved code from https://github.com/YohDeadfall/Yoh.Text.Json.NamingPolicies which implements snake and kebab policies. Customer ImpactAfter a few years they finally will get these highly demanded features. TestingYes, there are test checking different cases used in previous attempts too, but more of them were added.
|
@YohDeadfall CI fails with
|
src/libraries/System.Text.Json/Common/JsonSimpleNamingPolicy.cs
Outdated
Show resolved
Hide resolved
Okay, it should be fine now:
|
@teo-tsirpanis, while the public API shapes is awaiting for an approval, internals can be reviewed even now. |
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.
Some feedback, the code is a bit brittle at the moment.
I rewrote WriteWord
to something a bit more resilient, feel free to copy it over.
https://gist.github.com/NinoFloris/38597a90fb7c422d0244098c6fd94809
Also I noticed newlines are left alone entirely?
src/libraries/System.Text.Json/Common/JsonSimpleNamingPolicy.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/Common/JsonSimpleNamingPolicy.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/Common/JsonSimpleNamingPolicy.cs
Outdated
Show resolved
Hide resolved
}; | ||
|
||
if (currentCategory == CharCategory.Lowercase && char.IsUpper(next) || | ||
next == '_') |
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.
How does this fit with custom boundary chars?
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.
Hello, Nino (: Thank you for the valuable review.
That's a trimmed version of the original implementation which used word boundary and uppercase-lowercase logic to get words from an input string, but it was too heavy for a name policy as @ericstj told me in the previous attempt or in the issue. Therefore, the current implementation only support CLR member names and not any input string.
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 don't recall the exact conversation but it may have been about bringing in new library dependencies to handle word boundaries? Ultimately my guidance is usually just a suggestion and not a hard requirement -- we make the hard calls in API review and ultimately in PR with the area owners. Not everything is settled and if there is new data that invalidates past decisions it can be revisited. We do prioritize the right extensibility points in JSON rather than implementing every feature. cc @dotnet/area-system-text-json
return; | ||
|
||
int required = result.IsEmpty | ||
? word.Length |
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.
What works for the BCL in span.ToLower/ToUpper works here but a comment stating that we don't expect the length to change after upper/lowercasing, so we can just use length here, would be good.
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 would like to avoid assumptions on how internally such things work. Any dependency can be changed, but the code must continue to work.
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 agree which is why my gist code doesn't rely on it :)
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 think you can make the assumption that length can't change:
runtime/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.Globalization.cs
Lines 275 to 289 in f2de14d
public static int ToUpperInvariant(this ReadOnlySpan<char> source, Span<char> destination) | |
{ | |
if (source.Overlaps(destination)) | |
throw new InvalidOperationException(SR.InvalidOperation_SpanOverlappedOperation); | |
// Assuming that changing case does not affect length | |
if (destination.Length < source.Length) | |
return -1; | |
if (GlobalizationMode.Invariant) | |
InvariantModeCasing.ToUpper(source, destination); | |
else | |
TextInfo.Invariant.ChangeCaseToUpper(source, destination); | |
return source.Length; | |
} |
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.
Sure, but if that part changes at some point for whatever reason, the converter must be fixed too. Would someone remember to do that? I guess, not.
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.
Do we have evidence suggesting that the UTF-16 spec could permit variable character lengths when mapping casings? This would break the ToUpper
/ToLower
methods on char
.
cc @dotnet/area-system-globalization
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.
For ToUpper/ToLower on char
, we always map it manually through caching some tables from ICU. So, we guarantee 1-to-1 mapping. For the overloads that takes string
, it is possible to get variable length.
...braries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/NamingPolicyUnitTests.cs
Show resolved
Hide resolved
src/libraries/System.Text.Json/Common/JsonSimpleNamingPolicy.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs
Outdated
Show resolved
Hide resolved
@YohDeadfall given the newer APIs haven't been reviewed yet I'll refrain from review for now and let's not go too far with implementation or testing to not do unnecessary work. We've also discussed the new APIs during our JSON triage meeting and we don't feel strongly about either having or not having lowercase/uppercase APIs so we'll let API review folks make the final call. Specifically we don't have enough proof to believe uppercase version will be useful or not useful for anyone and at the same time the APIs seem to be isolated enough that we're ok with having them. |
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.
Thank you for your PR. It already looks very good. Have noted a few small things.
Looking forward to seeing this change with .NET 8.
src/libraries/System.Text.Json/Common/JsonSimpleNamingPolicy.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/Common/JsonSimpleNamingPolicy.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/Common/JsonSimpleNamingPolicy.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs
Outdated
Show resolved
Hide resolved
...braries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/NamingPolicyUnitTests.cs
Show resolved
Hide resolved
src/libraries/System.Text.Json/Common/JsonSimpleNamingPolicy.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/Common/JsonSimpleNamingPolicy.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/Common/JsonSimpleNamingPolicy.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/Common/JsonSimpleNamingPolicy.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/Common/JsonSimpleNamingPolicy.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/Common/JsonSimpleNamingPolicy.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/Common/JsonSimpleNamingPolicy.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/Common/JsonSimpleNamingPolicy.cs
Outdated
Show resolved
Hide resolved
ed2c3da
to
ead9f87
Compare
@eiriktsarpalis, I've addressed all name issues except one with which I strongly disagree ( |
...braries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/NamingPolicyUnitTests.cs
Show resolved
Hide resolved
src/libraries/System.Text.Json/Common/JsonSeparatorNamingPolicy.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/Common/JsonSeparatorNamingPolicy.cs
Outdated
Show resolved
Hide resolved
1914413
to
40d652c
Compare
40d652c
to
febb3c4
Compare
currentCategoryUnicode == UnicodeCategory.UppercaseLetter && | ||
char.IsLower(next)) | ||
{ | ||
WriteWord(chars.Slice(first, index - first), ref result); |
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 curious - should we be using identical rules to CamelCase except also adding -
or _
?
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.
Sure, I can do that, but knowing about "compatibility concerns" I expect to hear "no" from other reviewers (:
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.
And actually, what you asked is how naming policies work in other projects and platforms. They always split the input and then transform each word and concatenate them back.
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.
Please file an issue to consider joining this code with CamelCasing and I think we're ready to merge after that
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.
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.
LGTM with question
Any chance of this getting into .NET 7 via servicing? |
Guess, no, but feel free to use my package which source was used for that PR and later adjusted to address review issues from here:
I'll release version 1.0.0 soon. |
I doubt that will meet servicing bar. System.Text.Json ships as nuget package so you should be able to consume it with the next preview or nightly. |
Convert("aHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); | ||
Assert.Equal( | ||
"a_towel_it_says_is_about_the_most_massively_useful_thing_an_interstellar_hitchhiker_can_have_partly_it_has_great_practical_value_you_can_wrap_it_around_you_for_warmth_as_you_bound_across_the_cold_moons_of_jaglan_beta_you_can_lie_on_it_on_the_brilliant_marble_sanded_beaches_of_santraginus_v_inhaling_the_heady_sea_vapors_you_can_sleep_under_it_beneath_the_stars_which_shine_so_redly_on_the_desert_world_of_kakrafoon_use_it_to_sail_a_miniraft_down_the_slow_heavy_river_moth_wet_it_for_use_in_hand_to_hand_combat_wrap_it_round_your_head_to_ward_off_noxious_fumes_or_avoid_the_gaze_of_the_ravenous_bugblatter_beast_of_traal_a_mind_bogglingly_stupid_animal_it_assumes_that_if_you_cant_see_it_it_cant_see_you_daft_as_a_brush_but_very_very_ravenous_you_can_wave_your_towel_in_emergencies_as_a_distress_signal_and_of_course_dry_yourself_of_with_it_if_it_still_seems_to_be_clean_enough", | ||
Convert("ATowelItSaysIsAboutTheMostMassivelyUsefulThingAnInterstellarHitchhikerCanHave_PartlyItHasGreatPracticalValue_YouCanWrapItAroundYouForWarmthAsYouBoundAcrossTheColdMoonsOfJaglanBeta_YouCanLieOnItOnTheBrilliantMarbleSandedBeachesOfSantraginusVInhalingTheHeadySeaVapors_YouCanSleepUnderItBeneathTheStarsWhichShineSoRedlyOnTheDesertWorldOfKakrafoon_UseItToSailAMiniraftDownTheSlowHeavyRiverMoth_WetItForUseInHandToHandCombat_WrapItRoundYourHeadToWardOffNoxiousFumesOrAvoidTheGazeOfTheRavenousBugblatterBeastOfTraalAMindBogglinglyStupidAnimal_ItAssumesThatIfYouCantSeeItItCantSeeYouDaftAsABrushButVeryVeryRavenous_YouCanWaveYourTowelInEmergenciesAsADistressSignalAndOfCourseDryYourselfOfWithItIfItStillSeemsToBeCleanEnough")); |
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.
We should probably add a few tests validating that the output matches that of the Json.NET implementation, particularly when it comes to nontrivial inputs. We have time until .NET 8 ships, so we can always introduce breaking changes if needed.
Is there a particular reason why |
That's pretty simple to answer. That type is an implementation detail which shall not be exposed especially in case when it's a part of the SDK where anything public is written in stone and cannot be changed. Odd scenarios aren't a thing which is covered in developer kits, platforms and runtimes. |
Fixes #782
Description
As it was discussed in the issue, I moved code from https://github.com/YohDeadfall/Yoh.Text.Json.NamingPolicies which implements snake and kebab policies.
Customer Impact
After a few years they finally will get these highly demanded features.
Testing
Yes, there are test checking different cases used in previous attempts too, but more of them were added.