1mod absolute_filesystem_paths;
2mod absolute_module_paths;
3mod banned_dependencies;
4mod duplicate_logic;
5mod duplicate_types_alias;
6mod file_complexity;
7mod layer_direction;
8mod public_api_errors;
9mod srp_heuristic;
10mod use_tree_path;
11
12use crate::analysis::Workspace;
13use crate::config::{Level, Policy, RuleSettings};
14use crate::emit::Emitter;
15use crate::report::RuleCatalogEntry;
16
17pub use absolute_filesystem_paths::AbsoluteFilesystemPathsRule;
18pub use absolute_module_paths::AbsoluteModulePathsRule;
19pub use banned_dependencies::BannedDependenciesRule;
20pub use duplicate_logic::DuplicateLogicRule;
21pub use duplicate_types_alias::DuplicateTypesAliasCandidateRule;
22pub use file_complexity::FileComplexityRule;
23pub use layer_direction::LayerDirectionRule;
24pub use public_api_errors::PublicApiErrorsRule;
25pub use srp_heuristic::SrpHeuristicRule;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
28#[serde(rename_all = "snake_case")]
29pub enum RuleFamily {
30 Architecture,
31 Design,
32 Shape,
33 Portability,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
37#[serde(rename_all = "snake_case")]
38pub enum RuleBackend {
39 Syntax,
40 Semantic,
41 Adapter,
42}
43
44#[derive(Debug, Clone, Copy)]
45pub struct RuleInfo {
46 pub id: &'static str,
47 pub family: RuleFamily,
48 pub backend: RuleBackend,
49 pub summary: &'static str,
50 pub default_level: Level,
51 pub schema: &'static str,
52 pub config_example: &'static str,
53 pub fixable: bool,
54}
55
56pub struct RuleContext<'a> {
57 pub policy: &'a Policy,
58}
59
60pub trait Rule {
61 fn info(&self) -> RuleInfo;
62 fn run(&self, ws: &Workspace, ctx: &RuleContext<'_>, out: &mut dyn Emitter);
63}
64
65fn all_rules() -> Vec<Box<dyn Rule>> {
66 vec![
67 Box::new(AbsoluteModulePathsRule),
68 Box::new(AbsoluteFilesystemPathsRule),
69 Box::new(FileComplexityRule),
70 Box::new(DuplicateLogicRule),
71 Box::new(DuplicateTypesAliasCandidateRule),
72 Box::new(SrpHeuristicRule),
73 Box::new(BannedDependenciesRule),
74 Box::new(PublicApiErrorsRule),
75 Box::new(LayerDirectionRule),
76 ]
77}
78
79pub fn rule_catalog() -> Vec<RuleInfo> {
80 all_rules().into_iter().map(|rule| rule.info()).collect()
81}
82
83pub fn rule_catalog_entries() -> Vec<RuleCatalogEntry> {
84 rule_catalog()
85 .into_iter()
86 .map(|info| RuleCatalogEntry {
87 id: info.id.to_string(),
88 family: info.family,
89 backend: info.backend,
90 default_level: info.default_level,
91 summary: info.summary.to_string(),
92 fixable: info.fixable,
93 })
94 .collect()
95}
96
97pub fn enabled_rules(policy: &Policy) -> Vec<Box<dyn Rule>> {
98 all_rules()
99 .into_iter()
100 .filter(|rule| {
101 let info = rule.info();
102 policy.rule_enabled_anywhere(info.id, info.default_level)
103 })
104 .collect()
105}
106
107pub fn default_rule_settings() -> Vec<(String, RuleSettings)> {
108 rule_catalog()
109 .into_iter()
110 .map(|info| {
111 (
112 info.id.to_string(),
113 RuleSettings {
114 level: Some(info.default_level),
115 options: toml::Table::new(),
116 },
117 )
118 })
119 .collect()
120}