add omit test files and only frontend

This commit is contained in:
2026-08-27 14:00:24 +01:00
parent 95b5a7b70c
commit 1f5243d953
6 changed files with 158 additions and 24 deletions
+5
View File
@@ -1,3 +1,4 @@
// internal/config/config.go
package config
import (
@@ -79,6 +80,7 @@ type Config struct {
DrivePath string
VerticalSlices bool
SkipFrontend bool
OmitTest bool
}
func PrintUsage() {
@@ -104,6 +106,7 @@ func Parse() (*Config, error) {
drivePath string
verticalSlices bool
skipFrontend bool
omitTest bool
)
flag.StringVar(&input, "i", "", "single file input (append mode only)")
@@ -119,6 +122,7 @@ func Parse() (*Config, error) {
flag.StringVar(&drivePath, "drive-path", "", "full remote path on Proton Drive (requires --proton-drive)")
flag.BoolVar(&verticalSlices, "vertical-slices", false, "split output into root file + one markdown per top-level directory")
flag.BoolVar(&skipFrontend, "skip-frontend", false, "omit frontend file types (.html, .css, .js, .ts, .vue, .svelte, etc.)")
flag.BoolVar(&omitTest, "omit-test", false, "exclude test files (Go *_test.go, Java *Test.java) and strip #[cfg(test)] blocks from Rust")
flag.Usage = PrintUsage
flag.Parse()
@@ -161,6 +165,7 @@ func Parse() (*Config, error) {
DrivePath: drivePath,
VerticalSlices: verticalSlices,
SkipFrontend: skipFrontend,
OmitTest: omitTest,
}
if input != "" {
+24
View File
@@ -1,3 +1,4 @@
// internal/filter/filter.go
package filter
import (
@@ -10,6 +11,7 @@ type Filter struct {
MaxSize int64
Extensions []string
Ignores []string
OmitTest bool
}
func (f *Filter) ShouldSkipDir(name string) bool {
@@ -48,6 +50,28 @@ func (f *Filter) ShouldSkipFile(path, name string, info os.FileInfo) bool {
return true
}
if f.OmitTest && isTestFile(path, name) {
return true
}
return false
}
func isTestFile(path, name string) bool {
ext := strings.ToLower(filepath.Ext(path))
switch ext {
case ".go":
return strings.HasSuffix(strings.ToLower(name), "_test.go")
case ".java":
base := strings.TrimSuffix(name, filepath.Ext(name))
if strings.HasSuffix(base, "Test") || strings.HasSuffix(base, "Tests") {
return true
}
slashPath := filepath.ToSlash(path)
return strings.Contains(slashPath, "/src/test/")
}
return false
}
+70 -18
View File
@@ -1,3 +1,4 @@
// internal/renderer/renderer.go
package renderer
import (
@@ -14,7 +15,6 @@ import (
const fenceChars = "~~~"
// Write writes a single markdown file with tree and file contents.
func Write(result *walker.Result, outputPath string, appendMode bool, singleFile bool) error {
flags := os.O_CREATE | os.O_WRONLY
if appendMode {
@@ -55,7 +55,7 @@ func Write(result *walker.Result, outputPath string, appendMode bool, singleFile
for _, entry := range result.Entries {
fullPath := filepath.Join(result.AbsRoot, entry.RelPath)
content, err := readFile(fullPath)
content, err := readFileForOutput(fullPath, result.OmitTest)
if err != nil {
fmt.Fprintf(os.Stderr, "warning: cannot read %s: %v\n", entry.RelPath, err)
continue
@@ -82,8 +82,6 @@ func Write(result *walker.Result, outputPath string, appendMode bool, singleFile
return err
}
// WriteSlices generates a root markdown file plus one markdown per top-level directory.
// Returns the list of generated file paths.
func WriteSlices(result *walker.Result, outputDir, repoName string) ([]string, error) {
entries := result.Entries
if len(entries) == 0 {
@@ -109,16 +107,14 @@ func WriteSlices(result *walker.Result, outputDir, repoName string) ([]string, e
var generated []string
// Write root file as index_<reponame>.md
indexBasename := "index_" + repoName + ".md"
rootPath := filepath.Join(outputDir, indexBasename)
generated = append(generated, rootPath)
if err := writeRootSlice(rootPath, absRoot, rootName, repoName, rootFiles, topLevelDirs); err != nil {
if err := writeRootSlice(rootPath, absRoot, rootName, repoName, rootFiles, topLevelDirs, result.OmitTest); err != nil {
return nil, fmt.Errorf("failed to write root slice: %w", err)
}
// Write each top-level directory slice into a mirroring subdirectory
var dirNames []string
for k := range topLevelDirs {
dirNames = append(dirNames, k)
@@ -137,7 +133,6 @@ func WriteSlices(result *walker.Result, outputDir, repoName string) ([]string, e
absDir := filepath.Join(absRoot, dirName)
dirEntries := topLevelDirs[dirName]
// Strip dirName prefix for tree building only
treeEntries := make([]walker.Entry, len(dirEntries))
for i, e := range dirEntries {
sepIdx := strings.Index(e.RelPath, string(filepath.Separator))
@@ -151,7 +146,7 @@ func WriteSlices(result *walker.Result, outputDir, repoName string) ([]string, e
}
}
if err := writeDirSlice(slicePath, absDir, absRoot, dirName, treeEntries, dirEntries, indexBasename); err != nil {
if err := writeDirSlice(slicePath, absDir, absRoot, dirName, treeEntries, dirEntries, indexBasename, result.OmitTest); err != nil {
return nil, fmt.Errorf("failed to write slice %s: %w", sliceName, err)
}
}
@@ -159,7 +154,7 @@ func WriteSlices(result *walker.Result, outputDir, repoName string) ([]string, e
return generated, nil
}
func writeRootSlice(path, absRoot, rootName, repoName string, rootFiles []walker.Entry, topLevelDirs map[string][]walker.Entry) error {
func writeRootSlice(path, absRoot, rootName, repoName string, rootFiles []walker.Entry, topLevelDirs map[string][]walker.Entry, omitTest bool) error {
f, err := os.Create(path)
if err != nil {
return fmt.Errorf("cannot create root file: %w", err)
@@ -170,14 +165,12 @@ func writeRootSlice(path, absRoot, rootName, repoName string, rootFiles []walker
fmt.Fprintf(&sb, "# %s [ROOT]\n\n", absRoot)
// Build combined tree with references
treeLines := buildTreeWithRefs(rootName, repoName, topLevelDirs, rootFiles)
sb.WriteString("## Directory Tree\n\n")
sb.WriteString(fenceChars + "\n")
sb.WriteString(treeLines)
sb.WriteString(fenceChars + "\n\n")
// Vertical slices index for LLM navigation
sb.WriteString("## Vertical Slices Index\n\n")
sb.WriteString("These files contain the full contents of each top-level directory.\n")
sb.WriteString("Read the relevant slice file for detailed source code.\n\n")
@@ -211,7 +204,7 @@ func writeRootSlice(path, absRoot, rootName, repoName string, rootFiles []walker
for _, entry := range rootFiles {
fullPath := filepath.Join(absRoot, entry.RelPath)
content, err := readFile(fullPath)
content, err := readFileForOutput(fullPath, omitTest)
if err != nil {
fmt.Fprintf(os.Stderr, "warning: cannot read %s: %v\n", entry.RelPath, err)
continue
@@ -238,7 +231,7 @@ func writeRootSlice(path, absRoot, rootName, repoName string, rootFiles []walker
return err
}
func writeDirSlice(path, absDir, absRoot, dirName string, treeEntries, fileEntries []walker.Entry, rootFileName string) error {
func writeDirSlice(path, absDir, absRoot, dirName string, treeEntries, fileEntries []walker.Entry, rootFileName string, omitTest bool) error {
f, err := os.Create(path)
if err != nil {
return fmt.Errorf("cannot create slice file: %w", err)
@@ -266,7 +259,7 @@ func writeDirSlice(path, absDir, absRoot, dirName string, treeEntries, fileEntri
for _, entry := range fileEntries {
fullPath := filepath.Join(absRoot, entry.RelPath)
content, err := readFile(fullPath)
content, err := readFileForOutput(fullPath, omitTest)
if err != nil {
fmt.Fprintf(os.Stderr, "warning: cannot read %s: %v\n", entry.RelPath, err)
continue
@@ -298,19 +291,16 @@ func buildTreeWithRefs(rootName, repoName string, topLevelDirs map[string][]walk
sb.WriteString(rootName)
sb.WriteString("/\n")
// Collect and sort directory names
var dirNames []string
for k := range topLevelDirs {
dirNames = append(dirNames, k)
}
sort.Strings(dirNames)
// Sort root files
sort.Slice(rootFiles, func(i, j int) bool {
return rootFiles[i].RelPath < rootFiles[j].RelPath
})
// Merge directories and files into a single sorted list for display
type treeItem struct {
name string
isDir bool
@@ -441,6 +431,68 @@ func readFile(path string) (string, error) {
return content, nil
}
func readFileForOutput(fullPath string, omitTest bool) (string, error) {
content, err := readFile(fullPath)
if err != nil {
return "", err
}
if omitTest && strings.EqualFold(filepath.Ext(fullPath), ".rs") {
content = stripTestBlocks(content)
}
return content, nil
}
func stripTestBlocks(content string) string {
lines := strings.Split(content, "\n")
var result []string
i := 0
for i < len(lines) {
line := lines[i]
trimmed := strings.TrimSpace(line)
if isCfgTestAttr(trimmed) {
braceDepth := 0
foundBrace := false
for i < len(lines) {
line := lines[i]
if !foundBrace {
if strings.Contains(line, "{") {
braceDepth += strings.Count(line, "{") - strings.Count(line, "}")
foundBrace = true
}
i++
continue
}
braceDepth += strings.Count(line, "{") - strings.Count(line, "}")
i++
if braceDepth <= 0 {
break
}
}
continue
}
result = append(result, line)
i++
}
if len(result) == 0 {
return ""
}
return strings.Join(result, "\n")
}
func isCfgTestAttr(line string) bool {
return strings.Contains(line, "#[cfg(test)]") ||
strings.Contains(line, "#[cfg(all(test") ||
strings.Contains(line, "#[cfg(any(test")
}
func extToLang(ext string) string {
mapping := map[string]string{
".go": "go",
+6 -2
View File
@@ -1,3 +1,4 @@
// internal/walker/walker.go
package walker
import (
@@ -20,6 +21,7 @@ type Result struct {
Entries []Entry
AbsRoot string
SingleFile bool
OmitTest bool
}
func Run(cfg *config.Config) (*Result, error) {
@@ -43,6 +45,7 @@ func processSingleFile(cfg *config.Config) (*Result, error) {
MaxSize: cfg.MaxSize,
Extensions: cfg.Extensions,
Ignores: cfg.Ignores,
OmitTest: cfg.OmitTest,
}
if flt.ShouldSkipFile(cfg.AbsRoot, filepath.Base(cfg.AbsRoot), info) {
@@ -53,8 +56,8 @@ func processSingleFile(cfg *config.Config) (*Result, error) {
Entries: []Entry{{RelPath: filepath.Base(cfg.AbsRoot), Size: info.Size()}},
AbsRoot: filepath.Dir(cfg.AbsRoot),
SingleFile: true,
OmitTest: cfg.OmitTest,
}, nil
}
func walkDirectory(cfg *config.Config) (*Result, error) {
@@ -62,9 +65,10 @@ func walkDirectory(cfg *config.Config) (*Result, error) {
MaxSize: cfg.MaxSize,
Extensions: cfg.Extensions,
Ignores: cfg.Ignores,
OmitTest: cfg.OmitTest,
}
result := &Result{AbsRoot: cfg.AbsRoot}
result := &Result{AbsRoot: cfg.AbsRoot, OmitTest: cfg.OmitTest}
err := filepath.WalkDir(cfg.AbsRoot, func(path string, d fs.DirEntry, err error) error {
if err != nil {