Skip to content

feat: accept Filtered.Types selections as dependency targets for architecture rules#325

Merged
vbreuss merged 7 commits into
mainfrom
feature/architecture-rules-filtered-types-targets
Jun 6, 2026
Merged

feat: accept Filtered.Types selections as dependency targets for architecture rules#325
vbreuss merged 7 commits into
mainfrom
feature/architecture-rules-filtered-types-targets

Conversation

@vbreuss

@vbreuss vbreuss commented Jun 5, 2026

Copy link
Copy Markdown
Member

A reusable Filtered.Types selection (a "layer") can now act as a dependency target alongside the namespace and specific-type forms:

  • ThatType: DependsOn / DoesNotDependOn / DependsOnlyOn(Filtered.Types target, params Filtered.Types[] additional)
  • ThatTypes: DependOn / DoNotDependOn / DependOnlyOn (IEnumerable and IAsyncEnumerable subjects)
  • TypeFilters: WhichDependOn / WhichDoNotDependOn / WhichDependOnlyOn
  • All results and the filter result chain with OrOn(params Filtered.Types[]) to widen the targeted/allowed selections (Or is the inherited AndOrResult property and must not be hidden).

Each target selection is resolved once per assertion into the union set; membership is by type identity, with a generic type definition in the set matching any of its constructions. The only-on family keeps the own-namespace allowance and the framework rule, so an empty selection allows exactly the own namespace and framework dependencies. All dependency resolution still goes through TypeHelpers.ResolveDependencies, so a customized resolver applies automatically.

The first target is a regular parameter instead of params, because a pure params Filtered.Types[] overload would make the existing zero-argument calls (e.g. DependsOn()) ambiguous with the params IEnumerable namespace overloads (CS0121); this also enforces "at least one target" at compile time.

The README gains an "Architecture rules" section documenting the pattern: layers as reusable selections, combining rules with Expect.ThatAll, the aggregated failure shape, and exemptions via the Except filter.

@vbreuss vbreuss self-assigned this Jun 5, 2026
@vbreuss vbreuss added the enhancement New feature or request label Jun 5, 2026
@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

Test Results

    13 files  ±  0      13 suites  ±0   10m 13s ⏱️ +4s
 6 392 tests + 54   6 389 ✅ + 54   3 💤 ±0  0 ❌ ±0 
38 197 runs  +324  38 184 ✅ +324  13 💤 ±0  0 ❌ ±0 

Results for commit b83cc5f. ± Comparison against base commit bb37d17.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

🚀 Benchmark Results

Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 9V74 2.60GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.300
[Host] : .NET 10.0.8 (10.0.8, 10.0.826.23019), X64 RyuJIT x86-64-v3
DefaultJob : .NET 10.0.8 (10.0.8, 10.0.826.23019), X64 RyuJIT x86-64-v3

Method Mean Error StdDev Gen0 Allocated
TypeIsNotStatic_aweXpect 236.0 ns 3.03 ns 2.83 ns 0.0386 648 B

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

👽 Mutation Results

Mutation testing badge

aweXpect.Reflection

Details
File Score Killed Survived Timeout No Coverage Ignored Compile Errors Total Detected Total Undetected Total Mutants
Collections/Filtered.Types.cs 87.18% 32 2 2 3 19 8 34 5 66
Filters/TypeFilters.WhichDependOn.cs 57.14% 4 0 0 3 1 0 4 3 8
Filters/TypeFilters.WhichDependOnlyOn.cs 50.00% 2 0 0 2 1 0 2 2 5
Helpers/TypeHelpers.cs 82.29% 438 67 8 29 182 64 446 96 788
Options/TypeSetDependencyOptions.cs 82.76% 21 3 3 2 11 3 24 5 43
Results/TypeSetDependencyOnlyOnResult.cs 100.00% 2 0 0 0 2 0 2 0 4
Results/TypeSetDependencyResult.cs 100.00% 1 0 0 0 1 0 1 0 2
ThatType.DependsOn.cs 86.54% 45 5 0 2 7 24 45 7 83
ThatType.DependsOnlyOn.cs 73.08% 18 1 1 6 4 18 19 7 48
ThatTypes.DependOn.cs 64.81% 34 0 1 19 8 32 35 19 94
ThatTypes.DependOnlyOn.cs 56.25% 18 2 0 12 6 16 18 14 54

The final mutation score is 79.95%

