Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,19 @@ updates:
- dependency-name: "*"
update-types:
- version-update:semver-major

- package-ecosystem: nuget
directory: /ports/dotnet
schedule:
interval: weekly
groups:
dotnet:
patterns:
- "*"
update-types:
- minor
- patch
ignore:
- dependency-name: "*"
update-types:
- version-update:semver-major
59 changes: 59 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,59 @@ jobs:
cd .sdist-test
../.sdist-venv/bin/pytest

dotnet:
name: .NET on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
defaults:
run:
working-directory: ports/dotnet
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5
with:
dotnet-version: |
8.0.x
10.0.x
- name: Restore with locked dependencies
run: dotnet restore --locked-mode
- name: Check formatting and code style
run: dotnet format --verify-no-changes --no-restore
- name: Build with warnings as errors
run: dotnet build --configuration Release --no-restore
- name: Test net8.0 and net10.0
run: dotnet test --configuration Release --no-build

dotnet-package:
name: .NET package
runs-on: ubuntu-latest
timeout-minutes: 20
defaults:
run:
working-directory: ports/dotnet
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5
with:
dotnet-version: |
8.0.x
10.0.x
- name: Restore with locked dependencies
run: dotnet restore --locked-mode
- name: Audit dependencies for known vulnerabilities
# NuGetAudit is enabled in ports/dotnet/Directory.Build.props; the
# explicit escalation keeps a new advisory from passing as a warning.
run: dotnet restore --locked-mode --no-cache "-warnaserror:NU1901;NU1902;NU1903;NU1904"
- name: Pack, inspect, and consume both packages in isolation
shell: pwsh
run: ./scripts/package-smoke.ps1

required:
name: Required checks
if: always()
Expand All @@ -152,6 +205,8 @@ jobs:
- go
- python
- python-package
- dotnet
- dotnet-package
runs-on: ubuntu-latest
steps:
- name: Require successful CI
Expand All @@ -161,9 +216,13 @@ jobs:
GO_RESULT: ${{ needs.go.result }}
PYTHON_RESULT: ${{ needs.python.result }}
PYTHON_PACKAGE_RESULT: ${{ needs.python-package.result }}
DOTNET_RESULT: ${{ needs.dotnet.result }}
DOTNET_PACKAGE_RESULT: ${{ needs.dotnet-package.result }}
run: |
test "$NODE_RESULT" = "success"
test "$BENCHMARK_RESULT" = "success"
test "$GO_RESULT" = "success"
test "$PYTHON_RESULT" = "success"
test "$PYTHON_PACKAGE_RESULT" = "success"
test "$DOTNET_RESULT" = "success"
test "$DOTNET_PACKAGE_RESULT" = "success"
27 changes: 26 additions & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,36 @@ permissions:

jobs:
analyze:
name: Analyze ${{ matrix.language }}
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
- language: javascript-typescript
build-mode: none
- language: python
build-mode: none
- language: csharp
build-mode: manual
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- if: matrix.language == 'csharp'
uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5
with:
dotnet-version: |
8.0.x
10.0.x
- uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4
with:
languages: javascript-typescript,python
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
- name: Build the .NET port
if: matrix.language == 'csharp'
working-directory: ports/dotnet
run: dotnet build --configuration Release
- name: Analyze
uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4
with:
category: /language:${{ matrix.language }}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Language-neutral protocol semantics and golden vectors are under
| TypeScript | 0.1 / 0.1.2 | Reference package with documented integrations |
| [Go](ports/go) | 0.1 / 0.1.2 | Independent conformant verifier and CLI; integrations not yet included |
| [Python](ports/python) | 0.1 / 0.1.2 | Independent conformant verifier and CLI; integrations not yet included |
| [.NET](ports/dotnet) | 0.1 / 0.1.2 | Independent conformant verifier and CLI for .NET 8 and .NET 10; integrations not yet included |

## Run the examples

Expand Down
121 changes: 121 additions & 0 deletions ports/dotnet/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Directory-scoped settings for the independent WorldCut .NET port.
# The repository root .editorconfig still applies to whitespace and encoding.

