darklua_core/rules/
convert_luau_number.rs1use crate::{
2 nodes::{Block, HexNumber, NumberExpression, Token},
3 process::{DefaultVisitor, NodeProcessor, NodeVisitor},
4 rules::{Context, FlawlessRule, RuleConfiguration, RuleConfigurationError, RuleProperties},
5};
6
7use super::verify_no_rule_properties;
8
9#[derive(Default)]
10struct Processor<'a> {
11 code: &'a str,
12}
13
14impl Processor<'_> {
15 fn trim_underscores(&self, token: &mut Token) {
16 let content = token.read(self.code);
17
18 if content.contains('_') {
19 token.replace_with_content(content.chars().filter(|c| *c != '_').collect::<String>());
20 }
21 }
22}
23
24impl NodeProcessor for Processor<'_> {
25 fn process_number_expression(&mut self, number: &mut NumberExpression) {
26 match number {
27 NumberExpression::Binary(binary) => {
28 let value = binary.get_raw_value();
29 *number = HexNumber::new(value, false).into();
30 }
31 NumberExpression::Hex(hex_number) => {
32 if let Some(token) = hex_number.mutate_token() {
33 self.trim_underscores(token);
34 }
35 }
36 NumberExpression::Decimal(decimal_number) => {
37 if let Some(token) = decimal_number.mutate_token() {
38 self.trim_underscores(token);
39 }
40 }
41 }
42 }
43}
44
45impl<'a> Processor<'a> {
46 fn new(code: &'a str) -> Self {
47 Self { code }
48 }
49}
50
51pub const CONVERT_LUAU_NUMBER_RULE_NAME: &str = "convert_luau_number";
52
53#[derive(Default, Debug, PartialEq, Eq)]
55pub struct ConvertLuauNumber {}
56
57impl FlawlessRule for ConvertLuauNumber {
58 fn flawless_process(&self, block: &mut Block, context: &Context) {
59 let mut processor = Processor::new(context.original_code());
60 DefaultVisitor::visit_block(block, &mut processor);
61 }
62}
63
64impl RuleConfiguration for ConvertLuauNumber {
65 fn configure(&mut self, properties: RuleProperties) -> Result<(), RuleConfigurationError> {
66 verify_no_rule_properties(&properties)?;
67
68 Ok(())
69 }
70
71 fn get_name(&self) -> &'static str {
72 CONVERT_LUAU_NUMBER_RULE_NAME
73 }
74
75 fn serialize_to_properties(&self) -> RuleProperties {
76 RuleProperties::new()
77 }
78}
79
80#[cfg(test)]
81mod test {
82 use super::*;
83 use crate::rules::Rule;
84
85 use insta::assert_json_snapshot;
86
87 fn new_rule() -> ConvertLuauNumber {
88 ConvertLuauNumber::default()
89 }
90
91 #[test]
92 fn serialize_default_rule() {
93 let rule: Box<dyn Rule> = Box::new(new_rule());
94
95 assert_json_snapshot!("default_convert_luau_number", rule);
96 }
97
98 #[test]
99 fn configure_with_extra_field_error() {
100 let result = json5::from_str::<Box<dyn Rule>>(
101 r#"{
102 rule: 'convert_luau_number',
103 prop: "something",
104 }"#,
105 );
106 pretty_assertions::assert_eq!(result.unwrap_err().to_string(), "unexpected field 'prop'");
107 }
108}