返回 DeepSeek-Reasonix
layers.go
根目录 / tools / repolint / layers.go
1 package main
2
3 import (
4 "fmt"
5 "path"
6 "strings"
7 )
8
9 const modulePrefix = "reasonix/"
10
11 // Transport-agnostic control.Controller sits behind every frontend; nothing
12 // below it may reach up. See REASONIX.md.
13 var frontends = []string{
14 "internal/acp",
15 "internal/boot",
16 "internal/bot",
17 "internal/botruntime",
18 "internal/cli",
19 "internal/serve",
20 }
21
22 // Utility layer: these packages carry no knowledge of the kernel and must
23 // stay importable from anywhere without dragging a dependency graph along.
24 var leaves = []string{
25 "internal/ablation",
26 "internal/agentpreset",
27 "internal/billing",
28 "internal/diff",
29 "internal/extension/rpcwire",
30 "internal/extensioncontract",
31 "internal/filelock",
32 "internal/fileref",
33 "internal/fileutil",
34 "internal/fileutil/encoding",
35 "internal/frontmatter",
36 "internal/i18n",
37 "internal/mcpdiag",
38 "internal/nilutil",
39 "internal/packagegrant",
40 "internal/planmode",
41 "internal/proc",
42 "internal/releaseasset",
43 "internal/retrieval",
44 "internal/shellparse",
45 "internal/store",
46 "internal/sysproxy",
47
48 "internal/textutil",
49 }
50
51 func checkLayering(imports map[string][]importRef) []Finding {
52 var out []Finding
53 for _, rel := range sortedKeys(imports) {
54 pkg := path.Dir(rel)
55 for _, ref := range imports[rel] {
56 dep, ok := strings.CutPrefix(ref.path, modulePrefix)
57 if !ok {
58 continue
59 }
60 if msg := violates(pkg, dep); msg != "" {
61 out = append(out, Finding{rel, ref.line, ruleLayering, msg, 1})
62 }
63 }
64 }
65 return out
66 }
67
68 func violates(pkg, dep string) string {
69 switch {
70 case matches(leaves, pkg):
71 return fmt.Sprintf("%s is a utility-layer package and must not import %s", pkg, dep)
72 case under(dep, "internal/control") && !matches(frontends, pkg) && !under(pkg, "internal/control") && !host(pkg):
73 return fmt.Sprintf("%s may not import %s: the controller is reachable from frontends and entrypoints only", pkg, dep)
74 case matches(frontends, dep) && !matches(frontends, pkg) && !host(pkg):
75 return fmt.Sprintf("%s may not import the %s frontend: move shared behavior below the controller", pkg, dep)
76 }
77 return ""
78 }
79
80 func host(pkg string) bool { return under(pkg, "cmd") || under(pkg, "desktop") }
81
82 func under(pkg, root string) bool { return pkg == root || strings.HasPrefix(pkg, root+"/") }
83
84 func matches(roots []string, pkg string) bool {
85 for _, root := range roots {
86 if under(pkg, root) {
87 return true
88 }
89 }
90 return false
91 }
92
92 lines GO