diff --git a/.gitignore b/.gitignore
index 89be2bb..672ba92 100644
--- a/.gitignore
+++ b/.gitignore
@@ -404,4 +404,7 @@ _packages/
.zf/extensions/
*.sbom.*
.endjin/
-BenchmarkDotNet.Artifacts/
\ No newline at end of file
+BenchmarkDotNet.Artifacts/
+
+# Microsoft.Testing.Platform diagnostic logs written to the repo root by the ZeroFailed test task
+/*.diag
diff --git a/.zf/config.ps1 b/.zf/config.ps1
index f5aebdc..b5424c7 100644
--- a/.zf/config.ps1
+++ b/.zf/config.ps1
@@ -3,6 +3,17 @@ This example demonstrates a software build process using the 'ZeroFailed.Build.D
to provide the features needed when building a .NET solutions.
#>
+# Reproducible builds: pin SOURCE_DATE_EPOCH to the HEAD commit's timestamp, so the copyright year in
+# Endjin.Conventions.props (and anything else honouring the convention) derives from the commit being
+# built rather than from the clock, and rebuilding a commit yields identical bytes across a year
+# boundary. A value already present in the environment wins; outside a git checkout the clock is used.
+if (-not $env:SOURCE_DATE_EPOCH) {
+ $commitTimestamp = & git log -1 --format=%ct 2>$null
+ if ($LASTEXITCODE -eq 0 -and $commitTimestamp) {
+ $env:SOURCE_DATE_EPOCH = "$commitTimestamp".Trim()
+ }
+}
+
$zerofailedExtensions = @(
@{
# References the extension from its GitHub repository. If not already installed, use latest version from 'main' will be downloaded.
diff --git a/README.md b/README.md
index 15e79d0..b0b7d52 100644
--- a/README.md
+++ b/README.md
@@ -106,14 +106,15 @@ For any licensing questions, please email [licens
## Project Sponsor
-This project is sponsored by [endjin](https://endjin.com), a UK based Technology Consultancy which specializes in Data & Analytics, AI & Cloud Native App Dev, and is a [.NET Foundation Corporate Sponsor](https://dotnetfoundation.org/membership/corporate-sponsorship).
+This project is sponsored by [endjin](https://endjin.com), a UK based Technology Consultancy which specializes in Data & Analytics, AI & Cloud Native App Dev.
> We help small teams achieve big things.
-We produce two free weekly newsletters:
+We produce three free weekly newsletters:
- [Azure Weekly](https://azureweekly.info) for all things about the Microsoft Azure Platform
- - [Power BI Weekly](https://powerbiweekly.info) for all things Power BI, Microsoft Fabric, and Azure Synapse Analytics
+ - [Power BI Weekly](https://powerbiweekly.info) for all things Power BI
+ - [Fabric Weekly](https://fabricweekly.info) for all things Microsoft Fabric
Keep up with everything that's going on at endjin via our [blog](https://endjin.com/blog), follow us on [Twitter](https://twitter.com/endjin), [YouTube](https://www.youtube.com/c/endjin) or [LinkedIn](https://www.linkedin.com/company/endjin).
diff --git a/Solutions/.editorconfig b/Solutions/.editorconfig
index c55db32..b369627 100644
--- a/Solutions/.editorconfig
+++ b/Solutions/.editorconfig
@@ -1,110 +1,167 @@
-# Note: this file was added to your solution as a result of one or more projects using the Endjin.RecommendedPractices.Build.Common NuGet package.
-# You can edit this file (e.g., to remove these comments), and it will not be updated - the package just checks for its presence, and copies
-# this file. If you don't want this file (but you want to use the NuGet package that puts it here), add this setting to all projects
-# using Endjin.RecommendedPractices.Build.Common:
-# true
-# and then delete this file. That setting will prevent the package from recreating this file.
-
-# Code style rules for enforcing the endjin house style
-# See: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
-
-# XML project files
-[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
-indent_size = 2
-
-# XML config files
-[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
-indent_size = 2
-
-# C# files
-[*.{cs,csx}]
-indent_size = 4
-insert_final_newline = false
+root = true
-# Core editorconfig formatting - indentation
-
-# use soft tabs (spaces) for indentation
+# All files
+[*]
+charset = utf-8
indent_style = space
+indent_size = 4
+end_of_line = lf
+insert_final_newline = false
+trim_trailing_whitespace = true
-# Formatting - indentation options
-
-csharp_indent_case_contents = true
-csharp_indent_switch_labels = true
-
-# Formatting - new line options
-
-csharp_new_line_before_catch = true
-csharp_new_line_before_else = true
-csharp_new_line_before_open_brace = object_collection, object_collection_array_initalizers, accessors, lambdas, control_blocks, methods, properties, types
-
-# Formatting - spacing options
-
-csharp_space_after_cast = false
-csharp_space_after_colon_in_inheritance_clause = true
-csharp_space_after_keywords_in_control_flow_statements = true
-csharp_space_before_colon_in_inheritance_clause = true
-csharp_space_between_method_call_empty_parameter_list_parentheses = false
-csharp_space_between_method_call_name_and_opening_parenthesis = false
-csharp_space_between_method_call_parameter_list_parentheses = false
-csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
-csharp_space_between_method_declaration_parameter_list_parentheses = false
-
-# Formatting - wrapping options
-
-csharp_preserve_single_line_blocks = true
-csharp_preserve_single_line_statements = true
-
-
-# Style - expression bodied member options
-
-csharp_style_expression_bodied_accessors = false:none
-csharp_style_expression_bodied_constructors = false:none
-csharp_style_expression_bodied_methods = false:none
-csharp_style_expression_bodied_properties = false:none
-
-# Style - expression level options
-
-csharp_style_inlined_variable_declaration = true:suggestion
-dotnet_style_predefined_type_for_member_access = true:suggestion
-
-# Style - implicit and explicit types
-
-csharp_style_var_for_built_in_types = false:warning
-csharp_style_var_when_type_is_apparent = true:warning
-csharp_style_var_elsewhere = false:warning
-
-# Style - language keyword and framework type options
-
-dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
-
-# Style - qualification options
-
-dotnet_style_qualification_for_field = true:suggestion
-dotnet_style_qualification_for_method = true:suggestion
-dotnet_style_qualification_for_property = true:suggestion
-dotnet_style_qualification_for_event = true:suggestion
-
-# Style - using directives and namespace declarations
-csharp_using_directive_placement = inside_namespace:warning
+# C# files
+[*.cs]
+
+# C# 12 Language features
+csharp_style_namespace_declarations = file_scoped:warning
+csharp_style_prefer_primary_constructors = false:suggestion
+csharp_style_prefer_top_level_statements = true:silent
+
+# Pattern matching preferences
+csharp_style_pattern_matching_over_is_with_cast_check = true:warning
+csharp_style_pattern_matching_over_as_with_null_check = true:warning
+csharp_style_prefer_switch_expression = true:suggestion
+csharp_style_prefer_pattern_matching = true:suggestion
+csharp_style_prefer_not_pattern = true:suggestion
+csharp_style_prefer_extended_property_pattern = true:suggestion
+
+# Null-checking preferences
+csharp_style_throw_expression = true:suggestion
+csharp_style_conditional_delegate_call = true:warning
+csharp_style_prefer_null_check_over_type_check = true:suggestion
+
+# Modifier preferences
+csharp_prefer_static_local_function = true:warning
+csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async:warning
+csharp_style_prefer_readonly_struct = true:suggestion
+csharp_style_prefer_readonly_struct_member = true:suggestion
+
+# Expression preferences
+csharp_prefer_simple_using_statement = true:warning
+csharp_style_prefer_index_operator = true:suggestion
+csharp_style_prefer_range_operator = true:suggestion
+csharp_style_implicit_object_creation_when_type_is_apparent = true:warning
+csharp_style_prefer_tuple_swap = true:suggestion
+csharp_style_prefer_utf8_string_literals = true:suggestion
+csharp_style_inlined_variable_declaration = true:warning
+csharp_style_deconstructed_variable_declaration = true:suggestion
+csharp_style_unused_value_assignment_preference = discard_variable:suggestion
+csharp_style_unused_value_expression_statement_preference = discard_variable:silent
+
+# Expression-bodied members
+csharp_style_expression_bodied_methods = when_on_single_line:suggestion
+csharp_style_expression_bodied_constructors = false:suggestion
+csharp_style_expression_bodied_operators = when_on_single_line:suggestion
+csharp_style_expression_bodied_properties = true:suggestion
+csharp_style_expression_bodied_indexers = true:suggestion
+csharp_style_expression_bodied_accessors = true:suggestion
+csharp_style_expression_bodied_lambdas = true:suggestion
+csharp_style_expression_bodied_local_functions = when_on_single_line:suggestion
+
+# Collection expressions (C# 12)
+dotnet_style_prefer_collection_expression = true:suggestion
+
+# Code style rules
+dotnet_style_prefer_auto_properties = true:warning
+dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
+dotnet_style_prefer_conditional_expression_over_return = true:suggestion
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
+dotnet_style_prefer_compound_assignment = true:suggestion
+dotnet_style_prefer_simplified_interpolation = true:suggestion
+dotnet_style_prefer_simplified_boolean_expressions = true:warning
+
+# Field preferences
+dotnet_style_readonly_field = true:warning
+
+# Parameter preferences
+dotnet_code_quality_unused_parameters = all:warning
+
+# Suppression preferences
+dotnet_remove_unnecessary_suppression_exclusions = none
+
+# Code style for 'this.' qualification
+dotnet_style_qualification_for_field = true:silent
+dotnet_style_qualification_for_property = true:silent
+dotnet_style_qualification_for_method = true:silent
+dotnet_style_qualification_for_event = true:silent
+
+# Blank line preferences
+csharp_blank_lines_around_region = 1
+csharp_blank_lines_inside_region = 1
+csharp_blank_lines_between_using_groups = 1
+
+# Using preferences
+csharp_using_directive_placement = outside_namespace:warning
+csharp_prefer_simple_using_statement = true:warning
+dotnet_style_namespace_match_folder = true:suggestion
dotnet_sort_system_directives_first = true
+dotnet_separate_import_directive_groups = false
+
+# IDE0005: Remove unnecessary using directives
+dotnet_diagnostic.IDE0005.severity = warning
+
+# Naming conventions
+dotnet_naming_rule.interface_should_be_prefixed_with_i.severity = warning
+dotnet_naming_rule.interface_should_be_prefixed_with_i.symbols = interface
+dotnet_naming_rule.interface_should_be_prefixed_with_i.style = begins_with_i
+
+dotnet_naming_rule.types_should_be_pascal_case.severity = warning
+dotnet_naming_rule.types_should_be_pascal_case.symbols = types
+dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = warning
+dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+
+dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+
+dotnet_naming_style.begins_with_i.required_prefix = I
+dotnet_naming_style.begins_with_i.capitalization = pascal_case
+
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+
+# Source code files
+[src/**/*.cs]
+# CA1848: Use LoggerMessage delegates for performance
+dotnet_diagnostic.CA1848.severity = none
+# CA1031: Do not catch general exception types
+dotnet_diagnostic.CA1031.severity = none
+# CA1515: Make internal since this is an application
+dotnet_diagnostic.CA1515.severity = none
+# CA1050: Declare types in namespaces - top-level programs don't need this
+dotnet_diagnostic.CA1050.severity = none
+# CA2007: ConfigureAwait not needed in applications
+dotnet_diagnostic.CA2007.severity = none
+# CA1034: Nested types are ok for settings
+dotnet_diagnostic.CA1034.severity = none
+
+# Test files
+[**/*Tests.cs]
+# CA1707: Allow underscores in test method names
+dotnet_diagnostic.CA1707.severity = none
+# CA1303: Do not pass literals as localized parameters
+dotnet_diagnostic.CA1303.severity = none
+# CA1515: Consider making public types internal
+dotnet_diagnostic.CA1515.severity = none
+# CA2007: Consider calling ConfigureAwait on the awaited task
+dotnet_diagnostic.CA2007.severity = none
+
+# JSON files
+[*.json]
+indent_size = 2
+
+# YAML files
+[*.{yml,yaml}]
+indent_size = 2
-# Code analyzer rules (formerly in StyleCop.ruleset)
-# SA1025 makes it impossible to write decent-looking switch expressions because it
-# doesn't allow multiple whitespace characters in a row. There seems to be no way to
-# disable this rule just inside switch expressions, so we reluctantly live without it.
-dotnet_diagnostic.SA1025.severity = None
-# StyleCop's insistence that constructors' summaries must always start with exactly
-# the same boilerplate text is not deeply helpful. Saying "Creates a Foo"
-# is in most cases better than the "Initializes a new instance of the Foo type"
-# that this rule insists on.
-dotnet_diagnostic.SA1642.severity = None
-
-# CLS Compliance - not relevant for most of what we work on.
-dotnet_diagnostic.CA1014.severity = None
-
-# Standard exception constructors - not helpful when the exception absolutely needs certain information
-dotnet_diagnostic.CA1032.severity = None
-dotnet_diagnostic.RCS1194.severity = None
-
-# Localize string constants - apps that want localization can turn this back on
-dotnet_diagnostic.CA1303.severity = None
\ No newline at end of file
+# XML files
+[*.{xml,csproj,props,targets}]
+indent_size = 2
\ No newline at end of file
diff --git a/Solutions/Ais.Net.Models.Benchmarks/ConversionBenchmarks.cs b/Solutions/Ais.Net.Models.Benchmarks/ConversionBenchmarks.cs
index 0b09c8a..ba5f932 100644
--- a/Solutions/Ais.Net.Models.Benchmarks/ConversionBenchmarks.cs
+++ b/Solutions/Ais.Net.Models.Benchmarks/ConversionBenchmarks.cs
@@ -1,10 +1,8 @@
-namespace Ais.Net.Models.Benchmarks;
-
-using Ais.Net.Models;
using Ais.Net.Models.Abstractions;
using BenchmarkDotNet.Attributes;
+namespace Ais.Net.Models.Benchmarks;
///
/// Measures the pure numeric/enum helpers on the decode path. These are expected to be
/// branch-free-ish, sub-nanosecond, and allocation-free; the benchmark exists to prove that
diff --git a/Solutions/Ais.Net.Models.Benchmarks/MessageConstructionBenchmarks.cs b/Solutions/Ais.Net.Models.Benchmarks/MessageConstructionBenchmarks.cs
index 1fc1fc2..44734fb 100644
--- a/Solutions/Ais.Net.Models.Benchmarks/MessageConstructionBenchmarks.cs
+++ b/Solutions/Ais.Net.Models.Benchmarks/MessageConstructionBenchmarks.cs
@@ -1,10 +1,8 @@
-namespace Ais.Net.Models.Benchmarks;
-
-using Ais.Net.Models;
using Ais.Net.Models.Abstractions;
using BenchmarkDotNet.Attributes;
+namespace Ais.Net.Models.Benchmarks;
///
/// Measures the cost of materialising a model record for a decoded message. Records are
/// reference types, so each message is at least one heap allocation (plus a nested
diff --git a/Solutions/Ais.Net.Models.Benchmarks/PositionBenchmarks.cs b/Solutions/Ais.Net.Models.Benchmarks/PositionBenchmarks.cs
index 3db16ca..d497f1d 100644
--- a/Solutions/Ais.Net.Models.Benchmarks/PositionBenchmarks.cs
+++ b/Solutions/Ais.Net.Models.Benchmarks/PositionBenchmarks.cs
@@ -1,9 +1,9 @@
-namespace Ais.Net.Models.Benchmarks;
using Ais.Net.Models.Abstractions;
using BenchmarkDotNet.Attributes;
+namespace Ais.Net.Models.Benchmarks;
///
/// Confirms that constructing a is allocation-free. It was reworked from a
/// record (reference type, 32 B per instance) to a readonly record struct, so this
diff --git a/Solutions/Ais.Net.Models.Benchmarks/VesselNameBenchmarks.cs b/Solutions/Ais.Net.Models.Benchmarks/VesselNameBenchmarks.cs
index 1820142..d7a1018 100644
--- a/Solutions/Ais.Net.Models.Benchmarks/VesselNameBenchmarks.cs
+++ b/Solutions/Ais.Net.Models.Benchmarks/VesselNameBenchmarks.cs
@@ -1,11 +1,9 @@
-namespace Ais.Net.Models.Benchmarks;
using System;
-using Ais.Net.Models;
-
using BenchmarkDotNet.Attributes;
+namespace Ais.Net.Models.Benchmarks;
///
/// Compares vessel-name cleaning strategies. The production method currently uses
/// Trim(...).Split(...).Join(...) which allocates a temporary trimmed string, an array,
diff --git a/Solutions/Ais.Net.Models.Specs/AisMessageExtensionsTests.cs b/Solutions/Ais.Net.Models.Specs/AisMessageExtensionsTests.cs
index 0488954..b243a1a 100644
--- a/Solutions/Ais.Net.Models.Specs/AisMessageExtensionsTests.cs
+++ b/Solutions/Ais.Net.Models.Specs/AisMessageExtensionsTests.cs
@@ -1,14 +1,11 @@
-namespace Ais.Net.Models.Specs;
using System;
-using Ais.Net;
-using Ais.Net.Models;
-
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;
+namespace Ais.Net.Models.Specs;
[TestClass]
public class AisMessageExtensionsTests
{
diff --git a/Solutions/Ais.Net.Models.Specs/AisMessageType18Tests.cs b/Solutions/Ais.Net.Models.Specs/AisMessageType18Tests.cs
index dd956a3..5cd5426 100644
--- a/Solutions/Ais.Net.Models.Specs/AisMessageType18Tests.cs
+++ b/Solutions/Ais.Net.Models.Specs/AisMessageType18Tests.cs
@@ -1,12 +1,10 @@
-namespace Ais.Net.Models.Specs;
-
-using Ais.Net.Models;
using Ais.Net.Models.Abstractions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;
+namespace Ais.Net.Models.Specs;
[TestClass]
public class AisMessageType18Tests
{
diff --git a/Solutions/Ais.Net.Models.Specs/AisMessageType19Tests.cs b/Solutions/Ais.Net.Models.Specs/AisMessageType19Tests.cs
index 13b971e..1c58579 100644
--- a/Solutions/Ais.Net.Models.Specs/AisMessageType19Tests.cs
+++ b/Solutions/Ais.Net.Models.Specs/AisMessageType19Tests.cs
@@ -1,12 +1,10 @@
-namespace Ais.Net.Models.Specs;
-
-using Ais.Net.Models;
using Ais.Net.Models.Abstractions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;
+namespace Ais.Net.Models.Specs;
[TestClass]
public class AisMessageType19Tests
{
diff --git a/Solutions/Ais.Net.Models.Specs/AisMessageType1Through3Tests.cs b/Solutions/Ais.Net.Models.Specs/AisMessageType1Through3Tests.cs
index a4a7503..c9b1733 100644
--- a/Solutions/Ais.Net.Models.Specs/AisMessageType1Through3Tests.cs
+++ b/Solutions/Ais.Net.Models.Specs/AisMessageType1Through3Tests.cs
@@ -1,12 +1,10 @@
-namespace Ais.Net.Models.Specs;
-
-using Ais.Net.Models;
using Ais.Net.Models.Abstractions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;
+namespace Ais.Net.Models.Specs;
[TestClass]
public class AisMessageType1Through3Tests
{
diff --git a/Solutions/Ais.Net.Models.Specs/AisMessageType24Part0Tests.cs b/Solutions/Ais.Net.Models.Specs/AisMessageType24Part0Tests.cs
index a696c11..cb207a0 100644
--- a/Solutions/Ais.Net.Models.Specs/AisMessageType24Part0Tests.cs
+++ b/Solutions/Ais.Net.Models.Specs/AisMessageType24Part0Tests.cs
@@ -1,11 +1,8 @@
-namespace Ais.Net.Models.Specs;
-
-using Ais.Net.Models;
-
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;
+namespace Ais.Net.Models.Specs;
[TestClass]
public class AisMessageType24Part0Tests
{
diff --git a/Solutions/Ais.Net.Models.Specs/AisMessageType24Part1Tests.cs b/Solutions/Ais.Net.Models.Specs/AisMessageType24Part1Tests.cs
index 4153435..988a651 100644
--- a/Solutions/Ais.Net.Models.Specs/AisMessageType24Part1Tests.cs
+++ b/Solutions/Ais.Net.Models.Specs/AisMessageType24Part1Tests.cs
@@ -1,12 +1,8 @@
-namespace Ais.Net.Models.Specs;
-
-using Ais.Net.Models;
-using Ais.Net.Models.Abstractions;
-
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;
+namespace Ais.Net.Models.Specs;
[TestClass]
public class AisMessageType24Part1Tests
{
diff --git a/Solutions/Ais.Net.Models.Specs/AisMessageType27Tests.cs b/Solutions/Ais.Net.Models.Specs/AisMessageType27Tests.cs
index 14ae355..6c05771 100644
--- a/Solutions/Ais.Net.Models.Specs/AisMessageType27Tests.cs
+++ b/Solutions/Ais.Net.Models.Specs/AisMessageType27Tests.cs
@@ -1,12 +1,10 @@
-namespace Ais.Net.Models.Specs;
-
-using Ais.Net.Models;
using Ais.Net.Models.Abstractions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;
+namespace Ais.Net.Models.Specs;
[TestClass]
public class AisMessageType27Tests
{
diff --git a/Solutions/Ais.Net.Models.Specs/AisMessageType5Tests.cs b/Solutions/Ais.Net.Models.Specs/AisMessageType5Tests.cs
index 998bf3e..5ca0dad 100644
--- a/Solutions/Ais.Net.Models.Specs/AisMessageType5Tests.cs
+++ b/Solutions/Ais.Net.Models.Specs/AisMessageType5Tests.cs
@@ -1,12 +1,8 @@
-namespace Ais.Net.Models.Specs;
-
-using Ais.Net.Models;
-using Ais.Net.Models.Abstractions;
-
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;
+namespace Ais.Net.Models.Specs;
[TestClass]
public class AisMessageType5Tests
{
diff --git a/Solutions/Ais.Net.Models.Specs/PositionTests.cs b/Solutions/Ais.Net.Models.Specs/PositionTests.cs
index d8b884a..9761b51 100644
--- a/Solutions/Ais.Net.Models.Specs/PositionTests.cs
+++ b/Solutions/Ais.Net.Models.Specs/PositionTests.cs
@@ -1,12 +1,10 @@
-namespace Ais.Net.Models.Specs;
-
-using Ais.Net.Models;
using Ais.Net.Models.Abstractions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;
+namespace Ais.Net.Models.Specs;
[TestClass]
public class PositionTests
{
diff --git a/Solutions/Ais.Net.Models.Specs/ShipTypeClassificationTests.cs b/Solutions/Ais.Net.Models.Specs/ShipTypeClassificationTests.cs
index 67450ad..196e440 100644
--- a/Solutions/Ais.Net.Models.Specs/ShipTypeClassificationTests.cs
+++ b/Solutions/Ais.Net.Models.Specs/ShipTypeClassificationTests.cs
@@ -1,12 +1,10 @@
-namespace Ais.Net.Models.Specs;
-
-using Ais.Net.Models;
using Ais.Net.Models.Abstractions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;
+namespace Ais.Net.Models.Specs;
[TestClass]
public class ShipTypeClassificationTests
{
diff --git a/Solutions/Ais.Net.Models.Specs/packages.lock.json b/Solutions/Ais.Net.Models.Specs/packages.lock.json
index c3a54f2..cdee2ca 100644
--- a/Solutions/Ais.Net.Models.Specs/packages.lock.json
+++ b/Solutions/Ais.Net.Models.Specs/packages.lock.json
@@ -4,50 +4,53 @@
"net10.0": {
"Microsoft.Testing.Extensions.CodeCoverage": {
"type": "Direct",
- "requested": "[18.9.0, )",
- "resolved": "18.9.0",
- "contentHash": "Odp8djWEUFTJoRV02y0zJaAwAHF31CtNaDgnKKM+8dBHbbaH7Ee0oo9gweLpbzjI7UrtMUzH6xLJSrICZw+Nwg==",
+ "requested": "[18.12.0, )",
+ "resolved": "18.12.0",
+ "contentHash": "BST/sWYpKk9OXO7Yxktcg6FWORRsHU0EdCbMwZ7d3OqJsMKlrNHIZ30g0Ib4k5T5acJYXRBmg9mNrTU/N6cy1g==",
"dependencies": {
- "Microsoft.DiaSymReader": "2.2.9",
- "Microsoft.Extensions.DependencyModel": "10.0.8",
- "Microsoft.Testing.Platform": "2.3.0"
+ "Microsoft.DiaSymReader": "2.2.10",
+ "Microsoft.Extensions.DependencyModel": "10.0.10",
+ "Microsoft.Testing.Platform": "2.5.0",
+ "Mono.Cecil": "0.11.6"
}
},
"Microsoft.Testing.Extensions.TrxReport": {
"type": "Direct",
- "requested": "[2.3.2, )",
- "resolved": "2.3.2",
- "contentHash": "JzCtiOAmIfkPP2PpAKZeiH1hVYIVC9jMhsPWrd6PnH/Wtuct1UMuxpKi2F1cmXgfokc/HOadC6HOO1qzI23tnA==",
+ "requested": "[2.5.1, )",
+ "resolved": "2.5.1",
+ "contentHash": "NHqpG2UAVsXoNnNZtyIjxgsfPe9N/E6eTHjHCs7uaSbdOCOsbX5I7N0d1BHyjM7vv3Q5R2nlvngKSHWT+ZCRXQ==",
"dependencies": {
- "Microsoft.Testing.Extensions.TrxReport.Abstractions": "2.3.2",
- "Microsoft.Testing.Platform": "2.3.2"
+ "Microsoft.Testing.Extensions.TrxReport.Abstractions": "2.5.1",
+ "Microsoft.Testing.Platform": "[2.5.1, 3.0.0)"
}
},
"MSTest.TestAdapter": {
"type": "Direct",
- "requested": "[4.3.2, )",
- "resolved": "4.3.2",
- "contentHash": "uqpjJqQ3ws5z7Pq6BfMFpuqdrN2YIfe0Gfww91LRVXwxBdLqUaJd4JbHUImOSQvmK5m3PqW285kPjKbb69QFoA==",
+ "requested": "[4.5.1, )",
+ "resolved": "4.5.1",
+ "contentHash": "0q9TkkpOF3YjXGMfjcQG5bftpu/NPhVqKFL4DLUDJK6CGO4si5z+PVxVL1fM6TXEFSHnCM09E1691nhn8GUTYg==",
"dependencies": {
- "MSTest.TestFramework": "4.3.2",
- "Microsoft.Testing.Extensions.VSTestBridge": "2.3.2",
- "Microsoft.Testing.Platform.MSBuild": "2.3.2"
+ "MSTest.TestFramework": "4.5.1",
+ "Microsoft.TestPlatform.ObjectModel": "18.10.1",
+ "Microsoft.Testing.Extensions.Telemetry": "2.5.1",
+ "Microsoft.Testing.Extensions.TrxReport.Abstractions": "2.5.1",
+ "Microsoft.Testing.Platform.MSBuild": "2.5.1"
}
},
"MSTest.TestFramework": {
"type": "Direct",
- "requested": "[4.3.2, )",
- "resolved": "4.3.2",
- "contentHash": "Vlj3THt/BcOV/93k0Cdq29RNEsrY3TvUV6mF13rOuY8Gx7Ltd+LrOYId8AYu0cH9ioCYY/Sx1hppfI9p/vP+aw==",
+ "requested": "[4.5.1, )",
+ "resolved": "4.5.1",
+ "contentHash": "mdYgQYAtDGq/IixJq7oD6VvIYAz+mRniGMxyhlZ2wQOpIeFe6oFQ/RniT3i7c3ZfCTKykhI6AB0wqRYVEWZDgQ==",
"dependencies": {
- "MSTest.Analyzers": "4.3.2"
+ "MSTest.Analyzers": "4.5.1"
}
},
"NSubstitute": {
"type": "Direct",
- "requested": "[6.0.0, )",
- "resolved": "6.0.0",
- "contentHash": "0gvKMbiJ+/WrfbcfBfqRZZrvfLJcd3rqkqVMjjlY5dtmLRVzMY+o/K/rJUStofQ2haSr9Vd04YDfvZtVVGS3/A==",
+ "requested": "[6.2.0, )",
+ "resolved": "6.2.0",
+ "contentHash": "05oaAmBAvYYUQb/NTb9/kWBDjq0iS772X4t428WJcHRcH+5ULJx6rTbEvqkZJBIHWRLI8MlU3et3F5/gkEHKIw==",
"dependencies": {
"Castle.Core": "5.1.1"
}
@@ -91,64 +94,58 @@
},
"Microsoft.DiaSymReader": {
"type": "Transitive",
- "resolved": "2.2.9",
- "contentHash": "WLbDc/W9XkHpGVtd1L6Vml8W6+PaaYZZTJASHjHF7W2WX/hld6bfNK102Ui+I3a6zIdx4+oKRJtMgHz44JmBfw=="
+ "resolved": "2.2.10",
+ "contentHash": "zmGsm6b2y3STDa/Of7rdkkfTDV8VuGB8aCqIkLoJIQh5tL78K3zJ8OUyFKnfsaORXmGr9iOKwDkZfUjeXi+CwA=="
},
"Microsoft.Extensions.DependencyModel": {
"type": "Transitive",
- "resolved": "10.0.8",
- "contentHash": "vLyZVpxmduO2jx+76ggqnsA3m81kwMY3NkWciNTj5E+Nvqb0VihqCvQP89QsGONWp0AJwMZG+u9GzaCjDdFGNw=="
+ "resolved": "10.0.10",
+ "contentHash": "rfZA1RjR021RPqSmIPovfz2aOd79TGqJ9BengbjnzIISOVwjLmuSDnhCMmiY/1c6iYvGolQ1iNGzkav0u11XEA=="
},
"Microsoft.Testing.Extensions.Telemetry": {
"type": "Transitive",
- "resolved": "2.3.2",
- "contentHash": "Q1iapTk1DwFFT9aPtv4wxJHe22++NLxsg7IekEujac9RDAugxGQdCN0SQ1b9ryF78cdidhSBB17pHdCANurOyQ==",
+ "resolved": "2.5.1",
+ "contentHash": "mu2iyoHovwl0q1mGeeRU0h8+LALXC7HqbxniLa1shTKYdJGl+KPoCEgjWIQ8MLzk1tlTGPOfg1JsxdH3RxhMCA==",
"dependencies": {
"Microsoft.ApplicationInsights": "2.23.0",
- "Microsoft.Testing.Platform": "2.3.2"
+ "Microsoft.Testing.Platform": "[2.5.1, 3.0.0)"
}
},
"Microsoft.Testing.Extensions.TrxReport.Abstractions": {
"type": "Transitive",
- "resolved": "2.3.2",
- "contentHash": "frw+Qa6gUxOZSw2Mw6SPtJT9gPzcP4nS9TfQhS0cHXKL6Rcp/CqLG+o4Psc1bHAhxW04rpzTBhjpNMnw2L7BuQ==",
+ "resolved": "2.5.1",
+ "contentHash": "DYTZAguaHz0wNJdHDTTGYOXtnlDoLoIbTMDKSApNNcytm55DJcnwpwELfQGLk5DB5QlgaEjNhnGo1Pu5QvL5VA==",
"dependencies": {
- "Microsoft.Testing.Platform": "2.3.2"
- }
- },
- "Microsoft.Testing.Extensions.VSTestBridge": {
- "type": "Transitive",
- "resolved": "2.3.2",
- "contentHash": "DXJIaLlwt+6GnPurlf7eVMI0wAZV5KCZrgGPibhx9i9LNxAkwEOK2jVzdVjLvvZ/SX9MUUaGJB9yXuF/VoT4/w==",
- "dependencies": {
- "Microsoft.TestPlatform.ObjectModel": "18.4.0",
- "Microsoft.Testing.Extensions.Telemetry": "2.3.2",
- "Microsoft.Testing.Extensions.TrxReport.Abstractions": "2.3.2",
- "Microsoft.Testing.Platform": "2.3.2"
+ "Microsoft.Testing.Platform": "[2.5.1, 3.0.0)"
}
},
"Microsoft.Testing.Platform": {
"type": "Transitive",
- "resolved": "2.3.2",
- "contentHash": "FuJgIEfNU+rFHJYGhuqA8uup+3cryJ1N67Tijqo01Jd5xAr28ptz0aXkFfSqK3MhAUmGsrPpgQ92+3+0oXv8AA=="
+ "resolved": "2.5.1",
+ "contentHash": "FAMaFFWnULW+hDHMb40Qzhcgz9cAU2/EtgRCBNX/DdQoKo0sPG2EiY+w7bQdl/BgHnf/DbpXLbf5Xy0o15M8NA=="
},
"Microsoft.Testing.Platform.MSBuild": {
"type": "Transitive",
- "resolved": "2.3.2",
- "contentHash": "guFvvaE8FGUlB6h24jN+P+NBz/P5x4On9sk4n5UapUAPq4fr0y1AgUe4sXmItp7r2NMe3rhZYLE1teP9T9sVbg==",
+ "resolved": "2.5.1",
+ "contentHash": "lYawcAwY+h76rQmpma2n0HaL8zkOFbbKapso0Eb+uOAUQn7333pIByLftEuiO67csAoZufHNMwi6PqhNemWQXA==",
"dependencies": {
- "Microsoft.Testing.Platform": "2.3.2"
+ "Microsoft.Testing.Platform": "[2.5.1, 3.0.0)"
}
},
"Microsoft.TestPlatform.ObjectModel": {
"type": "Transitive",
- "resolved": "18.4.0",
- "contentHash": "4L6m2kS2pY5uJ9cpeRxzW22opr6ttScIRqsOpMDQpgENp/ZwxkkQCcmc6LRSURo2dFaaSW5KVflQZvroiJ7Wzg=="
+ "resolved": "18.10.1",
+ "contentHash": "o+PuLDRVp1iwiVAPBADZItXgm9Ck23XtPhE4kZtZVi0uYnMiiz1Dx9Cjh75kJ+ijfqnORL3VOTOaQVKi0f/ixg=="
+ },
+ "Mono.Cecil": {
+ "type": "Transitive",
+ "resolved": "0.11.6",
+ "contentHash": "f33RkDtZO8VlGXCtmQIviOtxgnUdym9xx/b1p9h91CRGOsJFxCFOFK1FDbVt1OCf1aWwYejUFa2MOQyFWTFjbA=="
},
"MSTest.Analyzers": {
"type": "Transitive",
- "resolved": "4.3.2",
- "contentHash": "GNvrVI6/Y5pNoKnK1/VELBls3XiHNZaj+zh14LtwlCqFI8zXTW3vuBe0Jv2qEr9wxHlOAQQBTJPRoNRjneGrKQ=="
+ "resolved": "4.5.1",
+ "contentHash": "oa0w2QC/T3U+ulUn38AmbWE/wnEMtqSFRb2z277z5SpswqNc/ySWcAVlG1qEWUxzm+NztCjkoeLAn/83gIx3ug=="
},
"System.CodeDom": {
"type": "Transitive",
diff --git a/Solutions/Ais.Net.Models/Ais.Net.Models.csproj b/Solutions/Ais.Net.Models/Ais.Net.Models.csproj
index 1b7fb4c..9083c4f 100644
--- a/Solutions/Ais.Net.Models/Ais.Net.Models.csproj
+++ b/Solutions/Ais.Net.Models/Ais.Net.Models.csproj
@@ -1,12 +1,11 @@
-
+
net10.0
latest
enable
- True
true
@@ -25,16 +24,8 @@
-
- RCS1029;SA1313;SA1009;
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
diff --git a/Solutions/Directory.Build.props b/Solutions/Directory.Build.props
new file mode 100644
index 0000000..5922c8d
--- /dev/null
+++ b/Solutions/Directory.Build.props
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+ true
+ true
+
+
+ true
+
+
+
+
+ true
+ true
+
+
+
\ No newline at end of file
diff --git a/Solutions/Directory.Packages.props b/Solutions/Directory.Packages.props
index f446a11..011a7c2 100644
--- a/Solutions/Directory.Packages.props
+++ b/Solutions/Directory.Packages.props
@@ -6,11 +6,10 @@
-
-
+
diff --git a/Solutions/Endjin.Conventions.props b/Solutions/Endjin.Conventions.props
new file mode 100644
index 0000000..8e41dcc
--- /dev/null
+++ b/Solutions/Endjin.Conventions.props
@@ -0,0 +1,113 @@
+
+
+
+
+
+ Endjin Limited
+
+
+ $([System.DateTime]::UnixEpoch.AddSeconds($(SOURCE_DATE_EPOCH)).Year)
+ $([System.DateTime]::UtcNow.Year)
+ Copyright (c) Endjin Limited $(CopyrightYear). All rights reserved.
+
+
+
+
+ true
+ https://github.com/ais-dotnet/Ais.Net.Models
+ git
+
+
+ true
+ true
+ true
+ snupkg
+ true
+
+
+
+
+ PackageIcon.png
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+ true
+
+
+
+
+ true
+ true
+
+
+
+
+
+
+
+
diff --git a/Solutions/stylecop.json b/Solutions/stylecop.json
deleted file mode 100644
index 3739b8e..0000000
--- a/Solutions/stylecop.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- // Note: this file was added to your solution as a result of one or more projects using the Endjin.RecommendedPractices.Build.Common NuGet package.
- // You can edit this file (e.g., to remove these comments), and it will not be updated - the package just checks for its presence, and copies
- // this file. If you don't want this file (but you want to use the NuGet package that puts it here), add this setting to all projects
- // using Endjin.RecommendedPractices.Build.Common:
- // true
- // and then delete this file. That setting will prevent the package from recreating this file.
- "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
- "settings": {
- "documentationRules": {
- "companyName": "Endjin Limited"
- }
- }
-}
\ No newline at end of file
diff --git a/build.ps1 b/build.ps1
index bb95a74..20fbf4f 100644
--- a/build.ps1
+++ b/build.ps1
@@ -70,10 +70,10 @@ param (
[string] $ZfModulePath,
[Parameter()]
- [string] $ZfModuleVersion = "1.0.5",
+ [string] $ZfModuleVersion = "1.0.7",
[Parameter()]
- [version] $InvokeBuildModuleVersion = "5.12.1"
+ [version] $InvokeBuildModuleVersion = "5.14.23"
)
$ErrorActionPreference = 'Stop'
$here = Split-Path -Parent $PSCommandPath
diff --git a/global.json b/global.json
index cbef943..7ec0d2c 100644
--- a/global.json
+++ b/global.json
@@ -7,6 +7,6 @@
"runner": "Microsoft.Testing.Platform"
},
"msbuild-sdks": {
- "MSTest.Sdk": "4.3.2"
+ "MSTest.Sdk": "4.5.1"
}
}