@optave/codegraph 3.1.0 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +5 -5
  2. package/grammars/tree-sitter-go.wasm +0 -0
  3. package/package.json +8 -9
  4. package/src/ast-analysis/engine.js +365 -0
  5. package/src/ast-analysis/metrics.js +118 -0
  6. package/src/ast-analysis/rules/csharp.js +201 -0
  7. package/src/ast-analysis/rules/go.js +182 -0
  8. package/src/ast-analysis/rules/index.js +82 -0
  9. package/src/ast-analysis/rules/java.js +175 -0
  10. package/src/ast-analysis/rules/javascript.js +246 -0
  11. package/src/ast-analysis/rules/php.js +219 -0
  12. package/src/ast-analysis/rules/python.js +196 -0
  13. package/src/ast-analysis/rules/ruby.js +204 -0
  14. package/src/ast-analysis/rules/rust.js +173 -0
  15. package/src/ast-analysis/shared.js +223 -0
  16. package/src/ast-analysis/visitor-utils.js +176 -0
  17. package/src/ast-analysis/visitor.js +162 -0
  18. package/src/ast-analysis/visitors/ast-store-visitor.js +150 -0
  19. package/src/ast-analysis/visitors/cfg-visitor.js +792 -0
  20. package/src/ast-analysis/visitors/complexity-visitor.js +243 -0
  21. package/src/ast-analysis/visitors/dataflow-visitor.js +358 -0
  22. package/src/ast.js +26 -166
  23. package/src/audit.js +2 -88
  24. package/src/batch.js +0 -25
  25. package/src/boundaries.js +1 -1
  26. package/src/branch-compare.js +82 -172
  27. package/src/builder.js +48 -184
  28. package/src/cfg.js +148 -1174
  29. package/src/check.js +1 -84
  30. package/src/cli.js +118 -197
  31. package/src/cochange.js +1 -39
  32. package/src/commands/audit.js +88 -0
  33. package/src/commands/batch.js +26 -0
  34. package/src/commands/branch-compare.js +97 -0
  35. package/src/commands/cfg.js +55 -0
  36. package/src/commands/check.js +82 -0
  37. package/src/commands/cochange.js +37 -0
  38. package/src/commands/communities.js +69 -0
  39. package/src/commands/complexity.js +77 -0
  40. package/src/commands/dataflow.js +110 -0
  41. package/src/commands/flow.js +70 -0
  42. package/src/commands/manifesto.js +77 -0
  43. package/src/commands/owners.js +52 -0
  44. package/src/commands/query.js +21 -0
  45. package/src/commands/sequence.js +33 -0
  46. package/src/commands/structure.js +64 -0
  47. package/src/commands/triage.js +49 -0
  48. package/src/communities.js +22 -96
  49. package/src/complexity.js +234 -1591
  50. package/src/cycles.js +1 -1
  51. package/src/dataflow.js +274 -1352
  52. package/src/db/connection.js +88 -0
  53. package/src/db/migrations.js +312 -0
  54. package/src/db/query-builder.js +280 -0
  55. package/src/db/repository/build-stmts.js +104 -0
  56. package/src/db/repository/cfg.js +83 -0
  57. package/src/db/repository/cochange.js +41 -0
  58. package/src/db/repository/complexity.js +15 -0
  59. package/src/db/repository/dataflow.js +12 -0
  60. package/src/db/repository/edges.js +259 -0
  61. package/src/db/repository/embeddings.js +40 -0
  62. package/src/db/repository/graph-read.js +39 -0
  63. package/src/db/repository/index.js +42 -0
  64. package/src/db/repository/nodes.js +236 -0
  65. package/src/db.js +58 -399
  66. package/src/embedder.js +158 -174
  67. package/src/export.js +1 -1
  68. package/src/extractors/javascript.js +130 -5
  69. package/src/flow.js +153 -222
  70. package/src/index.js +53 -16
  71. package/src/infrastructure/result-formatter.js +21 -0
  72. package/src/infrastructure/test-filter.js +7 -0
  73. package/src/kinds.js +50 -0
  74. package/src/manifesto.js +1 -82
  75. package/src/mcp.js +37 -20
  76. package/src/owners.js +127 -182
  77. package/src/queries-cli.js +866 -0
  78. package/src/queries.js +1271 -2416
  79. package/src/sequence.js +179 -223
  80. package/src/structure.js +211 -269
  81. package/src/triage.js +117 -212
  82. package/src/viewer.js +1 -1
  83. package/src/watcher.js +7 -4
