Skip to content

Commit 7937861

Browse files
authored
Merge pull request #6 from navidata-io/release/1.1.0
1.1.0 Release
2 parents 01c0d56 + 6c656e4 commit 7937861

36 files changed

+1125
-60
lines changed

.config/dotnet-tools.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"isRoot": true,
44
"tools": {
55
"gitversion.tool": {
6-
"version": "6.2.0",
6+
"version": "6.3.0",
77
"commands": [
88
"dotnet-gitversion"
99
],
@@ -15,6 +15,13 @@
1515
"NuGetKeyVaultSignTool"
1616
],
1717
"rollForward": false
18+
},
19+
"thirdlicense": {
20+
"version": "1.3.1",
21+
"commands": [
22+
"thirdlicense"
23+
],
24+
"rollForward": false
1825
}
1926
}
2027
}

.github/workflows/ci.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ jobs:
7474
sign-packages:
7575
if: >
7676
(github.event_name == 'pull_request' &&
77-
github.event.pull_request.base.ref == 'main') ||
77+
github.event.pull_request.base.ref == 'main' &&
78+
github.event.pull_request.user.login != 'dependabot[bot]') ||
7879
(github.event_name == 'push' &&
7980
github.ref_type == 'tag' &&
8081
github.event.base_ref == 'refs/heads/main')
@@ -141,7 +142,7 @@ jobs:
141142
PKG_VERSION: ${{ needs.build-pack-test.outputs.PKG_VERSION }}
142143

143144
publish-github-packages: # Push to GitHub Packages if inside pull-request targeting main
144-
if: github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'main'
145+
if: github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'main' && github.event.pull_request.user.login != 'dependabot[bot]'
145146
runs-on: ubuntu-latest
146147
needs: sign-packages
147148
permissions:

Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@
1919
</ItemGroup>
2020
<ItemGroup>
2121
<GlobalPackageReference Include="DotNet.ReproducibleBuilds" Version="1.2.25" />
22-
<GlobalPackageReference Include="GitVersion.MsBuild" Version="6.2.0" />
22+
<GlobalPackageReference Include="GitVersion.MsBuild" Version="6.3.0" />
2323
</ItemGroup>
2424
</Project>

navidataIO.Utils.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<File Path="Directory.Build.props" />
55
<File Path="Directory.Packages.props" />
66
<File Path="GitVersion.yml" />
7+
<File Path="LICENSE" />
78
<File Path="navidataIO.png" />
89
<File Path="README.md" />
910
</Folder>

src/Directory.Build.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
<ItemGroup>
3434
<None Include="..\..\navidataIO.png" Pack="true" PackagePath="\" />
3535
<None Include="..\..\README.md" Pack="true" PackagePath="\" />
36+
<None Include="NOTICES.txt" Pack="true" PackagePath="\" />
3637
</ItemGroup>
3738

3839
<ItemGroup>

src/navidataIO.Utils.Json/Json/JsonContainerBase.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
using Newtonsoft.Json;
1+
// Copyright (c) 2024 navidata.io Corp
2+
// LICENSE-SPDX: <LGPL-3.0-only>
3+
4+
using Newtonsoft.Json;
25
using Newtonsoft.Json.Linq;
36

47
namespace navidataIO.Utils.Json;

src/navidataIO.Utils.Json/Json/JsonExtensions.cs

Lines changed: 199 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
using Newtonsoft.Json;
1+
// Copyright (c) 2024 navidata.io Corp
2+
// LICENSE-SPDX: <LGPL-3.0-only>
3+
4+
using Newtonsoft.Json;
25
using Newtonsoft.Json.Linq;
6+
using System.Text;
37

48
namespace navidataIO.Utils.Json;
59