root = false

[*.{csproj,props,targets,config}]
indent_size = 2

[*.cs]
indent_size = 4

# --- Language and formatting conventions -------------------------------------

csharp_using_directive_placement = outside_namespace:error
csharp_style_namespace_declarations = file_scoped:error
csharp_prefer_braces = true:error
csharp_style_prefer_method_group_conversion = true:suggestion
csharp_style_var_for_built_in_types = false:silent
csharp_style_var_when_type_is_apparent = true:silent
csharp_style_var_elsewhere = false:silent
csharp_style_expression_bodied_methods = when_on_single_line:silent
csharp_style_expression_bodied_properties = when_on_single_line:silent
csharp_style_prefer_primary_constructors = false:silent

dotnet_sort_system_directives_first = true
dotnet_separate_import_directive_groups = false
dotnet_style_qualification_for_field = false:error
dotnet_style_qualification_for_property = false:error
dotnet_style_qualification_for_method = false:error
dotnet_style_qualification_for_event = false:error
dotnet_style_require_accessibility_modifiers = for_non_interface_members:error
dotnet_style_readonly_field = true:error
dotnet_style_predefined_type_for_locals_parameters_members = true:error
dotnet_style_predefined_type_for_member_access = true:error

dotnet_diagnostic.IDE0005.severity = error
dotnet_diagnostic.IDE0055.severity = error
dotnet_diagnostic.IDE0161.severity = error

# --- Naming ------------------------------------------------------------------
# Roslyn applies the first matching rule, so the const and static-readonly rules
# must precede the private instance-field rule.

dotnet_naming_rule.constant_fields_are_pascal_case.severity = error
dotnet_naming_rule.constant_fields_are_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_are_pascal_case.style = pascal_case

dotnet_naming_rule.static_readonly_fields_are_pascal_case.severity = error
dotnet_naming_rule.static_readonly_fields_are_pascal_case.symbols = static_readonly_fields
dotnet_naming_rule.static_readonly_fields_are_pascal_case.style = pascal_case

dotnet_naming_rule.private_fields_are_underscore_camel_case.severity = error
dotnet_naming_rule.private_fields_are_underscore_camel_case.symbols = private_fields
dotnet_naming_rule.private_fields_are_underscore_camel_case.style = underscore_camel_case

dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
dotnet_naming_symbols.constant_fields.required_modifiers = const

dotnet_naming_symbols.static_readonly_fields.applicable_kinds = field
dotnet_naming_symbols.static_readonly_fields.applicable_accessibilities = *
dotnet_naming_symbols.static_readonly_fields.required_modifiers = static,readonly

dotnet_naming_symbols.private_fields.applicable_kinds = field
dotnet_naming_symbols.private_fields.applicable_accessibilities = private
dotnet_naming_symbols.private_fields.required_modifiers =

dotnet_naming_style.pascal_case.capitalization = pascal_case

dotnet_naming_style.underscore_camel_case.capitalization = camel_case
dotnet_naming_style.underscore_camel_case.required_prefix = _

# --- Analyzer policy ---------------------------------------------------------
# `AnalysisLevel=latest-all` turns on every built-in analyzer. Each rule that is
# switched off below records why it does not apply to this port.

# The port is a small synchronous library with no logging abstraction, no async
# code, and no localization surface.
dotnet_diagnostic.CA1848.severity = none
dotnet_diagnostic.CA2007.severity = none
dotnet_diagnostic.CA1303.severity = none

# Protocol identifiers such as WORLDCUT_INVALID_INPUT and the JSON member names
# are fixed by spec/0.1 and must not be renamed for .NET naming heuristics.
dotnet_diagnostic.CA1707.severity = none

# The public surface exposes IReadOnlyList<T> rather than arrays; CA1002 targets
# mutable generic collections that this port never returns.
dotnet_diagnostic.CA1002.severity = none

# CA1812 flags internal types that the analyzer cannot see being constructed
# through reflection-free factory helpers used by this port.
dotnet_diagnostic.CA1812.severity = none

