From 0aaa0830a39e59f48a4b0fe160fba7e6f9c4d489 Mon Sep 17 00:00:00 2001 From: Louis Seubert Date: Thu, 21 May 2026 21:26:32 +0200 Subject: [PATCH] wip --- .editorconfig | 48 ++++-------- CHANGELOG.md | 4 +- README.md | 57 +++++++++++++- .../SemanticVersionComparerTests.cs | 2 +- src/semver.tests/SemanticVersionRangeTests.cs | 2 +- src/semver.tests/SemanticVersionTests.cs | 3 +- src/semver/SemanticVersion.Comparison.cs | 2 +- src/semver/SemanticVersion.Formatting.cs | 2 +- src/semver/SemanticVersion.JsonConverter.cs | 2 +- src/semver/SemanticVersion.Parsing.cs | 2 +- src/semver/SemanticVersion.cs | 2 +- src/semver/SemanticVersionComparer.cs | 2 +- src/semver/SemanticVersionRange.Formatting.cs | 2 +- .../SemanticVersionRange.JsonConverter.cs | 2 +- src/semver/SemanticVersionRange.Parsing.cs | 3 +- src/semver/SemanticVersionRange.cs | 2 +- src/semver/SpanBuffer.cs | 2 +- src/semver/package-icon.png | Bin 0 -> 15556 bytes src/semver/package-readme.md | 70 ++++++++++++++++++ 19 files changed, 155 insertions(+), 54 deletions(-) create mode 100644 src/semver/package-icon.png create mode 100644 src/semver/package-readme.md diff --git a/.editorconfig b/.editorconfig index 3848020..bdd4559 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,7 +5,7 @@ indent_style = tab indent_size = 4 tab_width = 4 end_of_line = lf -insert_final_newline = false +insert_final_newline = true trim_trailing_whitespace = true max_line_length = 120 @@ -14,22 +14,20 @@ indent_size = 2 indent_style = space trim_trailing_whitespace = false -[*.{csproj,props,targets,slnx}] +[*.{csproj,props,targets,slnx,config}] indent_size = 2 indent_style = space -[nuget.config] -indent_size = 2 -indent_style = space +[*.{cs,vb}] +#### code style rule default severity #### +dotnet_analyzer_diagnostic.category-style.severity = warning #### .NET Coding Conventions #### [*.{cs,vb}] - # Organize usings file_header_template = Copyright (c) The Geekeey Authors\nSPDX-License-Identifier: EUPL-1.2 dotnet_separate_import_directive_groups = true dotnet_sort_system_directives_first = true -dotnet_diagnostic.IDE0005.severity = suggestion # https://github.com/dotnet/roslyn/issues/41640 # this. and Me. preferences dotnet_style_qualification_for_event = false @@ -51,9 +49,8 @@ dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity dotnet_style_require_accessibility_modifiers = for_non_interface_members # Expression-level preferences - dotnet_diagnostic.IDE0270.severity = none -dotnet_style_coalesce_expression = true # IDE0029,IDE0030,IDE0270 +dotnet_style_coalesce_expression = true dotnet_style_collection_initializer = true dotnet_style_explicit_tuple_names = true @@ -64,16 +61,17 @@ dotnet_style_prefer_auto_properties = true dotnet_style_prefer_compound_assignment = true dotnet_diagnostic.IDE0045.severity = suggestion -dotnet_style_prefer_conditional_expression_over_assignment = true # IDE0045 +dotnet_style_prefer_conditional_expression_over_assignment = true + dotnet_diagnostic.IDE0046.severity = suggestion -dotnet_style_prefer_conditional_expression_over_return = true # IDE0046 +dotnet_style_prefer_conditional_expression_over_return = true dotnet_style_prefer_inferred_anonymous_type_member_names = true dotnet_style_prefer_inferred_tuple_names = true dotnet_style_prefer_is_null_check_over_reference_equality_method = true dotnet_style_prefer_simplified_boolean_expressions = true dotnet_style_prefer_simplified_interpolation = true -dotnet_style_namespace_match_folder = false # resharper: resharper_check_namespace_highlighting +dotnet_style_namespace_match_folder = false # Field preferences dotnet_style_readonly_field = true @@ -81,11 +79,6 @@ dotnet_style_readonly_field = true # Suppression preferences dotnet_remove_unnecessary_suppression_exclusions = none -# ReSharper preferences -resharper_wrap_object_and_collection_initializer_style = chop_always -resharper_check_namespace_highlighting = none -resharper_csharp_wrap_lines = false - #### C# Coding Conventions #### [*.cs] @@ -121,6 +114,7 @@ csharp_preferred_modifier_order = public, private, protected, internal, static, # Code-block preferences csharp_prefer_braces = true csharp_prefer_simple_using_statement = true +csharp_style_prefer_top_level_statements = false # Expression-level preferences csharp_prefer_simple_default_expression = true @@ -132,8 +126,8 @@ csharp_style_prefer_range_operator = true csharp_style_throw_expression = true dotnet_diagnostic.IDE0058.severity = suggestion -csharp_style_unused_value_assignment_preference = discard_variable # IDE0058 -csharp_style_unused_value_expression_statement_preference = discard_variable # IDE0058 +csharp_style_unused_value_assignment_preference = discard_variable +csharp_style_unused_value_expression_statement_preference = discard_variable # 'using' directive preferences csharp_using_directive_placement = outside_namespace @@ -401,19 +395,3 @@ dotnet_naming_style.s_camelcase.required_prefix = s_ dotnet_naming_style.s_camelcase.required_suffix = dotnet_naming_style.s_camelcase.word_separator = dotnet_naming_style.s_camelcase.capitalization = camel_case - -[*.{cs,vb}] -dotnet_analyzer_diagnostic.category-style.severity = warning -dotnet_analyzer_diagnostic.category-design.severity = warning -dotnet_analyzer_diagnostic.category-globalization.severity = notice -dotnet_analyzer_diagnostic.category-naming.severity = warning -dotnet_analyzer_diagnostic.category-performance.severity = warning -dotnet_analyzer_diagnostic.category-reliability.severity = warning -dotnet_analyzer_diagnostic.category-security.severity = warning -dotnet_analyzer_diagnostic.category-usage.severity = warning -dotnet_analyzer_diagnostic.category-maintainability.severity = warning - -dotnet_diagnostic.CA1716.severity = none # Identifiers should not match keywords -dotnet_diagnostic.CA1816.severity = suggestion # Dispose methods should call SuppressFinalize -dotnet_diagnostic.CA1848.severity = none # Use the LoggerMessage delegates -dotnet_diagnostic.IDE0210.severity = none # Use top-level statements diff --git a/CHANGELOG.md b/CHANGELOG.md index 81779d4..1ba22dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [1.0.0] - 2026-01-22 +## [1.0.0] - 2026-05-21 ### Added @@ -19,4 +19,4 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Removed [1.0.0]: https://code.geekeey.de/geekeey/semver/releases/tag/1.0.0 -[Unreleased]: https://code.geekeey.de/geekeey/semver/compare/1.0.0...HEAD \ No newline at end of file +[Unreleased]: https://code.geekeey.de/geekeey/semver/compare/1.0.0...HEAD diff --git a/README.md b/README.md index 335f284..25709ac 100644 --- a/README.md +++ b/README.md @@ -24,4 +24,59 @@ You may need to add our NuGet feed to your `nuget.config` this can be done by ru dotnet nuget add source -n geekeey https://code.geekeey.de/api/packages/geekeey/nuget/index.json ``` -### Usage \ No newline at end of file +### Usage + +```csharp +using Geekeey.SemVer; + +var version = SemanticVersion.Parse("1.2.3-beta+build.7"); +var next = new SemanticVersion(1, 3, 0); + +Console.WriteLine(version); +Console.WriteLine(version.Major); +Console.WriteLine(version.Prerelease); +Console.WriteLine(version.Metadata); +Console.WriteLine(version < next); +``` + +You can also use `TryParse` when you need to handle invalid input without exceptions. + +```csharp +using Geekeey.SemVer; + +if (SemanticVersion.TryParse("1.2.3-alpha", out var parsed)) +{ + Console.WriteLine(parsed); +} +``` + +Version ranges support npm-style and Maven-style syntax. + +```csharp +using Geekeey.SemVer; + +var npmRange = SemanticVersionRange.Parse("^1.2.3"); +var mavenRange = SemanticVersionRange.Parse("[1.2.3,2.0.0)"); +var candidate = SemanticVersion.Parse("1.4.2"); + +Console.WriteLine(npmRange.Contains(candidate)); +Console.WriteLine(mavenRange.Contains(candidate)); +Console.WriteLine(npmRange.ToString("m", null)); +Console.WriteLine(mavenRange.ToString("ns", null)); +``` + +Both `SemanticVersion` and `SemanticVersionRange` integrate with `System.Text.Json`. + +```csharp +using System.Text.Json; +using Geekeey.SemVer; + +var version = SemanticVersion.Parse("1.2.3-beta+build.7"); +var range = SemanticVersionRange.Parse("^1.2.3"); + +var versionJson = JsonSerializer.Serialize(version); +var rangeJson = JsonSerializer.Serialize(range); + +var roundTrippedVersion = JsonSerializer.Deserialize(versionJson); +var roundTrippedRange = JsonSerializer.Deserialize(rangeJson); +``` diff --git a/src/semver.tests/SemanticVersionComparerTests.cs b/src/semver.tests/SemanticVersionComparerTests.cs index de52204..94c9887 100644 --- a/src/semver.tests/SemanticVersionComparerTests.cs +++ b/src/semver.tests/SemanticVersionComparerTests.cs @@ -112,4 +112,4 @@ internal sealed class SemanticVersionComparerTests await Assert.That(SemanticVersionComparer.Priority.Equals(v1, v2)).IsFalse(); await Assert.That(SemanticVersionComparer.SortOrder.Equals(v1, v2)).IsFalse(); } -} \ No newline at end of file +} diff --git a/src/semver.tests/SemanticVersionRangeTests.cs b/src/semver.tests/SemanticVersionRangeTests.cs index 715efb1..2fb4c13 100644 --- a/src/semver.tests/SemanticVersionRangeTests.cs +++ b/src/semver.tests/SemanticVersionRangeTests.cs @@ -258,4 +258,4 @@ internal sealed class SemanticVersionRangeTests await Assert.That(success).IsFalse(); await Assert.That(charsWritten).IsEqualTo(0); } -} \ No newline at end of file +} diff --git a/src/semver.tests/SemanticVersionTests.cs b/src/semver.tests/SemanticVersionTests.cs index 0749384..fe09dd8 100644 --- a/src/semver.tests/SemanticVersionTests.cs +++ b/src/semver.tests/SemanticVersionTests.cs @@ -1,7 +1,6 @@ // Copyright (c) The Geekeey Authors // SPDX-License-Identifier: EUPL-1.2 -using System.Text; using System.Text.Encodings.Web; using System.Text.Json; @@ -223,4 +222,4 @@ internal sealed class SemanticVersionTests await Assert.That(() => JsonSerializer.Deserialize(json)) .Throws(); } -} \ No newline at end of file +} diff --git a/src/semver/SemanticVersion.Comparison.cs b/src/semver/SemanticVersion.Comparison.cs index 48ccfeb..6e2a43b 100644 --- a/src/semver/SemanticVersion.Comparison.cs +++ b/src/semver/SemanticVersion.Comparison.cs @@ -48,4 +48,4 @@ public readonly partial record struct SemanticVersion : IComparable, IComparable { return left.CompareTo(right) >= 0; } -} \ No newline at end of file +} diff --git a/src/semver/SemanticVersion.Formatting.cs b/src/semver/SemanticVersion.Formatting.cs index dc6b34b..890a35d 100644 --- a/src/semver/SemanticVersion.Formatting.cs +++ b/src/semver/SemanticVersion.Formatting.cs @@ -109,4 +109,4 @@ public readonly partial record struct SemanticVersion : ISpanFormattable } #endregion -} \ No newline at end of file +} diff --git a/src/semver/SemanticVersion.JsonConverter.cs b/src/semver/SemanticVersion.JsonConverter.cs index d08c40a..a0c200c 100644 --- a/src/semver/SemanticVersion.JsonConverter.cs +++ b/src/semver/SemanticVersion.JsonConverter.cs @@ -38,4 +38,4 @@ public readonly partial record struct SemanticVersion writer.WriteStringValue(value.ToString("f", null)); } } -} \ No newline at end of file +} diff --git a/src/semver/SemanticVersion.Parsing.cs b/src/semver/SemanticVersion.Parsing.cs index b3725b5..cb311aa 100644 --- a/src/semver/SemanticVersion.Parsing.cs +++ b/src/semver/SemanticVersion.Parsing.cs @@ -152,4 +152,4 @@ public readonly partial record struct SemanticVersion : ISpanParsable public string? Metadata { get; } -} \ No newline at end of file +} diff --git a/src/semver/SemanticVersionComparer.cs b/src/semver/SemanticVersionComparer.cs index c9e0dfa..a177492 100644 --- a/src/semver/SemanticVersionComparer.cs +++ b/src/semver/SemanticVersionComparer.cs @@ -304,4 +304,4 @@ public abstract class SemanticVersionComparer : IEqualityComparer buffer) Written += n; return true; } -} \ No newline at end of file +} diff --git a/src/semver/package-icon.png b/src/semver/package-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..35f4099b1fc44cc33936dcc321249cfab4de8c52 GIT binary patch literal 15556 zcmZ8|Wl$W>59l3o9PaM!aJai`arffx?p7%7P~4?hp%jNhin~K`FD}LH{r>O6`|xHb zn@M(db|=YXce6>XnyMTs5)l#r06G1TE0j#aIO=dAim{>$DNM7e zO(p1m2b+?^nc$G&&cwG$)oK7TjCL|*=qoc{3BF-qNhZ^kQSv<$SYLK8<$aES7|!#k zYnkp2ONN7FH3#?J2?aGTlX!4%Jr41Obvs7$if9Uk|xFq)_!m#i~1&t_Z*?m1^ zxN>c?w9CmP&?9(+H{=Vk(FgKWz2DxmbMQ^}F&h~++z|GdIGM()`Ut>@L ztJV45t+)S9lhAoSdfWW;@n)%LtR(cY;~^;cj{Y)n=WYvU!y^+w((L+_yogQs| zxhhw92bDZz!$h869~A&dC2K27JH)Tw+7$HOU*Sz8Q&|x{0pv9m(ob^jypEfE{D^bz zeQ5jCkD=C}+w*=+QupHLvGcT0%fr2z^f!zPlNSxxWj^kGb1gI6`&0g3;)m;Wz=l2L zPR4ZW{E^UgWyR)4+-LunPr`|Z0prg+|Jj}I==We&X|LYDl?Vkz<{Q_ZH`m1TIs8cvZ8;*NJbx|&u1fDO z4@gbx{@Yr}1NQV+s>;{a-+>?BeSY2lxjz(4B)e|g0XMe%P5E~f%xxn!u)a24@cy8? zwVT{%B#qbXK@wApC%hvXb|p*i@NuBR-V_ut{-S*kxOMiX07_PX_;L_jt1!UwGHBr^kOwddc@|_CC#h_fe8-c$iL%dmOAr&sHHchiUv0 zdi6jNq#7ZEo=IL5N^bl&cI zv2lp30B++l0*2z572L{Ubh#+Ql5rp?K3Ejh;*=D+12DjXAJg(ngt@#ad_s!sJoNY? z9|%iF0Sen$ZSQ}k-$VOVOtH+T|7>Ee76_62x#n+zUvETRZ$vC(HT#TcaJk-^OybKk z*Jt{+mo;s}cjt2aZ*A#ycLNSO)2CGoQ+1d{kHU@EwwLPG!{JL`Y)p{pQM3WfL@qK0 zRKwSPrtmNFD1sM9hMf$PL2g~#NpIW!!n)XP5V`gA(Ip~!bA6e7CxY&ZUH|1{YS_At z%-5}?A3g4_0atf*x+r?*W^IB&G( zp*^_GpO_3EgL#Rda#3VTh9s>8e`{a5<=)3gpP6=&Hm{;E2Air z{k=fUTM_@(jCP6!b_$Jia__kHUzutU-bM6z|A+kkY{1U@bcc8PsomLwndHycl~t4N zDL2xsGjxhZDsEsghjN7D-`X4cBUjb zg0jplpv(^qr{snT!V2>!7sutS-qN{Fzuu91--^KU_uU=S8~4quQu|=N_r_Rr()Mxl zbBAGO&t{uX(mMJM_z!@c!>X$l?Ac8*-fj-_RmDC{h<%Kt9PF>?#7)W!8o{+D0k;CS z9hEUL!==EH5c5ZI1_uOwaX<`%g+}1v3Jm^qWt($zgxp%;kGQ!A9vH-jVmcZQBEF8}W<)9Eyx` zBf#Bg(-yr$Y<3dH16@+y+6$8t-I2KX`hR6MNN>#J;Nxww;PuaCG6n!m8yLh%kma5W z^F+)6FIj6wYVtO=u$$SO{D^N4H2n3I0DA<-oUv`gl5{KhkTF{@+ym}XuIod@<;@(Hj`a-d7N2Y5#MbRMd|LNd+|=U4q`PL39A-K8NsDG@L976}=fO?(4>R zK5?6T7>5cyHu$*mq68!*5FU{J_eAKW=&csXrk