@@ -46,11 +50,10 @@ public static JObject InsertTokenAsString<T>(this JObject parent, string propert
4650
/// Attempts to convert the specified JSON property to a value of type <typeparamref name="T"/>.
4751
/// Returns the converted value, or the default value if the property does not exist or cannot be converted.
4852
/// </summary>
49-
public static T? ReadPropertySafe<T>(this JObject json, string property, T? defaultValue = default, ILogger? logger = default)
53+
public static T? ReadPropertySafe<T>(this JObject json, string property, T? defaultValue = default, ILogger? logger = null)
5054
{
5155
if (json == null) throw new ArgumentNullException(nameof(json));
52-
if (string.IsNullOrEmpty(property))
53-
throw new ArgumentException("Value cannot be null or empty.", nameof(property));
56+
if (string.IsNullOrEmpty(property)) throw new ArgumentException("Value cannot be null or empty.", nameof(property));
5457

5558
if (json.TryGetValue(property, StringComparison.InvariantCultureIgnoreCase, out var value))
5659
{
@@ -118,11 +121,11 @@ public static bool TryParseJson<T>(this string json, out T? result) where T : cl
118121
try
119122
{
120123
result = JsonConvert.DeserializeObject<T>(json);
121-
return result != default;
124+
return result != null;
122125
}
123126
catch
124127
{
125-
result = default;
128+
result = null;
126129
return false;
127130
}
128131
}
@@ -139,7 +142,7 @@ public static bool TryParseJsonObject(this string json, out JObject? result)
139142
}
140143
catch
141144
{
142-
result = default;
145+
result = null;
143146
return false;
144147
}
145148
}
@@ -156,17 +159,204 @@ public static bool TryParseJsonArray(this string json, out JArray? result)
156159
}
157160
catch
158161
{
159-
result = default;
162+
result = null;
160163
return false;
161164
}
162165
}
163166

164167
/// <summary>
165168
/// Serializes the object to a JSON string, with specified formatting.
166169
/// </summary>
170+
[Obsolete("Use AsJson<T>(T?, Formatting) instead.")]
167171
public static string ToJsonString<T>(this T? value, Newtonsoft.Json.Formatting format = Newtonsoft.Json.Formatting.Indented) where T : class =>
168-
value == default
172+
value == null
169173
? ""
170174
: JsonConvert.SerializeObject(value, new JsonSerializerSettings { Formatting = format, NullValueHandling = NullValueHandling.Ignore });
171175

