refactor(e10): move the platform components into components/ui/ and enforce the boundary
The app HAS a platform layer -- AnchoredPopover (22 importers, with arrows/typeahead/Escape/anchor-flip), QueryState (21), Modal (17), PageShell, DataTable, Tabs, Tooltip and ~26 more -- but it sat flat among ~160 feature components with nothing marking it as one. Several of those files describe themselves as 'the one place' or 'canonical' and were still bypassed by hand-rolled markup, because a layer nobody can see is a layer nobody uses; three separate inventory passes of this codebase misread it the same way. Moves the 33 domain-free modules into components/ui/, rewrites the imports in 89 files, and makes the boundary a lint rule rather than a convention: inside ui/ a one-level-up import (a feature component) and any lib/api slice are errors. The rule was verified to fire on both and to leave generic lib/ helpers alone. README.md states which side of the line a component belongs on and why. No behaviour change: 3x tsc, eslint, knip, prettier and 687 vitest tests all green; no backend file touched.
This commit is contained in:
@@ -67,5 +67,34 @@ export default tseslint.config(
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
// E10 S1: `components/ui/` is the PLATFORM layer, and the rule that makes it a layer rather than
|
||||
// a folder is enforced here, not in prose (see components/ui/README.md). A platform component is
|
||||
// domain-free: it may import sibling primitives and generic `lib/` helpers, never a feature
|
||||
// component (`../Feed`) and never a domain API slice. Without this rule the boundary erodes on
|
||||
// the first "just this once" import and the directory silently becomes another components/.
|
||||
files: ["src/components/ui/**/*.{ts,tsx}"],
|
||||
rules: {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
patterns: [
|
||||
{
|
||||
// `../X` (exactly one level up = a feature component). A `regex` rather than a glob:
|
||||
// eslint matches `patterns` gitignore-style, where `../*` also swallows `../../lib/x`.
|
||||
regex: "^\.\./(?!\.\./)",
|
||||
message:
|
||||
"components/ui/ is domain-free: a platform component may not import a feature component. Invert the dependency (take a prop/render-prop) or keep the component outside ui/.",
|
||||
},
|
||||
{
|
||||
regex: "^\.\./\.\./lib/api/",
|
||||
message:
|
||||
"components/ui/ is domain-free: a platform component may not call a domain API slice. Take the data as props.",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
prettier,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user