rfmt 1.5.3 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,35 @@
1
+ //! Rule-based formatting system for rfmt
2
+ //!
3
+ //! This module provides a Prettier-inspired architecture for formatting Ruby code:
4
+ //!
5
+ //! - **FormatContext**: Manages state during formatting (comments, source, config)
6
+ //! - **FormatRule**: Trait for implementing formatting rules for specific node types
7
+ //! - **RuleRegistry**: Maps node types to their formatting rules
8
+ //! - **Formatter**: Main entry point that coordinates the formatting process
9
+ //!
10
+ //! # Architecture
11
+ //!
12
+ //! ```text
13
+ //! AST Node → RuleRegistry.get_rule() → FormatRule.format() → Doc IR → Printer → String
14
+ //! ```
15
+ //!
16
+ //! # Example
17
+ //!
18
+ //! ```rust,ignore
19
+ //! use rfmt::format::Formatter;
20
+ //! use rfmt::config::Config;
21
+ //!
22
+ //! let formatter = Formatter::new(Config::default());
23
+ //! let result = formatter.format(source, &ast)?;
24
+ //! ```
25
+
26
+ pub mod context;
27
+ pub mod formatter;
28
+ pub mod registry;
29
+ pub mod rule;
30
+ pub mod rules;
31
+
32
+ pub use context::FormatContext;
33
+ pub use formatter::Formatter;
34
+ pub use registry::RuleRegistry;
35
+ pub use rule::{BoxedRule, FormatRule};
@@ -0,0 +1,195 @@
1
+ //! RuleRegistry - Dispatches nodes to appropriate formatting rules
2
+ //!
3
+ //! The registry maps NodeType to FormatRule implementations, allowing
4
+ //! the formatter to dispatch nodes to the correct rule.
5
+
6
+ use crate::ast::NodeType;
7
+ use std::borrow::Cow;
8
+ use std::collections::HashMap;
9
+
10
+ use super::rule::{BoxedRule, FormatRule};
11
+ use super::rules::{
12
+ BeginRule, BlockRule, CallRule, CaseMatchRule, CaseRule, ClassRule, DefRule, EnsureRule,
13
+ FallbackRule, ForRule, IfRule, InRule, InstanceVariableWriteRule, LambdaRule,
14
+ LocalVariableWriteRule, ModuleRule, RescueRule, SingletonClassRule, StatementsRule, UnlessRule,
15
+ UntilRule, WhenRule, WhileRule,
16
+ };
17
+
18
+ /// Key type for the registry, derived from NodeType.
19
+ ///
20
+ /// Uses `Cow<'static, str>` to avoid allocation for known node types
21
+ /// while still supporting dynamic Unknown types.
22
+ #[derive(Debug, Clone, PartialEq, Eq, Hash)]
23
+ pub struct NodeTypeKey(Cow<'static, str>);
24
+
25
+ impl NodeTypeKey {
26
+ #[inline]
27
+ const fn from_static(s: &'static str) -> Self {
28
+ Self(Cow::Borrowed(s))
29
+ }
30
+
31
+ fn from_owned(s: String) -> Self {
32
+ Self(Cow::Owned(s))
33
+ }
34
+ }
35
+
36
+ impl From<&NodeType> for NodeTypeKey {
37
+ #[inline]
38
+ fn from(node_type: &NodeType) -> Self {
39
+ match node_type {
40
+ NodeType::ProgramNode => Self::from_static("program_node"),
41
+ NodeType::StatementsNode => Self::from_static("statements_node"),
42
+ NodeType::ClassNode => Self::from_static("class_node"),
43
+ NodeType::ModuleNode => Self::from_static("module_node"),
44
+ NodeType::SingletonClassNode => Self::from_static("singleton_class_node"),
45
+ NodeType::DefNode => Self::from_static("def_node"),
46
+ NodeType::CallNode => Self::from_static("call_node"),
47
+ NodeType::IfNode => Self::from_static("if_node"),
48
+ NodeType::UnlessNode => Self::from_static("unless_node"),
49
+ NodeType::BeginNode => Self::from_static("begin_node"),
50
+ NodeType::RescueNode => Self::from_static("rescue_node"),
51
+ NodeType::EnsureNode => Self::from_static("ensure_node"),
52
+ NodeType::CaseNode => Self::from_static("case_node"),
53
+ NodeType::WhenNode => Self::from_static("when_node"),
54
+ NodeType::CaseMatchNode => Self::from_static("case_match_node"),
55
+ NodeType::InNode => Self::from_static("in_node"),
56
+ NodeType::WhileNode => Self::from_static("while_node"),
57
+ NodeType::UntilNode => Self::from_static("until_node"),
58
+ NodeType::ForNode => Self::from_static("for_node"),
59
+ NodeType::BlockNode => Self::from_static("block_node"),
60
+ NodeType::LambdaNode => Self::from_static("lambda_node"),
61
+ NodeType::LocalVariableWriteNode => Self::from_static("local_variable_write_node"),
62
+ NodeType::InstanceVariableWriteNode => {
63
+ Self::from_static("instance_variable_write_node")
64
+ }
65
+ NodeType::Unknown(s) => Self::from_owned(s.clone()),
66
+ // Default for unhandled types
67
+ _ => Self::from_static("unknown"),
68
+ }
69
+ }
70
+ }
71
+
72
+ /// Registry that maps NodeType to FormatRule.
73
+ pub struct RuleRegistry {
74
+ rules: HashMap<NodeTypeKey, BoxedRule>,
75
+ fallback: BoxedRule,
76
+ }
77
+
78
+ impl RuleRegistry {
79
+ pub fn new() -> Self {
80
+ Self {
81
+ rules: HashMap::new(),
82
+ fallback: Box::new(FallbackRule),
83
+ }
84
+ }
85
+
86
+ #[inline]
87
+ pub fn add<R: FormatRule + 'static>(mut self, node_type: NodeType, rule: R) -> Self {
88
+ let key = NodeTypeKey::from(&node_type);
89
+ self.rules.insert(key, Box::new(rule));
90
+ self
91
+ }
92
+
93
+ pub fn add_rule<R: FormatRule + 'static>(&mut self, node_type: NodeType, rule: R) {
94
+ let key = NodeTypeKey::from(&node_type);
95
+ self.rules.insert(key, Box::new(rule));
96
+ }
97
+
98
+ #[inline]
99
+ pub fn get_rule(&self, node_type: &NodeType) -> &dyn FormatRule {
100
+ let key = NodeTypeKey::from(node_type);
101
+ self.rules
102
+ .get(&key)
103
+ .map(|r| r.as_ref())
104
+ .unwrap_or(self.fallback.as_ref())
105
+ }
106
+
107
+ pub fn default_registry() -> Self {
108
+ Self::new()
109
+ .add(NodeType::StatementsNode, StatementsRule)
110
+ .add(NodeType::ClassNode, ClassRule)
111
+ .add(NodeType::ModuleNode, ModuleRule)
112
+ .add(NodeType::SingletonClassNode, SingletonClassRule)
113
+ .add(NodeType::DefNode, DefRule)
114
+ .add(NodeType::IfNode, IfRule)
115
+ .add(NodeType::UnlessNode, UnlessRule)
116
+ .add(NodeType::CaseNode, CaseRule)
117
+ .add(NodeType::WhenNode, WhenRule)
118
+ .add(NodeType::CaseMatchNode, CaseMatchRule)
119
+ .add(NodeType::InNode, InRule)
120
+ .add(NodeType::BeginNode, BeginRule)
121
+ .add(NodeType::RescueNode, RescueRule)
122
+ .add(NodeType::EnsureNode, EnsureRule)
123
+ .add(NodeType::CallNode, CallRule)
124
+ .add(NodeType::BlockNode, BlockRule)
125
+ .add(NodeType::LambdaNode, LambdaRule)
126
+ .add(NodeType::WhileNode, WhileRule)
127
+ .add(NodeType::UntilNode, UntilRule)
128
+ .add(NodeType::ForNode, ForRule)
129
+ .add(NodeType::LocalVariableWriteNode, LocalVariableWriteRule)
130
+ .add(
131
+ NodeType::InstanceVariableWriteNode,
132
+ InstanceVariableWriteRule,
133
+ )
134
+ }
135
+ }
136
+
137
+ impl Default for RuleRegistry {
138
+ fn default() -> Self {
139
+ Self::default_registry()
140
+ }
141
+ }
142
+
143
+ #[cfg(test)]
144
+ mod tests {
145
+ use super::*;
146
+
147
+ #[test]
148
+ fn test_node_type_key_from_node_type() {
149
+ let key = NodeTypeKey::from(&NodeType::ClassNode);
150
+ assert_eq!(key.0, "class_node");
151
+
152
+ let key = NodeTypeKey::from(&NodeType::DefNode);
153
+ assert_eq!(key.0, "def_node");
154
+
155
+ let key = NodeTypeKey::from(&NodeType::Unknown("custom".to_string()));
156
+ assert_eq!(key.0, "custom");
157
+ }
158
+
159
+ #[test]
160
+ fn test_registry_get_registered_rule() {
161
+ let registry = RuleRegistry::default_registry();
162
+
163
+ // ClassRule should be registered
164
+ let _rule = registry.get_rule(&NodeType::ClassNode);
165
+ // If we get here, the rule was found
166
+ }
167
+
168
+ #[test]
169
+ fn test_registry_get_fallback_rule() {
170
+ let registry = RuleRegistry::default_registry();
171
+
172
+ // IntegerNode doesn't have a specific rule, should use fallback
173
+ let _rule = registry.get_rule(&NodeType::IntegerNode);
174
+ // If we get here, the fallback was used
175
+ }
176
+
177
+ #[test]
178
+ fn test_registry_custom_registration() {
179
+ // Using builder pattern with method chaining
180
+ let registry = RuleRegistry::new().add(NodeType::IfNode, FallbackRule);
181
+
182
+ // Should find the registered rule
183
+ let _rule = registry.get_rule(&NodeType::IfNode);
184
+ }
185
+
186
+ #[test]
187
+ fn test_registry_add_rule_mutable() {
188
+ // Using mutable reference variant
189
+ let mut registry = RuleRegistry::new();
190
+ registry.add_rule(NodeType::DefNode, FallbackRule);
191
+
192
+ // Should find the registered rule
193
+ let _rule = registry.get_rule(&NodeType::DefNode);
194
+ }
195
+ }