176+
/// <summary>
177+
/// Creates or overwrites the named property on a <see cref="JObject"/>, but only if the provided value is not <c>null</c>.
178+
/// </summary>
179+
public static JObject WithOptional(this JObject json, string propertyName, JToken? value)
180+
{
181+
if (json == null) throw new ArgumentNullException(nameof(json));
182+
if (propertyName == null) throw new ArgumentNullException(nameof(propertyName));
183+
184+
if (value is null || value is { Type: JTokenType.Null }) return json;
185+
if (value is JValue { Value: null } /* default(string) */) return json;
186+
187+
json[propertyName] = value;
188+
return json;
189+
}
190+
191+
/// <summary>
192+
/// Creates or overwrites the named property on a <see cref="JObject"/>, but only if the provided value is not <c>null</c>
193+
/// and the provided factory method produces a non-null <see cref="JToken"/>.
194+
/// </summary>
195+
public static JObject WithOptional<T>(this JObject json, string propertyName, T? value, Func<T, JToken?> createToken)
196+
{
197+
if (json == null) throw new ArgumentNullException(nameof(json));
198+
if (propertyName == null) throw new ArgumentNullException(nameof(propertyName));
199+
200+
if (value is null) return json;
201+
202+
if (createToken(value) is { } token)
203+
json[propertyName] = token;
204+
return json;
205+
}
206+
207+
/// <summary>
208+
/// Creates or overwrites the named JSON property as a new <see cref="JArray"/>,
209+
/// generated from items of the provides collection using the provided <paramref name="createToken"/> factory method,
210+
/// but only if the provided collection is not <c>null</c>. Any items producing a <c>null</c> token are ignored.
211+
/// </summary>
212+
public static JObject WithOptionalArray<T>(this JObject parent, string propertyName,
213+
ICollection<T>? collection, Func<T, JToken?> createToken)
214+
{
215+
if (parent == null) throw new ArgumentNullException(nameof(parent));
216+
if (propertyName == null) throw new ArgumentNullException(nameof(propertyName));
217+
218+
if (collection is null) return parent;
219+
220+
parent[propertyName] = new JArray(collection.Select(createToken).WhereNotNull());
221+
return parent;
222+
}
223+
224+
/// <summary>
225+
/// Creates or overwrites the named property on a <see cref="JObject"/>, regardless of the provided value.
226+
/// </summary>
227+
public static JObject WithProperty(this JObject json, string propertyName, JToken? value)
228+
{
229+
if (json == null) throw new ArgumentNullException(nameof(json));
230+
if (propertyName == null) throw new ArgumentNullException(nameof(propertyName));
231+
json[propertyName] = value;
232+
return json;
233+
}
234+
235+
/// <summary>
236+
/// Selects a <see cref="JObject"/> from the provided JSON at the specified path.
237+
/// Throws an <see cref="InvalidOperationException"/> if the token is not a <see cref="JObject"/> or does not exist.
238+
/// </summary>
239+
public static JObject RequireObject(this JObject json, string jsonPath)
240+
{
241+
if (json == null) throw new ArgumentNullException(nameof(json));
242+
return json.SelectObject(jsonPath, throwIfNull: true)!;
243+
}
244+
245+
/// <summary>
246+
/// Selects a <see cref="JObject"/> from the provided JSON at the specified path.
247+
/// Returns <c>null</c> if the token does not exist, unless <paramref name="throwIfNull"/> is <c>true</c>,
248+
/// in which case an <see cref="InvalidOperationException"/> is thrown.
249+
/// Always throws an <see cref="InvalidOperationException"/> if the token is not a <see cref="JObject"/>.
250+
/// </summary>
251+
public static JObject? SelectObject(this JObject json, string jsonPath, bool throwIfNull = false) =>
252+
(json ?? throw new ArgumentNullException(nameof(json))).SelectToken(jsonPath) switch
253+
{
254+
JObject jObject => jObject,
255+
null when throwIfNull => throw new InvalidOperationException($"Expected token at path {jsonPath} does not exist and 'throwIfNull' was selected."),
256+
null => null,
257+
_ => throw new InvalidOperationException($"Unable to select object from JSON at path: {jsonPath}")
258+
};
259+
260+
/// <summary>
261+
/// Renames a property on a <see cref="JObject"/>. If the property does not exist, it is ignored.
262+
/// </summary>
263+
public static JObject RenameProperty(this JObject parent, string oldName, string newName)
264+
{
265+
if (parent[oldName] is { } existingToken)
266+
{
267+
parent[newName] = existingToken;
268+
parent.Remove(oldName);
269+
}
270+
return parent;
271+
}
272+
273+
/// <summary>
274+
/// Removes the specified properties from a <see cref="JObject"/>. If a property does not exist, it is ignored.
275+
/// </summary>
276+
public static JObject RemoveProperties(this JObject obj, params string[] propertyNames)
277+
{
278+
if (obj == null) throw new ArgumentNullException(nameof(obj));
279+
280+
foreach (var propertyName in propertyNames)
281+
{
282+
obj.Remove(propertyName);
283+
}
284+
return obj;
285+
}
286+
287+
/// <summary>
288+
/// Serializes the object to a JSON string.
289+
/// </summary>
290+
/// <param name="obj">The object to serialize.</param>
291+
/// <param name="formatting">The (optional) <see cref="Formatting"/> to apply when serializing. If omitted, and no <paramref name="serializerSettings"/> are provided, <see cref="Formatting.Indented"/> is used. If set, and <paramref name="serializerSettings"/> are provided, this argument overwrites <see cref="JsonSerializerSettings.Formatting"/>.</param>
292+
/// <param name="serializerSettings">The (optional) <see cref="JsonSerializerSettings"/> to use when serializing.</param>
293+
/// <param name="resultIfNull">The value to return if <paramref name="obj"/> is null (default is <c>null</c>).</param>
294+
/// <returns>The serialized object as a string.</returns>
295+
public static string? AsJson<T>(this T? obj, Formatting? formatting = null,
296+
JsonSerializerSettings? serializerSettings = null, string? resultIfNull = null)
297+
{
298+
if (obj is null) return resultIfNull;
299+
300+
var settings = serializerSettings ?? new JsonSerializerSettings();
301+
if (serializerSettings is null && formatting is null)
302+
settings.Formatting = Formatting.Indented;
303+
else if (formatting is not null)
304+
settings.Formatting = formatting.Value;
305+
306+
return obj.AsJson(JsonSerializer.Create(settings));
307+
}
308+
309+
/// <summary>
310+
/// Serializes the object to a JSON string.
311+
/// </summary>
312+
/// <param name="obj">The object to serialize.</param>
313+
/// <param name="serializer">The <see cref="JsonSerializer"/> to use when serializing.</param>
314+
/// <param name="resultIfNull">The value to return if <paramref name="obj"/> is null (default is <c>null</c>).</param>
315+
/// <returns>The serialized object as a string.</returns>
316+
public static string? AsJson<T>(this T? obj, JsonSerializer serializer, string? resultIfNull = null)
317+
{
318+
if (obj is null) return resultIfNull;
319+
if (serializer == null) throw new ArgumentNullException(nameof(serializer));
320+
321+
var sb = new StringBuilder();
322+
using (var writer = new StringWriter(sb))
323+
{
324+
serializer.Serialize(writer, obj);
325+
}
326+
return sb.ToString();
327+
}
328+
329+
330+
/// <summary>
331+
/// Creates a <see cref="JToken"/> from the provided object using the specified <see cref="JsonSerializer"/>.
332+
/// Returns <c>null</c> if the object is <c>null</c>.
333+
/// </summary>
334+
/// <param name="obj">The object to convert to JSON.</param>
335+
/// <param name="formatting">The (optional) <see cref="Formatting"/> to apply when serializing. If omitted, and no <paramref name="serializerSettings"/> are provided, <see cref="Formatting.Indented"/> is used. If set, and <paramref name="serializerSettings"/> are provided, this argument overwrites <see cref="JsonSerializerSettings.Formatting"/>.</param>
336+
/// <param name="serializerSettings">The (optional) <see cref="JsonSerializerSettings"/> to use when serializing.</param>
337+
public static JToken? ToJson<T>(this T obj, Formatting? formatting = null,
338+
JsonSerializerSettings? serializerSettings = null)
339+
{
340+
var settings = serializerSettings ?? new JsonSerializerSettings();
341+
if (serializerSettings is null && formatting is null)
342+
settings.Formatting = Formatting.Indented;
343+
else if (formatting is not null)
344+
settings.Formatting = formatting.Value;
345+
var serializer = JsonSerializer.Create(settings);
346+
347+
return obj.ToJson(serializer);
348+
}
349+
350+
/// <summary>
351+
/// Creates a <see cref="JToken"/> from the provided object using the specified <see cref="JsonSerializer"/>.
352+
/// Returns <c>null</c> if the object is <c>null</c>.
353+
/// </summary>
354+
public static JToken? ToJson<T>(this T obj, JsonSerializer serializer)
355+
{
356+
object? o = obj;
357+
return o is null
358+
? null
359+
: JToken.FromObject(o, serializer ?? throw new ArgumentNullException(nameof(serializer)));
360+
}
361+
172362
}

src/navidataIO.Utils.Json/LogMessages.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Microsoft.Extensions.Logging;
1+
// Copyright (c) 2024 navidata.io Corp
2+
// LICENSE-SPDX: <LGPL-3.0-only>
23

34
namespace navidataIO.Utils;
45

0 commit comments

Comments
 (0)