# JsonKind.String and JsonKind.Object name the JSON value shapes defined by
# RFC 8259 and used by every WorldCut port; CA1720's "contains type name"
# heuristic does not apply to a JSON kind enumeration.
dotnet_diagnostic.CA1720.severity = none

[Vendored/**/*.cs]
# Third-party source vendored verbatim from Jcs.NET 0.1.1 (MIT). A dedicated
# .editorconfig also lives next to that source; see
# ports/dotnet/THIRD-PARTY-NOTICES.md.
dotnet_analyzer_diagnostic.severity = none

[tests/**/*.cs]
# Test code is never a public library surface, so the API-hygiene rules below
# do not apply. Correctness rules stay on.
#
# CA1062: xUnit supplies theory arguments; null guards would be dead code.
# CA1508: several tests deliberately assert on comparisons the analyzer can
# prove, because proving them is the point of the test.
# CA2000: StringWriter holds no unmanaged resource and lives for one assertion.
# CA1861: constant argument arrays in assertions are intentional.
# CA5394: tests use a seeded System.Random for reproducible fuzzing, never for
# anything security relevant.
dotnet_diagnostic.CA1062.severity = none
dotnet_diagnostic.CA1508.severity = none
dotnet_diagnostic.CA2000.severity = none
dotnet_diagnostic.CA1861.severity = none
dotnet_diagnostic.CA5394.severity = none
8 changes: 8 additions & 0 deletions ports/dotnet/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
bin/
obj/
artifacts/
.local-feed/
.package-smoke/
.vs/
TestResults/
*.user
52 changes: 52 additions & 0 deletions ports/dotnet/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<Project>

<PropertyGroup>
<LangVersion>12.0</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<MSBuildTreatWarningsAsErrors>true</MSBuildTreatWarningsAsErrors>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<AnalysisLevel>latest-all</AnalysisLevel>
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn />
</PropertyGroup>

<!-- Deterministic, reproducible, source-linked builds. -->
<PropertyGroup>
<Deterministic>true</Deterministic>
<DebugType>portable</DebugType>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<ContinuousIntegrationBuild Condition="'$(CI)' == 'true' or '$(GITHUB_ACTIONS)' == 'true'">true</ContinuousIntegrationBuild>
</PropertyGroup>

<!-- Locked, audited restore. -->
<PropertyGroup>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<NuGetAudit>true</NuGetAudit>
<NuGetAuditMode>all</NuGetAuditMode>
<NuGetAuditLevel>low</NuGetAuditLevel>
</PropertyGroup>

<!-- Shared package metadata for the two publishable projects. -->
<PropertyGroup>
<Version>0.1.0</Version>
<Authors>Jason Doyle</Authors>
<Company>Jason Doyle</Company>
<Copyright>Copyright (c) 2026 Jason Doyle</Copyright>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/Jason-Doyle/WorldCut</PackageProjectUrl>
<RepositoryUrl>https://github.com/Jason-Doyle/WorldCut</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<PackageReadmeFile>README.md</PackageReadmeFile>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<PackageOutputPath>$(MSBuildThisFileDirectory)artifacts\package\</PackageOutputPath>
<IsPackable>false</IsPackable>
</PropertyGroup>

</Project>
18 changes: 18 additions & 0 deletions ports/dotnet/Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project>

<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
</PropertyGroup>

<!--
The WorldCut library and CLI have no third-party package dependencies.
Every version below is used only by the test project and is pinned exactly.
xunit.v3 runs on Microsoft.Testing.Platform, which is the supported
`dotnet test` path on the .NET 10 SDK.
-->
<ItemGroup>
<PackageVersion Include="xunit.v3" Version="4.0.0" />
</ItemGroup>

</Project>
17 changes: 17 additions & 0 deletions ports/dotnet/NuGet.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!--
Restore for this port resolves from nuget.org only. Clearing inherited
sources keeps `dotnet restore` in locked mode reproducible on developer
machines that configure additional feeds globally.
-->
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
</packageSources>
<packageSourceMapping>
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
</packageSourceMapping>
</configuration>
Loading
Loading