-
Notifications
You must be signed in to change notification settings - Fork 81
Comparing changes
Open a pull request
base repository: TNG/ArchUnitNET
base: main
head repository: TNG/ArchUnitNET
compare: refactor-slice-implemenation
- 10 commits
- 75 files changed
- 1 contributor
Commits on Aug 14, 2026
-
test: move slice fixtures into a dedicated SlicesTestAssembly
The slice tests shared TestAssembly with the rest of the suite, which meant their namespace layout could not be changed without disturbing unrelated tests, and it offered no way to express the namespace shapes slice patterns need to be tested against. Add TestAssemblies/SlicesTestAssembly, mirroring the other purpose-built test assemblies, with one folder per scenario: DirectCircle two slices depending on each other SubnamespaceCircle a cycle that only appears when sub-namespaces are folded into their parent slice (see #208) MultipleSubnamespaces slices nested up to three levels deep DuplicatePrefix a namespace whose last segment repeats its parent DotDotSemantics namespace shapes that distinguish a ".." matching whole segments from one matching within a segment No production code changes. The expectations in SlicesTests are the current implementation's, adjusted only for the new fixture: MultipleSubnamespaces has nine namespaces where TestAssembly.Slices had seven, and Slice3 now has four sub-namespaces rather than two.Configuration menu - View commit details
-
Copy full SHA for 786b4d7 - Browse repository at this point
Copy the full SHA 786b4d7View commit details -
test: pin current slice rule and PlantUML diagram behaviour
The slice pattern matcher is about to be reimplemented. Before touching it, capture what it does today so that each following commit shows its own effect as a test diff rather than leaving the reader to infer it. No production code changes; the expectations below are the current behaviour, warts included: - Everything after the first "(*" is discarded, so "(*)", "(*)..", "(*).(*)" and "(*)..(*)" all produce the same nine slices, a trailing literal such as "(**).Service.." matches nothing, and alternation is not supported at all. - A leading ".." is likewise ignored: the prefix is matched with Contains. - ".." may match within a namespace segment, so "(*)..Service" matches the single segment "AlphaService" as well as "Alpha.Service". - Patterns are validated per type while the slices are enumerated, so an invalid pattern raises nothing until the result is consumed. - Matching (unlike MatchingWithPackages) leaves a slice without a namespace prefix, which PlantUmlSlice.BuildStringC4Style dereferences unconditionally -- pinned as the NullReferenceException it currently throws. PlantUmlSliceDiagramSnapshotTests now covers every combination of pattern and rendering mode: plain and with packages, single and double asterisk, multiple and non-contiguous capture groups, LimitDependencies, C4Style and focus-on.Configuration menu - View commit details
-
Copy full SHA for 2d6be8a - Browse repository at this point
Copy the full SHA 2d6be8aView commit details -
feat: match slice patterns with regex like ArchUnit
Slice patterns were matched by string surgery: the pattern was split at the first "(*", and everything after it was discarded and replaced with "(**).". Every pattern therefore behaved as if it ended in a greedy capture, so "(*)", "(*)..", "(*).(*)" and "(*)..(*)" all produced the same nine slices, a trailing literal such as "(**).Service.." matched nothing, and alternation was ignored outright. Convert the pattern to a regular expression instead, porting PackageMatcher.convertToRegex from ArchUnit. "(*)" now captures exactly one namespace segment, "(**)" one or more, "*" matches a segment without capturing it, ".." skips segments, and "[A|B]" alternates. Pattern validation moves from the per-type assignment callback to Matching/MatchingWithPackages, so a malformed pattern is rejected where it is written rather than on the first type that happens to be checked. The "must contain (*) or (**)" check is deliberately last: a pattern that is malformed *and* has no capture group should report the specific problem. Only the first capture group names a slice for now; patterns with several groups are completed in a later commit. Visible in the tests: - "SubnamespaceCircle.(*).." now folds Slice2.Inner into Slice2 and so reports the cycle Slice1 -> Slice2 -> Slice1 (issue #208). It used to give Inner a slice of its own and see no cycle. - "MultipleSubnamespaces.(**).." no longer drops the top-level classes, so it now sees the Slice3 -> Slice1 edge that closes the loop. - ".." can still match empty in the middle of a segment, which splits "AlphaService" into "AlphaServic" + "e" and merges "Alpha.Service" with "AlphaService". The regex is ported faithfully, including this defect; it is pinned in DotDot_* and fixed separately.
Configuration menu - View commit details
-
Copy full SHA for 78f6fa2 - Browse repository at this point
Copy the full SHA 78f6fa2View commit details -
refactor: remove CountOfAsteriskInPattern from Slice and SliceIdentifier
The old string-surgery matcher could produce slice names containing dots even for a pattern made only of "(*)" groups, because it discarded everything after the first group and matched greedily. PlantUmlFileBuilder compensated with RemovePatternInappropriateSlices, which counted the dots in a slice name and dropped every slice with at least as many dots as the pattern had "(*)" groups. Now that "(*)" expands to \w+, a captured part can never contain a dot, so that filter can no longer remove anything: the dot count of a slice name minus the dot count of its namespace prefix is always zero, and the pattern always has at least one group. Remove the filter along with the CountOfAsteriskInPattern it consumed. BREAKING CHANGE: Slice.CountOfAsteriskInPattern, SliceIdentifier.CountOfAsteriskInPattern and the countOfAsteriskInPattern parameter of SliceIdentifier.Of are gone. Callers of SliceIdentifier.Of that passed a namespace positionally need to drop the middle argument.
Configuration menu - View commit details
-
Copy full SHA for b58b016 - Browse repository at this point
Copy the full SHA b58b016View commit details -
fix: base Slice equality on the identifier alone
Slice.Equals also compared Types, and IEnumerable<IType> has reference equality, so two slices built from the same identifier over equal but distinct sequences compared as different. A slice is defined by its identifier -- the types are derived from it -- so comparing them adds nothing but the reference-identity trap. This matters because PlantUmlFileBuilder calls slices.Distinct() and the freeze store deduplicates violations by slice.
Configuration menu - View commit details
-
Copy full SHA for 8419132 - Browse repository at this point
Copy the full SHA 8419132View commit details -
feat: support multiple capture groups in slice patterns
Only the first capture group named a slice, so "App.(*).(*)" grouped "App.Foo.Bar" and "App.Foo.Baz" into a single slice called "Foo" and the second group was silently ignored. Keep every captured group instead. SliceIdentifier now holds the parts as a list and compares them element-wise, so two identifiers belong to the same slice exactly when they captured the same parts in the same order -- "Foo" (one part) and ["Foo", "Bar"] are different slices even though the first parts match. The parts are joined with "." into a single name. A slice has to have one name, not two: PlantUML component aliases may not contain whitespace, and the exporter splits the name on "." to nest package blocks, so anything else would leave failure messages, the freeze store and the diagrams disagreeing about what a slice is called. Dots are also what "(**)" already produces, so "App.(*).(*)" and "App.(**)" now name the same grouping the same way. Note that upstream ArchUnit joins with " - " instead. It can afford to because it offers namingSlices("$1.$2") to override the default; ArchUnitNET has no such API yet, so its default has to stand on its own.Configuration menu - View commit details
-
Copy full SHA for 75253a3 - Browse repository at this point
Copy the full SHA 75253a3View commit details -
fix: make .. in slice patterns match whole namespace segments
".." is documented as "zero or more namespace segments", but the regex ported from ArchUnit's PackageMatcher.TWO_DOTS_REGEX, (?:(?:^\w*)?\.(?:\w+\.)*(?:\w*$)?)? is optional as a whole and brings its own dots, so it also matches the empty string in the middle of a segment. Three consequences: App.(*)..(*) on App.Slice3 captured ["Slice", "3"] App.(*)..Serv on App.MyServ captured ["My"] App.(*)..(*) on App.Single captured ["Singl", "e"] None of those are namespace segments; the pattern silently invented a boundary inside a name. Expand ".." depending on where it sits in the pattern instead, so the separating dot is always consumed: leading (?:\w+\.)* skip whole leading segments trailing (?:\.\w+)* skip whole trailing segments inner \.(?:\w+\.)* the separating dot, then whole segments The expansion stays greedy, matching the behaviour released so far for every single-capture pattern; only the mid-segment matches disappear. The deviation from upstream is recorded on the method. Visible in the tests: the DotDotSemantics fixture stops splitting "AlphaService" and "Single", and the non-contiguous PlantUML diagrams lose their bogus "Slice.1"/"Slice.2"/"Slice.3" components.Configuration menu - View commit details
-
Copy full SHA for 7b5cb17 - Browse repository at this point
Copy the full SHA 7b5cb17View commit details -
fix: do not nest PlantUML packages for slices that are not namespace …
…paths PlantUmlSlice splits a slice name on "." to build nested package blocks, which only tells the truth when the name really is the namespace path of everything inside the slice. A pattern with ".." between two capture groups drops the segments in between: "App.(*)..(*)" names the types in "App.Slice3.Group1.Inner" "App.Slice3.Inner", and the diagram then drew "Inner" as a sibling of "Group1" -- inverting a containment relation the same diagram shows correctly one level up, and claiming a namespace that does not exist. Check that every type in the slice actually lives at or below the slice name before nesting it, and draw it as one flat, fully qualified component otherwise. The slice's own NameSpace is untouched, so IsPackage, the focus-on checks and the LimitDependencies branch are unaffected. Three defects on paths this newly exercises, all older than this branch: - PlantUmlSlice.BuildStringC4Style had no return in its "no namespace" branch and dereferenced the namespace on the next line. Any C4Style diagram built from Matching (rather than MatchingWithPackages) slices threw a NullReferenceException. The test that pinned the throw becomes a real snapshot. - A capture group at position 0 (e.g. MatchingWithPackages("(*)..")) gave the slice an empty namespace rather than none, and BuildString then called "".Remove(-1). Report no namespace instead. - OneToOneIfSameParentNamespace wrote component names bare where every other arrow brackets them, so "[a] --|> [b]" came out as "a --|> b". That happens to parse while a name is a plain identifier and stops as soon as one is not. Its two mixed component/package arrows had the same problem and no test at all; both are now covered. Also fills the last hole in the diagram matrix, LimitDependencies over a non-contiguous pattern.Configuration menu - View commit details
-
Copy full SHA for e05db0a - Browse repository at this point
Copy the full SHA e05db0aView commit details -
feat: name slices after the pattern text between their capture groups
Joining the captured parts with "." made a slice name read as a namespace even when it was not one. "App.(*)..(*)" named the types in "App.Slice3.Group1.Inner" the slice "Slice3.Inner", which is a namespace that does not exist, and "App.(*).Service.(*)" dropped the "Service" segment from "Orders.Service.Http" and called the slice "Orders.Http". The exporter already refuses to nest such names, but a rule message or a freeze entry showed them with nothing to say they were not paths. Build the name from the pattern instead: take the pattern text from the first capture group to the last and substitute what each group captured. The separators come from the pattern rather than from the match, so every type a pattern groups together still gets the same name. App.(*).(*) Orders.Http unchanged App.(*).Service.(*) Orders.Service.Http was Orders.Http App.(*)..(*) Orders..Http was Orders.Http App.(*).*.(*) Orders.*.Http was Orders.Http Text before the first group and after the last one selects which types belong to a slice rather than naming it, so it stays out -- that is what keeps "App.(*)" naming a slice "Orders" and not "App.Orders", and it means every single-capture pattern keeps exactly the name it has today. Alternations become "*": a PlantUML name may not contain "[" or "]", and which alternative matched is no more part of a slice's identity than which segment "*" matched.
Configuration menu - View commit details
-
Copy full SHA for 12b1926 - Browse repository at this point
Copy the full SHA 12b1926View commit details -
docs: document slice rules and pattern syntax
The slice API had almost no XML documentation, and the guide covered slices only as a one-paragraph "Cycle Rule" that did not say what a pattern may contain or what a slice ends up being called. Document every public type under Fluent/Slices and the two domain types, and rewrite guide.md 3.6 as "Slice Rules" with the pattern token table, the naming rules and the two available conditions. Note in 5.4 which patterns nest in a diagram and which do not. No behaviour change; the only non-comment edit is a missing semicolon in the focus-on example in 5.6.
Configuration menu - View commit details
-
Copy full SHA for 06d08a4 - Browse repository at this point
Copy the full SHA 06d08a4View commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff main...refactor-slice-implemenation