|
1 | 1 | # typed: true
|
2 | 2 | # frozen_string_literal: true
|
3 | 3 |
|
4 |
| -require "packwerk/constant_name_inspector" |
| 4 | +require "packwerk/constant_name_inspector_interface" |
5 | 5 |
|
6 | 6 | module Packwerk
|
7 | 7 | # Extracts a constant name from an AST node of type :const
|
8 | 8 | class ConstNodeInspector
|
9 |
| - include ConstantNameInspector |
| 9 | + include ConstantNameInspectorInterface |
10 | 10 |
|
11 | 11 | def constant_name_from_node(node, ancestors:)
|
12 |
| - return nil unless Node.type(node) == Node::CONSTANT |
13 |
| - |
| 12 | + return nil unless Node.constant?(node) |
14 | 13 | # Only process the root `const` node for namespaced constant references. For example, in the
|
15 | 14 | # reference `Spam::Eggs::Thing`, we only process the const node associated with `Spam`.
|
16 |
| - parent = ancestors.first |
17 |
| - return nil if parent && Node.type(parent) == Node::CONSTANT |
18 |
| - |
19 |
| - if constant_in_module_or_class_definition?(node, parent: parent) |
20 |
| - # We're defining a class with this name, in which case the constant is implicitly fully qualified by its |
21 |
| - # enclosing namespace |
22 |
| - name = Node.parent_module_name(ancestors: ancestors) |
23 |
| - name ||= Node.enclosing_namespace_path(node, ancestors: ancestors).push(Node.constant_name(node)).join("::") |
| 15 | + return nil if root_constant?(ancestors) |
24 | 16 |
|
25 |
| - "::" + name |
| 17 | + if constant_in_module_or_class_definition?(node, ancestors: ancestors) |
| 18 | + fully_qualify_constant(node, ancestors: ancestors) |
26 | 19 | else
|
27 |
| - begin |
28 |
| - Node.constant_name(node) |
29 |
| - rescue Node::TypeError |
30 |
| - nil |
31 |
| - end |
| 20 | + Node.constant_name(node) |
32 | 21 | end
|
| 22 | + rescue Node::TypeError |
| 23 | + nil |
33 | 24 | end
|
34 | 25 |
|
35 | 26 | private
|
36 | 27 |
|
37 |
| - def constant_in_module_or_class_definition?(node, parent:) |
38 |
| - if parent |
| 28 | + def root_constant?(ancestors) |
| 29 | + parent = ancestors.first |
| 30 | + parent && Node.constant?(parent) |
| 31 | + end |
| 32 | + |
| 33 | + def constant_in_module_or_class_definition?(node, ancestors:) |
| 34 | + if (parent = ancestors.first) |
39 | 35 | parent_name = Node.module_name_from_definition(parent)
|
40 | 36 | parent_name && parent_name == Node.constant_name(node)
|
41 | 37 | end
|
42 | 38 | end
|
| 39 | + |
| 40 | + def fully_qualify_constant(node, ancestors:) |
| 41 | + # We're defining a class with this name, in which case the constant is implicitly fully qualified by its |
| 42 | + # enclosing namespace |
| 43 | + name = Node.parent_module_name(ancestors: ancestors) |
| 44 | + name ||= generate_qualified_constant(node, ancestors) |
| 45 | + "::" + name |
| 46 | + end |
| 47 | + |
| 48 | + def generate_qualified_constant(node, ancestors:) |
| 49 | + namespace_path = Node.enclosing_namespace_path(node, ancestors: ancestors) |
| 50 | + constant_name = Node.constant_name(node) |
| 51 | + namespace_path.push(constant_name).join("::") |
| 52 | + end |
43 | 53 | end
|
44 | 54 | end
|
0 commit comments