(&mut self, node: Node<'t>)
| 559 | // --- extractVariable — the lua/luau branch (2538-2549, 2789-2805) ----- |
| 560 | |
| 561 | fn extract_variable(&mut self, node: Node<'t>) { |
| 562 | // isConst absent → kind is ALWAYS `variable`; docstring from the |
| 563 | // DECLARATION node; isExported = hook ?? false → false for BOTH |
| 564 | // dialects (luau's slice sees `local …`). |
| 565 | let docstring = preceding_docstring(node, self.src); |
| 566 | let is_exported = self.is_exported_of(node).unwrap_or(false); |
| 567 | |
| 568 | let mut cursor = node.walk(); |
| 569 | let assign = node |
| 570 | .named_children(&mut cursor) |
| 571 | .find(|c| c.kind() == "assignment_statement") |
| 572 | .unwrap_or(node); |
| 573 | let mut ac = assign.walk(); |
| 574 | let var_list = assign.named_children(&mut ac).find(|c| c.kind() == "variable_list"); |
| 575 | let mut ec = assign.walk(); |
| 576 | let expr_list = assign.named_children(&mut ec).find(|c| c.kind() == "expression_list"); |
| 577 | let values: Vec<Node<'t>> = match expr_list { |
| 578 | Some(el) => { |
| 579 | let mut c = el.walk(); |
| 580 | el.named_children(&mut c).collect() |
| 581 | } |
| 582 | None => Vec::new(), |
| 583 | }; |
| 584 | let targets: Vec<Node<'t>> = match var_list { |
| 585 | Some(vl) => { |
| 586 | let mut c = vl.walk(); |
| 587 | vl.named_children(&mut c).collect() |
| 588 | } |
| 589 | None => Vec::new(), |
| 590 | }; |
| 591 | for (i, name_node) in targets.iter().enumerate() { |
| 592 | let Some((name, receiver, full_name)) = self.lua_assignment_target(*name_node) else { |
| 593 | continue; |
| 594 | }; |
| 595 | let value = values.get(i).copied(); |
| 596 | if let Some(value) = value { |
| 597 | if value.kind() == "function_definition" { |
| 598 | self.extract_lua_function_value( |
| 599 | value, |
| 600 | name, |
| 601 | receiver, |
| 602 | docstring.clone(), |
| 603 | ); |
| 604 | continue; |
| 605 | } |
| 606 | if value.kind() == "table_constructor" { |
| 607 | self.extract_lua_table_functions(value, full_name); |
| 608 | } |
| 609 | } |
| 610 | // Dotted assignments update table members, not standalone vars. |
| 611 | if receiver.is_some() || node.kind() == "assignment_statement" { |
| 612 | continue; |
| 613 | } |
| 614 | // Positional value pairing; a missing value → NO signature key. |
| 615 | let signature = value.map(|v| util::init_signature(self.text(v))); |
| 616 | self.create_node( |
| 617 | "variable", |
| 618 | &name, |
no test coverage detected