reluxscript 0.1.4

Write AST transformations once. Compile to Babel, SWC, and beyond.
Documentation
/// Test: Pattern Matching
/// Tests: matches! macro, if-let, match expression, enum patterns

plugin PatternMatchingPlugin {

    // Enum declaration
    enum HookType {
        State,
        Effect,
        Ref,
        Memo,
        Custom(Str),
    }

    // Enum with multiple variants
    enum NodeCategory {
        Literal,
        Expression,
        Statement,
        Declaration,
        Unknown,
    }

    struct State {
        hook_count: i32,
        categories: Vec<NodeCategory>,
    }

    // Function using match expression
    fn categorize_hook(name: &Str) -> HookType {
        match name.as_str() {
            "useState" => HookType::State,
            "useReducer" => HookType::State,
            "useEffect" => HookType::Effect,
            "useLayoutEffect" => HookType::Effect,
            "useRef" => HookType::Ref,
            "useMemo" => HookType::Memo,
            "useCallback" => HookType::Memo,
            _ => HookType::Custom(name.clone()),
        }
    }

    // Match with multiple patterns using |
    fn get_operator_type(op: &Str) -> Str {
        match op.as_str() {
            "+" | "-" => "additive",
            "*" | "/" | "%" => "multiplicative",
            "==" | "!=" | "<" | ">" | "<=" | ">=" => "comparison",
            "&&" | "||" => "logical",
            _ => "other",
        }
    }

    // Function using if-let with Option
    fn get_identifier_name(expr: &Expression) -> Option<Str> {
        if let Expression::Identifier(id) = expr {
            Some(id.name.clone())
        } else {
            None
        }
    }

    // Nested if-let patterns
    fn extract_member_object(expr: &Expression) -> Option<Str> {
        if let Expression::MemberExpression(member) = expr {
            if let Expression::Identifier(obj) = &member.object {
                return Some(obj.name.clone());
            }
        }
        None
    }

    // Visitor using matches! macro
    fn visit_call_expression(node: &mut CallExpression, ctx: &Context) {
        // matches! for simple pattern check
        if matches!(node.arguments.len(), 0 | 1 | 2) {
            self.state.hook_count += 1;
        }

        // matches! with struct pattern
        if matches!(node.callee, MemberExpression {
            object: Identifier { name: "console" },
            property: Identifier { name: "log" }
        }) {
            // This is console.log
            self.state.hook_count += 1;
        }

        node.visit_children(self);
    }

    // Visitor using if-let with Option return
    fn visit_expression_statement(node: &mut ExpressionStatement, ctx: &Context) {
        if let Some(name) = get_identifier_name(&node.expression) {
            if name.starts_with("use") {
                let hook_type = categorize_hook(&name);

                // Match on enum variant
                match hook_type {
                    HookType::State => self.state.hook_count += 2,
                    HookType::Effect => self.state.hook_count += 1,
                    HookType::Custom(custom_name) => {
                        let _msg = format!("Custom hook: {}", custom_name);
                    },
                    _ => {},
                }
            }
        }

        node.visit_children(self);
    }

    // Visitor with multiple if-let chains
    fn visit_member_expression(node: &mut MemberExpression, ctx: &Context) {
        if let Expression::Identifier(obj) = &node.object {
            if let MemberProperty::Identifier(prop) = &node.property {
                let full_path = format!("{}.{}", obj.name, prop.name);
                let _category = get_operator_type(&full_path);
            }
        }

        node.visit_children(self);
    }

    // if-let with else branch
    fn classify_literal(lit: &Literal) -> NodeCategory {
        if let Literal::StringLiteral(s) = lit {
            if s.value.is_empty() {
                NodeCategory::Unknown
            } else {
                NodeCategory::Literal
            }
        } else if let Literal::NumericLiteral(n) = lit {
            NodeCategory::Literal
        } else {
            NodeCategory::Unknown
        }
    }
}