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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @framinosona
120 changes: 120 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# GitHub Copilot Instructions for Plugin.BaseTypeExtensions

## Project Overview

**Plugin.BaseTypeExtensions** is a collection of extension methods for .NET base types —
strings, numerics, enums, collections, dates/times, comparables, reflection, and a handful of
other primitives — aimed at productivity, type safety, and readability in modern .NET
applications.

**Key Features:**
- Null-safe string operations and character manipulation
- Generic numeric operations for all `INumber<T>` types (angles, percentages, clamping)
- Enum flag manipulation, description retrieval, and general enum utilities
- Dictionary/list/enumerable extensions, including synchronization-aware variants
- `DateTime`/`DateOnly`/`TimeOnly`/`TimeSpan` utilities
- Reflection and assembly helpers (type discovery, attribute scanning, embedded resources)
- `IComparable<T>` extensions plus standalone `ComparableTools`/`NumericRangeTools` helpers
- Smaller extensions for `Byte`, `Guid`, `Version`, `Uri`, `Stream`, `Task`, `TaskCompletionSource`,
`CancellationToken`, `SemaphoreSlim`, `Random`, `Exception`

## Technology Stack

- **Framework:** .NET 9.0 (SDK `9.0.305`, see `global.json`)
- **Language:** C# (latest)
- **Testing:** xUnit + FluentAssertions (v7.x — stays open source indefinitely per Directory.Packages.props comment)
- **Package Management:** Central Package Management (`Directory.Packages.props`)
- **CI/CD:** GitHub Actions
- **Documentation:** DocFX (`Plugin.BaseTypeExtensions.Docs/`, published to GitHub Pages)

## Project Structure

```
Plugin.BaseTypeExtensions/
├── .github/
│ ├── workflows/ci.yml
│ └── copilot-instructions.md # This file
├── Plugin.BaseTypeExtensions/ # Main library — one file per extended type/category
│ ├── StringExtensions.cs
│ ├── NumericExtensions.cs / NumericRangeTools.cs
│ ├── EnumExtensions.cs
│ ├── DictionaryExtensions.cs / ListExtensions.cs / EnumerableExtensions.cs
│ ├── ConcurrentDictionaryExtensions.cs / SemaphoreSlimExtensions.cs
│ ├── DateTimeExtensions.cs / DateOnlyExtensions.cs / TimeOnlyExtensions.cs / TimeSpanExtensions.cs
│ ├── ComparableExtensions.cs / ComparableTools.cs
│ ├── ReflectionExtensions.cs / AssemblyExtensions.cs
│ ├── ByteExtensions.cs / GuidExtensions.cs / VersionExtensions.cs / UriExtensions.cs / StreamExtensions.cs
│ ├── TaskExtensions.cs / TaskCompletionSourceExtensions.cs / CancellationTokenExtensions.cs
│ ├── RandomExtensions.cs / ExceptionExtensions.cs
├── Plugin.BaseTypeExtensions.Tests/ # xUnit tests, one file per source file
└── Plugin.BaseTypeExtensions.Docs/ # DocFX documentation site
```

## Development Setup

### Prerequisites
- .NET SDK 9.0.305 or later (see `global.json`)

### Build Commands
```bash
dotnet restore Plugin.BaseTypeExtensions.slnx
dotnet build Plugin.BaseTypeExtensions.slnx --configuration Release --no-restore
dotnet test Plugin.BaseTypeExtensions.Tests/Plugin.BaseTypeExtensions.Tests.csproj --configuration Release --no-build
```

## Code Organization Patterns

- **One file per extended type or tightly-related group** — `*Extensions.cs`, named after the
type it extends (e.g. `StringExtensions.cs`). Don't mix categories in one file.
- **Generic numeric code uses `INumber<T>`** constraints instead of per-type overloads.
- **Standalone helpers that don't read naturally as extension methods** (e.g. clamping across a
pair of bounds) live in `ComparableTools`/`NumericRangeTools` as static classes — keep that
separation rather than bolting them onto `ComparableExtensions`/`NumericExtensions`.

## Coding Standards