Coverage Thresholds: high:80 low:60 break:0

@vbreuss vbreuss force-pushed the feature/architecture-rules-filtered-types-targets branch 2 times, most recently from 0f82606 to fcedf25 Compare June 6, 2026 01:54
vbreuss added 4 commits June 6, 2026 04:26
…itecture rules

A reusable Filtered.Types selection (a "layer") can now act as a dependency
target alongside the namespace and specific-type forms:

- ThatType: DependsOn / DoesNotDependOn / DependsOnlyOn(Filtered.Types target,
  params Filtered.Types[] additional)
- ThatTypes: DependOn / DoNotDependOn / DependOnlyOn (IEnumerable and
  IAsyncEnumerable subjects)
- TypeFilters: WhichDependOn / WhichDoNotDependOn / WhichDependOnlyOn
- All results and the filter result chain with OrOn(params Filtered.Types[])
  to widen the targeted/allowed selections (Or is the inherited
  AndOrResult property and must not be hidden).

Each target selection is resolved once per assertion into the union set;
membership is by type identity, with a generic type definition in the set
matching any of its constructions. The only-on family keeps the own-namespace
allowance and the framework rule, so an empty selection allows exactly the
own namespace and framework dependencies. All dependency resolution still
goes through TypeHelpers.ResolveDependencies, so a customized resolver
applies automatically.

The first target is a regular parameter instead of params, because a pure
params Filtered.Types[] overload would make the existing zero-argument
calls (e.g. DependsOn()) ambiguous with the params IEnumerable<string>
namespace overloads (CS0121); this also enforces "at least one target" at
compile time.

The README gains an "Architecture rules" section documenting the pattern:
layers as reusable selections, combining rules with Expect.ThatAll, the
aggregated failure shape, and exemptions via the Except filter.
- Normalize the resolved target set via the shared StripElementTypes, so
  array/by-ref/pointer types in a target selection match their element
  type, mirroring the specific-type overloads (an array target in
  DoesNotDependOn no longer passes silently).
- Report type-set violations deduplicated by type identity and qualify
  distinct violators sharing a simple name with their namespace, so they
  no longer collapse into one indistinguishable entry.
- Validate widening targets fully before mutating the shared options and
  report the actual parameter name of the caller (additional/targets).
- Share the violation-collection core and the framework/own-namespace
  exemption predicate between the namespace-based and type-set-based
  helpers, so the two families cannot drift apart.
- Factor the null-item predicates of the type-set collection constraints
  into static helpers, mirroring the namespace-based siblings.
- DependsOnlyOn/DependOnlyOn/WhichDependOnlyOn with Filtered.Types targets
  return new only-on results exposing ExcludingOwnSubNamespaces, mirroring
  the namespace family (the own-sub-namespace exemption was hard-coded)
- TypeSetDependencyOptions.Resolve returns a ResolvedTypeSet that performs
  all matching, so matching against an unresolved target set is
  unrepresentable; the assertion CancellationToken is forwarded
- share the constructed-generic matching rule between MatchesType and the
  type-set matcher via TypeHelpers.GetGenericTypeDefinitionOfConstruction
- parenthesize the target description in the type-set filter suffixes, so
  the target scope no longer runs into the subject collection scope
- drop a provably dead Distinct() in GetDependencyTypeSetViolations
- make all WhichDependOn/WhichDoNotDependOn/DependOn/DoNotDependOn
  overloads adjacent (Sonar S4136)
- README: promote type dependencies and architecture rules into their own
  top-level section and avoid em-dashes
…les'

Updated section headers for clarity and consistency.
@vbreuss vbreuss force-pushed the feature/architecture-rules-filtered-types-targets branch from b83cc5f to 8404108 Compare June 6, 2026 02:31
@vbreuss vbreuss enabled auto-merge (squash) June 6, 2026 02:37
@sonarqubecloud

sonarqubecloud Bot commented Jun 6, 2026

Copy link
Copy Markdown

@vbreuss vbreuss disabled auto-merge June 6, 2026 02:41
@vbreuss vbreuss merged commit 9a8b7c1 into main Jun 6, 2026
10 checks passed
@vbreuss vbreuss deleted the feature/architecture-rules-filtered-types-targets branch June 6, 2026 02:42
@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown

This is addressed in release v2.0.0.

@github-actions github-actions Bot added the state: released The issue is released label Jun 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request state: released The issue is released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant