Skip to main content

darklua_core/rules/convert_require/
roblox_index_style.rs

1use serde::{Deserialize, Serialize};
2
3use crate::nodes::{FieldExpression, FunctionCall, IndexExpression, Prefix, StringExpression};
4use crate::process::utils::is_valid_identifier;
5
6use std::str::FromStr;
7
8/// Represents the different styles of indexing in Roblox.
9#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
10#[serde(rename_all = "snake_case", tag = "name")]
11pub enum RobloxIndexStyle {
12    /// Uses `:FindFirstChild(name)` calls to access child Instances.
13    #[default]
14    FindFirstChild,
15    /// Uses `:WaitForChild(name)` calls to access child Instances.
16    WaitForChild,
17    /// Uses the property syntax (`parent.ObjectName`) to access child Instances.
18    Property,
19}
20
21impl RobloxIndexStyle {
22    pub(crate) fn index(&self, instance: Prefix, child_name: &str) -> Prefix {
23        let child_name = if child_name.ends_with(".lua") {
24            child_name.get(0..child_name.len() - 4).unwrap()
25        } else if child_name.ends_with(".luau") {
26            child_name.get(0..child_name.len() - 5).unwrap()
27        } else {
28            child_name
29        };
30        match self {
31            RobloxIndexStyle::FindFirstChild => FunctionCall::from_prefix(instance)
32                .with_method("FindFirstChild")
33                .with_argument(StringExpression::from_value(child_name))
34                .into(),
35            RobloxIndexStyle::WaitForChild => FunctionCall::from_prefix(instance)
36                .with_method("WaitForChild")
37                .with_argument(StringExpression::from_value(child_name))
38                .into(),
39            RobloxIndexStyle::Property => {
40                if is_valid_identifier(child_name) {
41                    FieldExpression::new(instance, child_name).into()
42                } else {
43                    IndexExpression::new(instance, StringExpression::from_value(child_name)).into()
44                }
45            }
46        }
47    }
48}
49
50impl FromStr for RobloxIndexStyle {
51    type Err = String;
52
53    fn from_str(s: &str) -> Result<Self, Self::Err> {
54        Ok(match s {
55            "find_first_child" => Self::FindFirstChild,
56            "wait_for_child" => Self::WaitForChild,
57            "property" => Self::Property,
58            _ => return Err(format!("invalid roblox index style `{}`", s)),
59        })
60    }
61}
62
63#[cfg(test)]
64mod test {
65    use super::*;
66
67    #[test]
68    fn deserialize_find_first_child() {
69        assert_eq!(
70            RobloxIndexStyle::FindFirstChild,
71            "find_first_child".parse().unwrap()
72        );
73    }
74
75    #[test]
76    fn deserialize_wait_for_child() {
77        assert_eq!(
78            RobloxIndexStyle::WaitForChild,
79            "wait_for_child".parse().unwrap()
80        );
81    }
82
83    #[test]
84    fn deserialize_property() {
85        assert_eq!(RobloxIndexStyle::Property, "property".parse().unwrap());
86    }
87
88    #[test]
89    fn deserialize_invalid() {
90        assert_eq!(
91            "invalid roblox index style `oops`",
92            "oops".parse::<RobloxIndexStyle>().unwrap_err()
93        );
94    }
95}