### Naming Conventions (enforced by `.editorconfig`)
- Classes/structs/interfaces/methods/properties/constants: PascalCase
- Private fields: `_camelCase`
- Parameters/locals: camelCase

### Style Guidelines
- Line length: max 240 characters; indentation: 4 spaces; line endings: LF
- Prefer `var` when the type is apparent
- Braces always required, even for single-line statements
- `System` usings first, separated from the rest

### Documentation Requirements
- XML docs (`<summary>`, `<param>`, `<returns>`, `<exception>`) required on all public APIs

## Testing Guidelines

- **Framework:** xUnit, assertions via FluentAssertions (v7.2.2, open-source)
- **File naming:** `{ClassName}Tests.cs`, matching the source file
- **Test naming:** `MethodName_Scenario_ExpectedBehavior`
- Cover success paths, failure paths, and boundary conditions (null, empty, min/max values)
- Use `[Theory]`/`[InlineData]` for multiple similar cases; keep tests independent of each other

## Dependencies

### Production
- `Microsoft.Extensions.Logging.Abstractions` (10.0.11)
### Development
- `xunit` (2.9.3), `xunit.runner.visualstudio` (4.0.0), `FluentAssertions` (7.2.2)
- `coverlet.collector` / `coverlet.msbuild` (10.0.1)
- `Microsoft.NET.Test.Sdk` (18.9.0), `JetBrains.Annotations` (2025.2.0)
- `Microsoft.CodeAnalysis.NetAnalyzers` (10.0.400), `Microsoft.SourceLink.GitHub` (10.0.201)

(Versions drift via Dependabot — check `Directory.Packages.props` for current values rather than
trusting this list long-term.)

## CI/CD Pipeline

`ci.yml` runs: version generation → build/test/package → publish test artifacts → DocFX build and
deploy to GitHub Pages → publish to NuGet.org (on `main`) → tag & GitHub release.

## Useful Resources

- **Repository:** https://github.com/laerdal/Plugin.BaseTypeExtensions
- **NuGet Package:** https://www.nuget.org/packages/Plugin.BaseTypeExtensions
- **Documentation:** https://laerdal.github.io/Plugin.BaseTypeExtensions/
50 changes: 50 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
## Summary

Describe the change in 2-6 lines.

## Why

Explain the reason for this change.

## Change Type

- [ ] Feature
- [ ] Bug fix
- [ ] Refactor
- [ ] Docs only
- [ ] CI/build/tooling

## Affected Areas

- [ ] String / Numeric / Enum extensions
- [ ] Collection extensions (Dictionary / List / Enumerable / ConcurrentDictionary)
- [ ] Temporal extensions (DateTime / DateOnly / TimeOnly / TimeSpan)
- [ ] Reflection / Assembly extensions
- [ ] Comparison extensions
- [ ] Tests
- [ ] Docs

## Behavior And Compatibility

- [ ] Public API changed
- [ ] Exception behavior changed
- [ ] No externally visible behavior change

If any box above is checked, describe impact:

## Tests

- [ ] Unit tests added/updated
- [ ] Not applicable (explain)

## Documentation

- [ ] README feature list updated
- [ ] XML docs added/updated
- [ ] Not applicable (explain)

## Checklist

- [ ] Commit messages follow Conventional Commits (`type(scope): subject`)
- [ ] CI passes
- [ ] Change is scoped to one logical unit of work
36 changes: 36 additions & 0 deletions .github/skills/code-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
name: code-review
description: Use for reviewing pull requests on Plugin.BaseTypeExtensions — checks file-per-category organization, generic numeric constraints, and null/boundary safety on new extension methods.
---

# Code Review — Plugin.BaseTypeExtensions

## Checklist for new or changed extension methods

