Skip to content

Commit 0e95665

Browse files
authored
fix: ruby treesitter (#1881)
* fix: ruby node fixes * fix: more ruby node changes
1 parent b21725e commit 0e95665

1 file changed

Lines changed: 54 additions & 3 deletions

File tree

pkg/languages/ruby/pattern/pattern.go

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ var (
2424
unanchoredPatternNodeTypes = []string{"pair", "keyword_parameter"}
2525
allowedPatternQueryTypes = []string{"identifier", "constant", "_", "call", "simple_symbol"}
2626

27-
classPatternErrorRegex = regexp.MustCompile(`\Aclass\s*\z`)
27+
classPatternErrorRegex = regexp.MustCompile(`\Aclass\s*\z`)
28+
superclassPatternErrorRegex = regexp.MustCompile(`<\s*\z`)
2829
)
2930

3031
type Pattern struct {
@@ -101,7 +102,30 @@ func (*Pattern) AnonymousParentTypes() []string {
101102
}
102103

103104
func (*Pattern) IsContainer(node *tree.Node) bool {
104-
return slices.Contains(patternMatchNodeContainerTypes, node.Type())
105+
if slices.Contains(patternMatchNodeContainerTypes, node.Type()) {
106+
return true
107+
}
108+
// Treat body_statement as a container so pattern variables skip over it
109+
// and capture the actual content inside. In the new tree-sitter grammar,
110+
// class/module/block bodies are wrapped in body_statement.
111+
if node.Type() == "body_statement" {
112+
return true
113+
}
114+
return false
115+
}
116+
117+
func (*Pattern) IsLeaf(node *tree.Node) bool {
118+
// Treat bare method calls (no receiver, no arguments) as leaf nodes.
119+
// In the new tree-sitter grammar, `find_by!` is parsed as:
120+
// call(method: identifier)
121+
// We want patterns like `find_by!` to match the identifier directly,
122+
// not require a full call node structure.
123+
if node.Type() == "call" {
124+
if node.ChildByFieldName("receiver") == nil && node.ChildByFieldName("arguments") == nil {
125+
return true
126+
}
127+
}
128+
return false
105129
}
106130

107131
func (*Pattern) IsAnchored(node *tree.Node) (bool, bool) {
@@ -211,7 +235,29 @@ func (*Pattern) TranslateContent(fromNodeType, toNodeType, content string) strin
211235
}
212236

213237
func (*Pattern) IsRoot(node *tree.Node) bool {
214-
return !slices.Contains([]string{"program"}, node.Type())
238+
// Skip program node
239+
if node.Type() == "program" {
240+
return false
241+
}
242+
243+
// Skip bare method calls (no receiver, no arguments) and use their
244+
// method identifier as the root instead. In the new tree-sitter grammar,
245+
// `find_by!` is parsed as call(method: identifier). We want auxiliary
246+
// patterns like `find_by!` to compile to an identifier query, not a call query.
247+
if node.Type() == "call" {
248+
if node.ChildByFieldName("receiver") == nil && node.ChildByFieldName("arguments") == nil {
249+
return false
250+
}
251+
}
252+
253+
// Skip body_statement nodes and use the actual content inside.
254+
// In the new tree-sitter grammar, class/module/block bodies are wrapped
255+
// in body_statement. Patterns should match the contents, not the wrapper.
256+
if node.Type() == "body_statement" {
257+
return false
258+
}
259+
260+
return true
215261
}
216262

217263
func (*Pattern) FixupVariableDummyValue(input []byte, node *tree.Node, dummyValue string) string {
@@ -221,9 +267,14 @@ func (*Pattern) FixupVariableDummyValue(input []byte, node *tree.Node, dummyValu
221267
}
222268

223269
errorPrefix := input[ancestor.ContentStart.Byte:node.ContentStart.Byte]
270+
// Capitalize class name: class $<NAME>
224271
if classPatternErrorRegex.Match(errorPrefix) {
225272
return strings.ToUpper(string(dummyValue[0])) + dummyValue[1:]
226273
}
274+
// Capitalize superclass: class Foo < $<PARENT>
275+
if superclassPatternErrorRegex.Match(errorPrefix) {
276+
return strings.ToUpper(string(dummyValue[0])) + dummyValue[1:]
277+
}
227278
}
228279

229280
return dummyValue

0 commit comments

Comments
 (0)