refactor: remove dead scaffolding from parser and edit

edit.ValidateLanguage had zero callers (only its own godoc referenced it) —
removed.

yaml_json.go: contrary to the audit's claim, the file is NOT entirely dead —
ParseYAML/ParseJSON are live via the Parse() dispatch (parser.go:198-200) and
are kept with their tests. Removed only the genuinely unreachable scaffolding
that nothing constructs or calls: the YAMLNode/JSONNode types, WalkYAML,
GetYAMLNodeText, GetYAMLNodeLocation, QueryYAML, QueryJSON, ValidateYAML,
ValidateJSON, and ToSitterTree, plus their now-orphaned tests. YAML/JSON parsing
behavior is unchanged (TestParseYAML/TestParseJSON/TestRegistryParse_YAML_JSON
still pass).
This commit is contained in:
2026-06-21 02:21:37 +01:00
parent f4c34c41e4
commit d24c8218fd
3 changed files with 8 additions and 237 deletions
-11
View File
@@ -881,14 +881,3 @@ func truncateString(s string, maxLen int) string {
} }
return s[:util.RuneBoundary(s, maxLen-3)] + "..." return s[:util.RuneBoundary(s, maxLen-3)] + "..."
} }
// ValidateLanguage checks if AST editing is supported for a file.
// Returns nil for supported languages, error for unsupported.
// Note: Text-based editing is always available regardless of this check.
func ValidateLanguage(filename string) error {
lang := protocol.DetectLanguage(filename)
if lang == protocol.LangUnknown {
return fmt.Errorf("unsupported file type for AST editing: %s (text-based editing is available)", filename)
}
return nil
}
+8 -145
View File
@@ -4,70 +4,45 @@ package parser
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"fmt"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"github.com/lukaszraczylo/mcp-filepuff/pkg/errors" "github.com/lukaszraczylo/mcp-filepuff/pkg/errors"
"github.com/lukaszraczylo/mcp-filepuff/pkg/protocol" "github.com/lukaszraczylo/mcp-filepuff/pkg/protocol"
sitter "github.com/smacker/go-tree-sitter"
) )
// YAMLNode wraps yaml.Node to provide tree-sitter-like interface // ParseYAML parses YAML content and returns a tree-sitter-compatible result.
type YAMLNode struct { // YAML does not use tree-sitter, so the returned ParseResult.Tree is nil.
*yaml.Node
Content []byte
}
// JSONNode represents a JSON AST node
type JSONNode struct {
Value any
Type string
Children []*JSONNode
Line int
Column int
}
// ParseYAML parses YAML content and returns a tree-sitter-compatible result
func (r *Registry) ParseYAML(ctx context.Context, filename string, content []byte) (*ParseResult, error) { func (r *Registry) ParseYAML(ctx context.Context, filename string, content []byte) (*ParseResult, error) {
// Check file size
if len(content) > maxFileSize { if len(content) > maxFileSize {
return nil, errors.NewFileTooLarge(filename, int64(len(content)), maxFileSize) return nil, errors.NewFileTooLarge(filename, int64(len(content)), maxFileSize)
} }
// Parse YAML
var root yaml.Node var root yaml.Node
if err := yaml.Unmarshal(content, &root); err != nil { if err := yaml.Unmarshal(content, &root); err != nil {
return nil, errors.NewParseError("yaml", filename, err) return nil, errors.NewParseError("yaml", filename, err)
} }
// Extract syntax errors from YAML parse
syntaxErrors := extractYAMLErrors()
// Create a pseudo tree-sitter tree for compatibility
// We'll use nil for the tree since YAML doesn't use tree-sitter
return &ParseResult{ return &ParseResult{
Tree: nil, // YAML uses yaml.Node instead Tree: nil, // YAML uses yaml.Node instead of tree-sitter
Language: protocol.LangYAML, Language: protocol.LangYAML,
Errors: syntaxErrors, Errors: extractYAMLErrors(),
Content: content, Content: content,
}, nil }, nil
} }
// ParseJSON parses JSON content and returns a tree-sitter-compatible result // ParseJSON parses JSON content and returns a tree-sitter-compatible result.
// JSON does not use tree-sitter, so the returned ParseResult.Tree is nil.
func (r *Registry) ParseJSON(ctx context.Context, filename string, content []byte) (*ParseResult, error) { func (r *Registry) ParseJSON(ctx context.Context, filename string, content []byte) (*ParseResult, error) {
// Check file size
if len(content) > maxFileSize { if len(content) > maxFileSize {
return nil, errors.NewFileTooLarge(filename, int64(len(content)), maxFileSize) return nil, errors.NewFileTooLarge(filename, int64(len(content)), maxFileSize)
} }
// Parse JSON to validate syntax
var jsonData any var jsonData any
if err := json.Unmarshal(content, &jsonData); err != nil { if err := json.Unmarshal(content, &jsonData); err != nil {
return nil, errors.NewParseError("json", filename, err) return nil, errors.NewParseError("json", filename, err)
} }
// JSON parsing succeeded, no syntax errors
return &ParseResult{ return &ParseResult{
Tree: nil, // JSON uses native Go structures Tree: nil, // JSON uses native Go structures
Language: protocol.LangJSON, Language: protocol.LangJSON,
@@ -76,120 +51,8 @@ func (r *Registry) ParseJSON(ctx context.Context, filename string, content []byt
}, nil }, nil
} }
// extractYAMLErrors extracts errors from YAML nodes // extractYAMLErrors returns YAML syntax errors. yaml.Unmarshal already reports
// parse errors, so reaching here means the document was syntactically valid.
func extractYAMLErrors() []SyntaxError { func extractYAMLErrors() []SyntaxError {
// YAML parser already validates during unmarshal
// If we got here, there are no syntax errors
// However, we could add semantic validation here in the future
return []SyntaxError{} return []SyntaxError{}
} }
// WalkYAML walks a YAML AST and calls fn for each node
func WalkYAML(node *yaml.Node, fn func(*yaml.Node) bool) {
if node == nil || !fn(node) {
return
}
for _, child := range node.Content {
WalkYAML(child, fn)
}
}
// GetYAMLNodeText returns the text representation of a YAML node
func GetYAMLNodeText(node *yaml.Node) string {
if node == nil {
return ""
}
switch node.Kind {
case yaml.DocumentNode:
if len(node.Content) > 0 {
return GetYAMLNodeText(node.Content[0])
}
return ""
case yaml.MappingNode:
return node.Value
case yaml.SequenceNode:
return node.Value
case yaml.ScalarNode:
return node.Value
case yaml.AliasNode:
return node.Value
default:
return ""
}
}
// GetYAMLNodeLocation returns the location of a YAML node
func GetYAMLNodeLocation(node *yaml.Node) protocol.Location {
if node == nil {
return protocol.Location{Line: 1, Column: 1}
}
return protocol.Location{
Line: node.Line,
Column: node.Column,
}
}
// QueryYAML performs a simple query on YAML content
// Example: "$.metadata.name" to find the name field in metadata
func QueryYAML(content []byte, query string) ([]*yaml.Node, error) {
var root yaml.Node
if err := yaml.Unmarshal(content, &root); err != nil {
return nil, fmt.Errorf("failed to parse YAML: %w", err)
}
// Simple path-based query implementation
// This is a basic implementation - can be extended with more sophisticated queries
var results []*yaml.Node
WalkYAML(&root, func(node *yaml.Node) bool {
if node.Value == query || node.Tag == query {
results = append(results, node)
}
return true
})
return results, nil
}
// QueryJSON performs a simple query on JSON content
func QueryJSON(content []byte, query string) ([]any, error) {
var data any
if err := json.Unmarshal(content, &data); err != nil {
return nil, fmt.Errorf("failed to parse JSON: %w", err)
}
// Basic implementation - can be extended with JSONPath support
var results []any
// For now, just validate that it's valid JSON
results = append(results, data)
return results, nil
}
// ValidateYAML validates YAML content without parsing to full AST
func ValidateYAML(content []byte) error {
var node yaml.Node
if err := yaml.Unmarshal(content, &node); err != nil {
return fmt.Errorf("YAML validation failed: %w", err)
}
return nil
}
// ValidateJSON validates JSON content
func ValidateJSON(content []byte) error {
var data any
if err := json.Unmarshal(content, &data); err != nil {
return fmt.Errorf("JSON validation failed: %w", err)
}
return nil
}
// ToSitterTree is a placeholder that returns nil for YAML/JSON
// These formats don't use tree-sitter, but we keep this for interface compatibility
func (yn *YAMLNode) ToSitterTree() *sitter.Tree {
return nil
}
-81
View File
@@ -4,8 +4,6 @@ import (
"context" "context"
"testing" "testing"
"gopkg.in/yaml.v3"
"github.com/lukaszraczylo/mcp-filepuff/pkg/protocol" "github.com/lukaszraczylo/mcp-filepuff/pkg/protocol"
) )
@@ -202,82 +200,3 @@ version: 1.0.0`)
t.Errorf("expected YAML language for .yml extension, got %s", ymlResult.Language) t.Errorf("expected YAML language for .yml extension, got %s", ymlResult.Language)
} }
} }
func TestWalkYAML(t *testing.T) {
content := []byte(`metadata:
name: test
labels:
app: myapp
env: prod`)
var root yaml.Node
if err := yaml.Unmarshal(content, &root); err != nil {
t.Fatalf("failed to parse YAML: %v", err)
}
nodeCount := 0
WalkYAML(&root, func(node *yaml.Node) bool {
nodeCount++
return true
})
if nodeCount == 0 {
t.Error("expected to visit nodes, but count is 0")
}
}
func TestValidateYAML(t *testing.T) {
tests := []struct {
name string
content []byte
shouldError bool
}{
{
name: "valid YAML",
content: []byte("name: test\nvalue: 100"),
shouldError: false,
},
{
name: "invalid YAML",
content: []byte("name: test\n bad:\n[unclosed"),
shouldError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateYAML(tt.content)
if (err != nil) != tt.shouldError {
t.Errorf("ValidateYAML() error = %v, shouldError = %v", err, tt.shouldError)
}
})
}
}
func TestValidateJSON(t *testing.T) {
tests := []struct {
name string
content []byte
shouldError bool
}{
{
name: "valid JSON",
content: []byte(`{"name": "test", "value": 100}`),
shouldError: false,
},
{
name: "invalid JSON",
content: []byte(`{"name": "test", "value": 100`),
shouldError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateJSON(tt.content)
if (err != nil) != tt.shouldError {
t.Errorf("ValidateJSON() error = %v, shouldError = %v", err, tt.shouldError)
}
})
}
}