- [ ] **One file per extended type/category**: a new extension method belongs in the
`*Extensions.cs` file named after the type it extends (e.g. a new `DateTime` helper goes in
`DateTimeExtensions.cs`, not bundled into an unrelated file). A PR mixing categories into
one file, or adding a same-named method to two files, is a real finding.
- [ ] **Generic numeric code uses `INumber<T>`**: new numeric operations should use generic math
constraints rather than adding per-type overloads (`int`, `double`, `float`, ...) — flag
copy-pasted overloads as a sign the generic constraint was skipped.
- [ ] **Null/boundary safety**: string, collection, and comparable extensions handle `null`
input explicitly (per this library's "null-safe" positioning) rather than throwing an
unhandled `NullReferenceException`.
- [ ] **Standalone helpers stay standalone**: logic that doesn't read naturally as an extension
method (e.g. clamping across a pair of bounds) belongs in `ComparableTools`/
`NumericRangeTools` as static helpers — don't bolt it onto `ComparableExtensions`/
`NumericExtensions` as an awkward extension method just to keep the "everything is an
extension" pattern.
- [ ] **XML docs**: new public members have accurate `<summary>`/`<param>`/`<returns>`/
`<exception>` docs.
- [ ] **README feature list**: a new extension category should be reflected there.

## What to flag as a real risk, not a nit

- A new extension method that duplicates behavior already available in `System.Linq` or the
BCL without a clear reason (this library's value is filling *gaps*, not re-wrapping existing
APIs).
- Breaking changes to existing extension method signatures — this is a published NuGet package
consumed by other repos in this org (e.g. `Plugin.ExceptionListeners`), so a signature change
is a semver-relevant, not a routine tweak.
55 changes: 55 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Contributor Covenant Code of Conduct

## Our Pledge

We as members, contributors, and leaders pledge to make participation in our community a
harassment-free experience for everyone, regardless of age, body size, visible or invisible
disability, ethnicity, sex characteristics, gender identity and expression, level of experience,
education, socio-economic status, nationality, personal appearance, race, religion, or sexual
identity and orientation.

We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive,
and healthy community.

## Our Standards

Examples of behavior that contributes to a positive environment include:

- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes, and learning from
the experience
- Focusing on what is best not just for us as individuals, but for the overall community

Examples of unacceptable behavior include:

- The use of sexualized language or imagery, and sexual attention or advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email address, without their
explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting

## Enforcement Responsibilities

Maintainers are responsible for clarifying and enforcing standards of acceptable behavior and
will take appropriate and fair corrective action in response to any behavior deemed
inappropriate, threatening, offensive, or harmful.

## Scope

This Code of Conduct applies within all community spaces for this project, and also applies when
an individual is officially representing the project in public spaces.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the
maintainer, [@framinosona](https://github.com/framinosona), via the contact details listed on
their GitHub profile. All complaints will be reviewed and investigated promptly and fairly.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org),
version 2.1, available at
https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
35 changes: 35 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Contributing

## Branching

Work off a short-lived feature branch cut from `main`. Open a PR early and mark it as a Draft
if it's still in progress.

## Commit convention

This repo uses [Conventional Commits](https://www.conventionalcommits.org/): `type(scope): subject`,
imperative mood, <= 72 characters. Common types: `feat`, `fix`, `docs`, `style`, `refactor`,
`perf`, `test`, `chore`. Scope is optional but recommended (e.g. the extension category touched).

## Pull requests

Fill out the PR template. Keep each PR scoped to one logical change. CI must pass before merge.

## Code style

Follow this repo's `.editorconfig`. Prefer clarity over cleverness; avoid unnecessary abstraction
— this is a firm preference, not a suggestion. Keep each extension category in its own
`*Extensions.cs` file named after the type it extends (e.g. `StringExtensions.cs`,
`DateTimeExtensions.cs`) — don't mix categories in one file. See
`.github/copilot-instructions.md` for the existing conventions.

## Testing

All new functionality needs xUnit tests in `Plugin.BaseTypeExtensions.Tests`, using
FluentAssertions for assertions. Test both success and failure paths and boundary conditions
(null, empty, min/max values).

## Documentation

Public APIs need XML doc comments (`<summary>`, `<param>`, `<returns>`, `<exception>`). If you
add a new extension category, update the README's feature list too.
13 changes: 13 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Security Policy

## Reporting a Vulnerability

Please report security vulnerabilities privately using
[GitHub's private vulnerability reporting](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability)
(Security tab → "Report a vulnerability") rather than opening a public issue.

We'll acknowledge reports as soon as possible and coordinate disclosure once a fix is available.

## Supported Versions

Only the latest published release is actively supported.
Loading