=twwFDw|u_7oe*s3ai1%@+b0K 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 OKtV=Tx?a*O{Qm&xB7La< literal 0 HcmV?d00001 diff --git a/src/semver/package-readme.md b/src/semver/package-readme.md new file mode 100644 index 0000000..de6be3b --- /dev/null +++ b/src/semver/package-readme.md @@ -0,0 +1,70 @@ +SemVer is a .NET library for parsing, comparing, formatting, and serializing semantic versions and version ranges. + +## Features + +- **Parsing:** parse semantic version strings into structured objects. +- **Comparison:** compare versions with operators or `CompareTo`. +- **Ranges:** evaluate npm-style and Maven-style version ranges. +- **Serialization:** use `System.Text.Json` converters for versions and ranges. + +## Getting Started + +### Install the NuGet package: + +```shell +dotnet add package Geekeey.SemVer +``` + +You may need to add our NuGet feed to your `nuget.config` this can be done by running the following command: + +```shell +dotnet nuget add source -n geekeey https://code.geekeey.de/api/packages/geekeey/nuget/index.json +``` + +### Usage + +```csharp +using Geekeey.SemVer; + +var version = SemanticVersion.Parse("1.2.3-beta+build.7"); +var next = new SemanticVersion(1, 3, 0); + +Console.WriteLine(version); +Console.WriteLine(version.Major); +Console.WriteLine(version.Prerelease); +Console.WriteLine(version.Metadata); +Console.WriteLine(version < next); + +if (SemanticVersion.TryParse("1.2.3-alpha", out var parsed)) +{ + Console.WriteLine(parsed); +} +``` + +Version ranges support npm-style and Maven-style syntax. + +```csharp +using Geekeey.SemVer; + +var npmRange = SemanticVersionRange.Parse("^1.2.3"); +var mavenRange = SemanticVersionRange.Parse("[1.2.3,2.0.0)"); +var candidate = SemanticVersion.Parse("1.4.2"); + +Console.WriteLine(npmRange.Contains(candidate)); +Console.WriteLine(mavenRange.Contains(candidate)); +Console.WriteLine(npmRange.ToString("m", null)); +Console.WriteLine(mavenRange.ToString("ns", null)); +``` + +Both `SemanticVersion` and `SemanticVersionRange` integrate with `System.Text.Json`. + +```csharp +using System.Text.Json; +using Geekeey.SemVer; + +var versionJson = JsonSerializer.Serialize(SemanticVersion.Parse("1.2.3-beta+build.7")); +var rangeJson = JsonSerializer.Serialize(SemanticVersionRange.Parse("^1.2.3")); + +var roundTrippedVersion = JsonSerializer.Deserialize(versionJson); +var roundTrippedRange = JsonSerializer.Deserialize(rangeJson); +```