tsz_parser/syntax/
transform_utils.rs1use crate::parser::{NodeArena, NodeIndex, node::NodeAccess, syntax_kind_ext};
6use tsz_scanner::SyntaxKind;
7
8#[derive(Clone, Copy)]
9enum ReferenceTarget {
10 Arguments,
11 This,
12}
13
14impl ReferenceTarget {
15 const fn identifier_name(self) -> &'static str {
16 match self {
17 Self::Arguments => "arguments",
18 Self::This => "this",
19 }
20 }
21
22 const fn include_keyword_check(self) -> bool {
23 matches!(self, Self::This)
24 }
25}
26
27#[must_use]
29pub fn contains_this_reference(arena: &NodeArena, node_idx: NodeIndex) -> bool {
30 contains_target_reference(arena, node_idx, ReferenceTarget::This)
31}
32
33#[must_use]
41pub fn contains_arguments_reference(arena: &NodeArena, node_idx: NodeIndex) -> bool {
42 contains_target_reference(arena, node_idx, ReferenceTarget::Arguments)
43}
44
45fn contains_target_reference(
46 arena: &NodeArena,
47 node_idx: NodeIndex,
48 target: ReferenceTarget,
49) -> bool {
50 let Some(node) = arena.get(node_idx) else {
51 return false;
52 };
53
54 if target.include_keyword_check()
55 && (node.kind == SyntaxKind::ThisKeyword as u16
56 || node.kind == SyntaxKind::SuperKeyword as u16)
57 {
58 return true;
59 }
60
61 if node.kind == SyntaxKind::Identifier as u16
62 && let Some(identifier) = arena.get_identifier(node)
63 {
64 return identifier.escaped_text == target.identifier_name();
65 }
66
67 target_reference_children(arena, node_idx)
68 .into_iter()
69 .any(|child_idx| contains_target_reference(arena, child_idx, target))
70}
71
72fn target_reference_children(arena: &NodeArena, node_idx: NodeIndex) -> Vec<NodeIndex> {
73 let Some(node) = arena.get(node_idx) else {
74 return Vec::new();
75 };
76
77 match node.kind {
78 kind if kind == syntax_kind_ext::FUNCTION_DECLARATION
79 || kind == syntax_kind_ext::FUNCTION_EXPRESSION =>
80 {
81 Vec::new()
82 }
83 kind if kind == syntax_kind_ext::METHOD_DECLARATION => {
84 if let Some(method) = arena.get_method_decl(node) {
85 Vec::from([method.name])
86 } else {
87 Vec::new()
88 }
89 }
90 kind if kind == syntax_kind_ext::GET_ACCESSOR || kind == syntax_kind_ext::SET_ACCESSOR => {
91 if let Some(accessor) = arena.get_accessor(node) {
92 Vec::from([accessor.name])
93 } else {
94 Vec::new()
95 }
96 }
97 kind if kind == syntax_kind_ext::ARROW_FUNCTION => {
98 if let Some(func) = arena.get_function(node) {
99 let mut children = Vec::new();
100 for ¶m_idx in &func.parameters.nodes {
101 let Some(param_node) = arena.get(param_idx) else {
102 continue;
103 };
104 let Some(param) = arena.get_parameter(param_node) else {
105 continue;
106 };
107 if param.initializer.is_some() {
108 children.push(param.initializer);
109 }
110 }
111 if func.body.is_some() {
112 children.push(func.body);
113 }
114 children
115 } else {
116 Vec::new()
117 }
118 }
119 kind if kind == syntax_kind_ext::VARIABLE_STATEMENT
120 || kind == syntax_kind_ext::VARIABLE_DECLARATION_LIST =>
121 {
122 if let Some(var_stmt) = arena.get_variable(node) {
123 var_stmt.declarations.nodes.clone()
124 } else {
125 Vec::new()
126 }
127 }
128 kind if kind == syntax_kind_ext::VARIABLE_DECLARATION => {
129 if let Some(decl) = arena.get_variable_declaration(node) {
130 if decl.initializer.is_none() {
131 Vec::new()
132 } else {
133 vec![decl.initializer]
134 }
135 } else {
136 Vec::new()
137 }
138 }
139 _ => arena.get_children(node_idx),
140 }
141}
142
143#[must_use]
145pub fn is_private_identifier(arena: &NodeArena, name_idx: NodeIndex) -> bool {
146 let Some(node) = arena.get(name_idx) else {
147 return false;
148 };
149 node.kind == SyntaxKind::PrivateIdentifier as u16
150}