@@ -0,0 +1,246 @@
1
+ /**
2
+ * JavaScript / TypeScript / TSX — AST analysis rules.
3
+ *
4
+ * Shared across: javascript, typescript, tsx language IDs.
5
+ */
6
+
7
+ import { makeCfgRules, makeDataflowRules } from '../shared.js';
8
+
9
+ // ─── Complexity ───────────────────────────────────────────────────────────
10
+
11
+ export const complexity = {
12
+ branchNodes: new Set([
13
+ 'if_statement',
14
+ 'else_clause',
15
+ 'switch_statement',
16
+ 'for_statement',
17
+ 'for_in_statement',
18
+ 'while_statement',
19
+ 'do_statement',
20
+ 'catch_clause',
21
+ 'ternary_expression',
22
+ ]),
23
+ caseNodes: new Set(['switch_case']),
24
+ logicalOperators: new Set(['&&', '||', '??']),
25
+ logicalNodeType: 'binary_expression',
26
+ optionalChainType: 'optional_chain_expression',
27
+ nestingNodes: new Set([
28
+ 'if_statement',
29
+ 'switch_statement',
30
+ 'for_statement',
31
+ 'for_in_statement',
32
+ 'while_statement',
33
+ 'do_statement',
34
+ 'catch_clause',
35
+ 'ternary_expression',
36
+ ]),
37
+ functionNodes: new Set([
38
+ 'function_declaration',
39
+ 'function_expression',
40
+ 'arrow_function',
41
+ 'method_definition',
42
+ 'generator_function',
43
+ 'generator_function_declaration',
44
+ ]),
45
+ ifNodeType: 'if_statement',
46
+ elseNodeType: 'else_clause',
47
+ elifNodeType: null,
48
+ elseViaAlternative: false,
49
+ switchLikeNodes: new Set(['switch_statement']),
50
+ };
51
+
52
+ // ─── Halstead ─────────────────────────────────────────────────────────────
53
+
54
+ export const halstead = {
55
+ operatorLeafTypes: new Set([
56
+ // Arithmetic
57
+ '+',
58
+ '-',
59
+ '*',
60
+ '/',
61
+ '%',
62
+ '**',
63
+ // Assignment
64
+ '=',
65
+ '+=',
66
+ '-=',
67
+ '*=',
68
+ '/=',
69
+ '%=',
70
+ '**=',
71
+ '<<=',
72
+ '>>=',
73
+ '>>>=',
74
+ '&=',
75
+ '|=',
76
+ '^=',
77
+ '&&=',
78
+ '||=',
79
+ '??=',
80
+ // Comparison
81
+ '==',
82
+ '===',
83
+ '!=',
84
+ '!==',
85
+ '<',
86
+ '>',
87
+ '<=',
88
+ '>=',
89
+ // Logical
90
+ '&&',
91
+ '||',
92
+ '!',
93
+ '??',
94
+ // Bitwise
95
+ '&',
96
+ '|',
97
+ '^',
98
+ '~',
99
+ '<<',
100
+ '>>',
101
+ '>>>',
102
+ // Unary
103
+ '++',
104
+ '--',
105
+ // Keywords as operators
106
+ 'typeof',
107
+ 'instanceof',
108
+ 'new',
109
+ 'return',
110
+ 'throw',
111
+ 'yield',
112
+ 'await',
113
+ 'if',
114
+ 'else',
115
+ 'for',
116
+ 'while',
117
+ 'do',
118
+ 'switch',
119
+ 'case',
120
+ 'break',
121
+ 'continue',
122
+ 'try',
123
+ 'catch',
124
+ 'finally',
125
+ // Arrow, spread, ternary, access
126
+ '=>',
127
+ '...',
128
+ '?',
129
+ ':',
130
+ '.',
131
+ '?.',
132
+ // Delimiters counted as operators
133
+ ',',
134
+ ';',
135
+ ]),
136
+ operandLeafTypes: new Set([
137
+ 'identifier',
138
+ 'property_identifier',
139
+ 'shorthand_property_identifier',
140
+ 'shorthand_property_identifier_pattern',
141
+ 'number',
142
+ 'string_fragment',
143
+ 'regex_pattern',
144
+ 'true',
145
+ 'false',
146
+ 'null',
147
+ 'undefined',
148
+ 'this',
149
+ 'super',
150
+ 'private_property_identifier',
151
+ ]),
152
+ compoundOperators: new Set([
153
+ 'call_expression',
154
+ 'subscript_expression',
155
+ 'new_expression',
156
+ 'template_substitution',
157
+ ]),
158
+ skipTypes: new Set(['type_annotation', 'type_parameters', 'return_type', 'implements_clause']),
159
+ };
160
+
161
+ // ─── CFG ──────────────────────────────────────────────────────────────────
162
+
163
+ export const cfg = makeCfgRules({
164
+ ifNode: 'if_statement',
165
+ elseClause: 'else_clause',
166
+ forNodes: new Set(['for_statement', 'for_in_statement']),
167
+ whileNode: 'while_statement',
168
+ doNode: 'do_statement',
169
+ switchNode: 'switch_statement',
170
+ caseNode: 'switch_case',
171
+ defaultNode: 'switch_default',
172
+ tryNode: 'try_statement',
173
+ catchNode: 'catch_clause',
174
+ finallyNode: 'finally_clause',
175
+ returnNode: 'return_statement',
176
+ throwNode: 'throw_statement',
177
+ breakNode: 'break_statement',
178
+ continueNode: 'continue_statement',
179
+ blockNode: 'statement_block',
180
+ labeledNode: 'labeled_statement',
181
+ functionNodes: new Set([
182
+ 'function_declaration',
183
+ 'function_expression',
184
+ 'arrow_function',
185
+ 'method_definition',
186
+ 'generator_function',
187
+ 'generator_function_declaration',
188
+ ]),
189
+ });
190
+
191
+ // ─── Dataflow ─────────────────────────────────────────────────────────────
192
+
193
+ const JS_TS_MUTATING = new Set([
194
+ 'push',
195
+ 'pop',
196
+ 'shift',
197
+ 'unshift',
198
+ 'splice',
199
+ 'sort',
200
+ 'reverse',
201
+ 'fill',
202
+ 'set',
203
+ 'delete',
204
+ 'add',
205
+ 'clear',
206
+ ]);
207
+
208
+ export const dataflow = makeDataflowRules({
209
+ functionNodes: new Set([
210
+ 'function_declaration',
211
+ 'method_definition',
212
+ 'arrow_function',
213
+ 'function_expression',
214
+ 'function',
215
+ ]),
216
+ varAssignedFnParent: 'variable_declarator',
217
+ assignmentFnParent: 'assignment_expression',
218
+ pairFnParent: 'pair',
219
+ paramWrapperTypes: new Set(['required_parameter', 'optional_parameter']),
220
+ defaultParamType: 'assignment_pattern',
221
+ restParamType: 'rest_pattern',
222
+ objectDestructType: 'object_pattern',
223
+ arrayDestructType: 'array_pattern',
224
+ shorthandPropPattern: 'shorthand_property_identifier_pattern',
225
+ pairPatternType: 'pair_pattern',
226
+ returnNode: 'return_statement',
227
+ varDeclaratorNode: 'variable_declarator',
228
+ assignmentNode: 'assignment_expression',
229
+ callNode: 'call_expression',
230
+ spreadType: 'spread_element',
231
+ memberNode: 'member_expression',
232
+ optionalChainNode: 'optional_chain_expression',
233
+ awaitNode: 'await_expression',
234
+ mutatingMethods: JS_TS_MUTATING,
235
+ });
236
+
237
+ // ─── AST Node Types ───────────────────────────────────────────────────────
238
+
239
+ export const astTypes = {
240
+ new_expression: 'new',
241
+ throw_statement: 'throw',
242
+ await_expression: 'await',
243
+ string: 'string',
244
+ template_string: 'string',
245
+ regex: 'regex',
246
+ };
@@ -0,0 +1,219 @@
1
+ /**
2
+ * PHP — AST analysis rules.
3
+ */
4
+
5
+ import { makeCfgRules, makeDataflowRules } from '../shared.js';
6
+
7
+ // ─── Complexity ───────────────────────────────────────────────────────────
8
+
9
+ export const complexity = {
10
+ branchNodes: new Set([
11
+ 'if_statement',
12
+ 'else_if_clause',
13
+ 'else_clause',
14
+ 'for_statement',
15
+ 'foreach_statement',
16
+ 'while_statement',
17
+ 'do_statement',
18
+ 'catch_clause',
19
+ 'conditional_expression',
20
+ 'switch_statement',
21
+ ]),
22
+ caseNodes: new Set(['case_statement', 'default_statement']),
23
+ logicalOperators: new Set(['&&', '||', 'and', 'or', '??']),
24
+ logicalNodeType: 'binary_expression',
25
+ optionalChainType: 'nullsafe_member_access_expression',
26
+ nestingNodes: new Set([
27
+ 'if_statement',
28
+ 'for_statement',
29
+ 'foreach_statement',
30
+ 'while_statement',
31
+ 'do_statement',
32
+ 'catch_clause',
33
+ 'conditional_expression',
34
+ 'switch_statement',
35
+ ]),
36
+ functionNodes: new Set([
37
+ 'function_definition',
38
+ 'method_declaration',
39
+ 'anonymous_function_creation_expression',
40
+ 'arrow_function',
41
+ ]),
42
+ ifNodeType: 'if_statement',
43
+ elseNodeType: 'else_clause',
44
+ elifNodeType: 'else_if_clause',
45
+ elseViaAlternative: false,
46
+ switchLikeNodes: new Set(['switch_statement']),
47
+ };
48
+
49
+ // ─── Halstead ─────────────────────────────────────────────────────────────
50
+
51
+ export const halstead = {
52
+ operatorLeafTypes: new Set([
53
+ '+',
54
+ '-',
55
+ '*',
56
+ '/',
57
+ '%',
58
+ '**',
59
+ '=',
60
+ '+=',
61
+ '-=',
62
+ '*=',
63
+ '/=',
64
+ '%=',
65
+ '**=',
66
+ '.=',
67
+ '&=',
68
+ '|=',
69
+ '^=',
70
+ '<<=',
71
+ '>>=',
72
+ '==',
73
+ '===',
74
+ '!=',
75
+ '!==',
76
+ '<',
77
+ '>',
78
+ '<=',
79
+ '>=',
80
+ '<=>',
81
+ '&&',
82
+ '||',
83
+ '!',
84
+ 'and',
85
+ 'or',
86
+ 'xor',
87
+ '??',
88
+ '&',
89
+ '|',
90
+ '^',
91
+ '~',
92
+ '<<',
93
+ '>>',
94
+ '++',
95
+ '--',
96
+ 'instanceof',
97
+ 'new',
98
+ 'clone',
99
+ 'if',
100
+ 'else',
101
+ 'elseif',
102
+ 'for',
103
+ 'foreach',
104
+ 'while',
105
+ 'do',
106
+ 'switch',
107
+ 'case',
108
+ 'return',
109
+ 'throw',
110
+ 'break',
111
+ 'continue',
112
+ 'try',
113
+ 'catch',
114
+ 'finally',
115
+ 'echo',
116
+ 'print',
117
+ 'yield',
118
+ '.',
119
+ '->',
120
+ '?->',
121
+ '::',
122
+ ',',
123
+ ';',
124
+ ':',
125
+ '?',
126
+ '=>',
127
+ ]),
128
+ operandLeafTypes: new Set([
129
+ 'name',
130
+ 'variable_name',
131
+ 'integer',
132
+ 'float',
133
+ 'string_content',
134
+ 'true',
135
+ 'false',
136
+ 'null',
137
+ ]),
138
+ compoundOperators: new Set([
139
+ 'function_call_expression',
140
+ 'member_call_expression',
141
+ 'scoped_call_expression',
142
+ 'subscript_expression',
143
+ 'object_creation_expression',
144
+ ]),
145
+ skipTypes: new Set([]),
146
+ };
147
+
148
+ // ─── CFG ──────────────────────────────────────────────────────────────────
149
+
150
+ export const cfg = makeCfgRules({
151
+ ifNode: 'if_statement',
152
+ elifNode: 'else_if_clause',
153
+ elseClause: 'else_clause',
154
+ ifConsequentField: 'body',
155
+ forNodes: new Set(['for_statement', 'foreach_statement']),
156
+ whileNode: 'while_statement',
157
+ doNode: 'do_statement',
158
+ switchNode: 'switch_statement',
159
+ caseNode: 'case_statement',
160
+ defaultNode: 'default_statement',
161
+ tryNode: 'try_statement',
162
+ catchNode: 'catch_clause',
163
+ finallyNode: 'finally_clause',
164
+ returnNode: 'return_statement',
165
+ throwNode: 'throw_expression',
166
+ breakNode: 'break_statement',
167
+ continueNode: 'continue_statement',
168
+ blockNode: 'compound_statement',
169
+ functionNodes: new Set([
170
+ 'function_definition',
171
+ 'method_declaration',
172
+ 'anonymous_function_creation_expression',
173
+ 'arrow_function',
174
+ ]),
175
+ });
176
+
177
+ // ─── Dataflow ─────────────────────────────────────────────────────────────
178
+
179
+ export const dataflow = makeDataflowRules({
180
+ functionNodes: new Set([
181
+ 'function_definition',
182
+ 'method_declaration',
183
+ 'anonymous_function_creation_expression',
184
+ 'arrow_function',
185
+ ]),
186
+ paramListField: 'parameters',
187
+ paramIdentifier: 'variable_name',
188
+ returnNode: 'return_statement',
189
+ varDeclaratorNode: null,
190
+ assignmentNode: 'assignment_expression',
191
+ assignLeftField: 'left',
192
+ assignRightField: 'right',
193
+ callNodes: new Set([
194
+ 'function_call_expression',
195
+ 'member_call_expression',
196
+ 'scoped_call_expression',
197
+ ]),
198
+ callFunctionField: 'function',
199
+ callArgsField: 'arguments',
200
+ spreadType: 'spread_expression',
201
+ memberNode: 'member_access_expression',
202
+ memberObjectField: 'object',
203
+ memberPropertyField: 'name',
204
+ argumentWrapperType: 'argument',
205
+ extraIdentifierTypes: new Set(['variable_name', 'name']),
206
+ mutatingMethods: new Set(['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']),
207
+ extractParamName(node) {
208
+ if (node.type === 'simple_parameter' || node.type === 'variadic_parameter') {
209
+ const nameNode = node.childForFieldName('name');
210
+ return nameNode ? [nameNode.text] : null;
211
+ }
212
+ if (node.type === 'variable_name') return [node.text];
213
+ return null;
214
+ },
215
+ });
216
+
217
+ // ─── AST Node Types ───────────────────────────────────────────────────────
218
+
219
+ export const astTypes = null;
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Python — AST analysis rules.
3
+ */
4
+
5
+ import { makeCfgRules, makeDataflowRules } from '../shared.js';
6
+
7
+ // ─── Complexity ───────────────────────────────────────────────────────────
8
+
9
+ export const complexity = {
10
+ branchNodes: new Set([
11
+ 'if_statement',
12
+ 'elif_clause',
13
+ 'else_clause',
14
+ 'for_statement',
15
+ 'while_statement',
16
+ 'except_clause',
17
+ 'conditional_expression',
18
+ 'match_statement',
19
+ ]),
20
+ caseNodes: new Set(['case_clause']),
21
+ logicalOperators: new Set(['and', 'or']),
22
+ logicalNodeType: 'boolean_operator',
23
+ optionalChainType: null,
24
+ nestingNodes: new Set([
25
+ 'if_statement',
26
+ 'for_statement',
27
+ 'while_statement',
28
+ 'except_clause',
29
+ 'conditional_expression',
30
+ ]),
31
+ functionNodes: new Set(['function_definition', 'lambda']),
32
+ ifNodeType: 'if_statement',
33
+ elseNodeType: 'else_clause',
34
+ elifNodeType: 'elif_clause',
35
+ elseViaAlternative: false,
36
+ switchLikeNodes: new Set(['match_statement']),
37
+ };
38
+
39
+ // ─── Halstead ─────────────────────────────────────────────────────────────
40
+
41
+ export const halstead = {
42
+ operatorLeafTypes: new Set([
43
+ '+',
44
+ '-',
45
+ '*',
46
+ '/',
47
+ '%',
48
+ '**',
49
+ '//',
50
+ '=',
51
+ '+=',
52
+ '-=',
53
+ '*=',
54
+ '/=',
55
+ '%=',
56
+ '**=',
57
+ '//=',
58
+ '&=',
59
+ '|=',
60
+ '^=',
61
+ '<<=',
62
+ '>>=',
63
+ '==',
64
+ '!=',
65
+ '<',
66
+ '>',
67
+ '<=',
68
+ '>=',
69
+ 'and',
70
+ 'or',
71
+ 'not',
72
+ '&',
73
+ '|',
74
+ '^',
75
+ '~',
76
+ '<<',
77
+ '>>',
78
+ 'if',
79
+ 'else',
80
+ 'elif',
81
+ 'for',
82
+ 'while',
83
+ 'with',
84
+ 'try',
85
+ 'except',
86
+ 'finally',
87
+ 'raise',
88
+ 'return',
89
+ 'yield',
90
+ 'await',
91
+ 'pass',
92
+ 'break',
93
+ 'continue',
94
+ 'import',
95
+ 'from',
96
+ 'as',
97
+ 'in',
98
+ 'is',
99
+ 'lambda',
100
+ 'del',
101
+ '.',
102
+ ',',
103
+ ':',
104
+ '@',
105
+ '->',
106
+ ]),
107
+ operandLeafTypes: new Set([
108
+ 'identifier',
109
+ 'integer',
110
+ 'float',
111
+ 'string_content',
112
+ 'true',
113
+ 'false',
114
+ 'none',
115
+ ]),
116
+ compoundOperators: new Set(['call', 'subscript', 'attribute']),
117
+ skipTypes: new Set([]),
118
+ };
119
+
120
+ // ─── CFG ──────────────────────────────────────────────────────────────────
121
+
122
+ export const cfg = makeCfgRules({
123
+ ifNode: 'if_statement',
124
+ elifNode: 'elif_clause',
125
+ elseClause: 'else_clause',
126
+ forNodes: new Set(['for_statement']),
127
+ whileNode: 'while_statement',
128
+ switchNode: 'match_statement',
129
+ caseNode: 'case_clause',
130
+ tryNode: 'try_statement',
131
+ catchNode: 'except_clause',
132
+ finallyNode: 'finally_clause',
133
+ returnNode: 'return_statement',
134
+ throwNode: 'raise_statement',
135
+ breakNode: 'break_statement',
136
+ continueNode: 'continue_statement',
137
+ blockNode: 'block',
138
+ functionNodes: new Set(['function_definition']),
139
+ });
140
+
141
+ // ─── Dataflow ─────────────────────────────────────────────────────────────
142
+
143
+ export const dataflow = makeDataflowRules({
144
+ functionNodes: new Set(['function_definition', 'lambda']),
145
+ defaultParamType: 'default_parameter',
146
+ restParamType: 'list_splat_pattern',
147
+ returnNode: 'return_statement',
148
+ varDeclaratorNode: null,
149
+ assignmentNode: 'assignment',
150
+ assignLeftField: 'left',
151
+ assignRightField: 'right',
152
+ callNode: 'call',
153
+ callFunctionField: 'function',
154
+ callArgsField: 'arguments',
155
+ spreadType: 'list_splat',
156
+ memberNode: 'attribute',
157
+ memberObjectField: 'object',
158
+ memberPropertyField: 'attribute',
159
+ awaitNode: 'await',
160
+ mutatingMethods: new Set([
161
+ 'append',
162
+ 'extend',
163
+ 'insert',
164
+ 'pop',
165
+ 'remove',
166
+ 'clear',
167
+ 'sort',
168
+ 'reverse',
169
+ 'add',
170
+ 'discard',
171
+ 'update',
172
+ ]),
173
+ extractParamName(node) {
174
+ if (node.type === 'typed_parameter' || node.type === 'typed_default_parameter') {
175
+ for (const c of node.namedChildren) {
176
+ if (c.type === 'identifier') return [c.text];
177
+ }
178
+ return null;
179
+ }
180
+ if (node.type === 'default_parameter') {
181
+ const nameNode = node.childForFieldName('name');
182
+ return nameNode ? [nameNode.text] : null;
183
+ }
184
+ if (node.type === 'list_splat_pattern' || node.type === 'dictionary_splat_pattern') {
185
+ for (const c of node.namedChildren) {
186
+ if (c.type === 'identifier') return [c.text];
187
+ }
188
+ return null;
189
+ }
190
+ return null;
191
+ },
192
+ });
193
+
194
+ // ─── AST Node Types ───────────────────────────────────────────────────────
195
+
196
+ export const astTypes = null;