mirror of
https://github.com/danielmiessler/Fabric.git
synced 2026-01-08 22:08:03 -05:00
- Rename `code_helper` command to `code2context` throughout codebase - Update README.md table of contents and references - Update installation instructions with new binary name - Update all usage examples in main.go help text - Update create_coding_feature pattern documentation - Rename cmd directory from code_helper to code2context
251 lines
5.5 KiB
Go
251 lines
5.5 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// FileItem represents a file in the project
|
|
type FileItem struct {
|
|
Type string `json:"type"`
|
|
Name string `json:"name"`
|
|
Content string `json:"content,omitempty"`
|
|
Contents []FileItem `json:"contents,omitempty"`
|
|
}
|
|
|
|
// ProjectData represents the entire project structure with instructions
|
|
type ProjectData struct {
|
|
Files []FileItem `json:"files"`
|
|
Instructions struct {
|
|
Type string `json:"type"`
|
|
Name string `json:"name"`
|
|
Details string `json:"details"`
|
|
} `json:"instructions"`
|
|
Report struct {
|
|
Type string `json:"type"`
|
|
Directories int `json:"directories"`
|
|
Files int `json:"files"`
|
|
} `json:"report"`
|
|
}
|
|
|
|
// ScanDirectory scans a directory and returns a JSON representation of its structure
|
|
func ScanDirectory(rootDir string, maxDepth int, instructions string, ignoreList []string) ([]byte, error) {
|
|
// Count totals for report
|
|
dirCount := 1
|
|
fileCount := 0
|
|
|
|
// Create root directory item
|
|
rootItem := FileItem{
|
|
Type: "directory",
|
|
Name: rootDir,
|
|
Contents: []FileItem{},
|
|
}
|
|
|
|
// Walk through the directory
|
|
err := filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Skip .git directory
|
|
if strings.Contains(path, ".git") {
|
|
if info.IsDir() {
|
|
return filepath.SkipDir
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Check if path matches any ignore pattern
|
|
relPath, err := filepath.Rel(rootDir, path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, pattern := range ignoreList {
|
|
if strings.Contains(relPath, pattern) {
|
|
if info.IsDir() {
|
|
return filepath.SkipDir
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
if relPath == "." {
|
|
return nil
|
|
}
|
|
|
|
depth := len(strings.Split(relPath, string(filepath.Separator)))
|
|
if depth > maxDepth {
|
|
if info.IsDir() {
|
|
return filepath.SkipDir
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Create directory structure
|
|
if info.IsDir() {
|
|
dirCount++
|
|
} else {
|
|
fileCount++
|
|
|
|
// Read file content
|
|
content, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return fmt.Errorf("error reading file %s: %v", path, err)
|
|
}
|
|
|
|
// Add file to appropriate parent directory
|
|
addFileToDirectory(&rootItem, relPath, string(content), rootDir)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Create final data structure
|
|
var data []any
|
|
data = append(data, rootItem)
|
|
|
|
// Add report
|
|
reportItem := map[string]any{
|
|
"type": "report",
|
|
"directories": dirCount,
|
|
"files": fileCount,
|
|
}
|
|
data = append(data, reportItem)
|
|
|
|
// Add instructions
|
|
instructionsItem := map[string]any{
|
|
"type": "instructions",
|
|
"name": "code_change_instructions",
|
|
"details": instructions,
|
|
}
|
|
data = append(data, instructionsItem)
|
|
|
|
return json.MarshalIndent(data, "", " ")
|
|
}
|
|
|
|
// ScanFiles scans specific files and returns a JSON representation
|
|
func ScanFiles(files []string, instructions string) ([]byte, error) {
|
|
fileCount := 0
|
|
dirSet := make(map[string]bool)
|
|
|
|
// Create root directory item
|
|
rootItem := FileItem{
|
|
Type: "directory",
|
|
Name: ".",
|
|
Contents: []FileItem{},
|
|
}
|
|
|
|
for _, filePath := range files {
|
|
// Skip directories
|
|
info, err := os.Stat(filePath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error accessing file %s: %v", filePath, err)
|
|
}
|
|
if info.IsDir() {
|
|
continue
|
|
}
|
|
|
|
// Track unique directories
|
|
dir := filepath.Dir(filePath)
|
|
if dir != "." {
|
|
dirSet[dir] = true
|
|
}
|
|
|
|
fileCount++
|
|
|
|
// Read file content
|
|
content, err := os.ReadFile(filePath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error reading file %s: %v", filePath, err)
|
|
}
|
|
|
|
// Clean path for consistent handling
|
|
cleanPath := filepath.Clean(filePath)
|
|
if strings.HasPrefix(cleanPath, "./") {
|
|
cleanPath = cleanPath[2:]
|
|
}
|
|
|
|
// Add file to the structure
|
|
addFileToDirectory(&rootItem, cleanPath, string(content), ".")
|
|
}
|
|
|
|
// Create final data structure
|
|
var data []any
|
|
data = append(data, rootItem)
|
|
|
|
// Add report
|
|
reportItem := map[string]any{
|
|
"type": "report",
|
|
"directories": len(dirSet) + 1,
|
|
"files": fileCount,
|
|
}
|
|
data = append(data, reportItem)
|
|
|
|
// Add instructions
|
|
instructionsItem := map[string]any{
|
|
"type": "instructions",
|
|
"name": "code_change_instructions",
|
|
"details": instructions,
|
|
}
|
|
data = append(data, instructionsItem)
|
|
|
|
return json.MarshalIndent(data, "", " ")
|
|
}
|
|
|
|
// addFileToDirectory adds a file to the correct directory in the structure
|
|
func addFileToDirectory(root *FileItem, path, content, rootDir string) {
|
|
parts := strings.Split(path, string(filepath.Separator))
|
|
|
|
// If this is a file at the root level
|
|
if len(parts) == 1 {
|
|
root.Contents = append(root.Contents, FileItem{
|
|
Type: "file",
|
|
Name: parts[0],
|
|
Content: content,
|
|
})
|
|
return
|
|
}
|
|
|
|
// Otherwise, find or create the directory path
|
|
current := root
|
|
for i := 0; i < len(parts)-1; i++ {
|
|
dirName := parts[i]
|
|
found := false
|
|
|
|
// Look for existing directory
|
|
for j, item := range current.Contents {
|
|
if item.Type == "directory" && item.Name == dirName {
|
|
current = ¤t.Contents[j]
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
// Create directory if not found
|
|
if !found {
|
|
newDir := FileItem{
|
|
Type: "directory",
|
|
Name: dirName,
|
|
Contents: []FileItem{},
|
|
}
|
|
current.Contents = append(current.Contents, newDir)
|
|
current = ¤t.Contents[len(current.Contents)-1]
|
|
}
|
|
}
|
|
|
|
// Add the file to the current directory
|
|
current.Contents = append(current.Contents, FileItem{
|
|
Type: "file",
|
|
Name: parts[len(parts)-1],
|
|
Content: content,
|
|
})
|
|
}
|