add only frontend

This commit is contained in:
2026-08-27 14:20:33 +01:00
parent 1f5243d953
commit 2bbbf4e81e
5 changed files with 81 additions and 31 deletions
+24 -8
View File
@@ -14,6 +14,7 @@ Generate markdown documentation from directory structure. Optimized for LLM inge
- Configurable depth, file size limits, ignore patterns - Configurable depth, file size limits, ignore patterns
- Optional upload to Proton Drive after generating output - Optional upload to Proton Drive after generating output
- Skip frontend files (`.html`, `.css`, `.js`, etc.) - Skip frontend files (`.html`, `.css`, `.js`, etc.)
- Frontend only mode (include only frontend files and `README.md`)
- Omit test files and inline test blocks (Go, Java, Rust) - Omit test files and inline test blocks (Go, Java, Rust)
## Build ## Build
@@ -40,6 +41,9 @@ Generate markdown documentation from directory structure. Optimized for LLM inge
# Skip frontend files (.html, .css, .js, etc.) # Skip frontend files (.html, .css, .js, etc.)
dirmd -o output.md ~/repos/myproject --skip-frontend dirmd -o output.md ~/repos/myproject --skip-frontend
# Frontend only (include only frontend files and README.md)
dirmd -o output.md ~/repos/myproject --frontend-only
# Omit test files and inline test blocks # Omit test files and inline test blocks
# Go: excludes *_test.go # Go: excludes *_test.go
# Java: excludes *Test.java, *Tests.java, src/test/java/* # Java: excludes *Test.java, *Tests.java, src/test/java/*
@@ -47,7 +51,7 @@ Generate markdown documentation from directory structure. Optimized for LLM inge
dirmd -o output.md ~/repos/myproject --omit-test dirmd -o output.md ~/repos/myproject --omit-test
# Combine filters # Combine filters
dirmd -o output.md ~/repos/myproject --skip-frontend --omit-test dirmd -o output.md ~/repos/myproject --frontend-only --omit-test
# Generate and upload to Proton Drive (default: /my-files/md/<filename>) # Generate and upload to Proton Drive (default: /my-files/md/<filename>)
dirmd -o output.md ~/repos/myproject --proton-drive dirmd -o output.md ~/repos/myproject --proton-drive
@@ -67,18 +71,26 @@ The `--omit-test` flag removes test files and inline test blocks to reduce token
The Rust stripping works by detecting the `#[cfg(test)]` attribute, then tracking brace depth until the module closes. Nested braces in string literals may occasionally throw off the count, but this is acceptable for RAG use cases. The Rust stripping works by detecting the `#[cfg(test)]` attribute, then tracking brace depth until the module closes. Nested braces in string literals may occasionally throw off the count, but this is acceptable for RAG use cases.
Frontend files can be excluded separately with `--skip-frontend`: ## Frontend Filtering
| Extension Type | Excluded With `--skip-frontend` | Two complementary flags control frontend file inclusion:
|---------------|-------------------------------|
| Flag | Effect |
|------|--------|
| `--skip-frontend` | Exclude frontend files, keep everything else |
| `--frontend-only` | Include only frontend files and `README.md`, exclude everything else |
Frontend extensions covered:
| Type | Extensions |
|------|------------|
| Templates | `.html`, `.htm`, `.gohtml`, `.tmpl` | | Templates | `.html`, `.htm`, `.gohtml`, `.tmpl` |
| Stylesheets | `.css`, `.scss`, `.sass`, `.less` | | Stylesheets | `.css`, `.scss`, `.sass`, `.less` |
| Scripts | `.js`, `.jsx`, `.mjs`, `.cjs`, `.ts`, `.tsx` | | JavaScript | `.js`, `.jsx`, `.mjs`, `.cjs` |
| TypeScript | `.ts`, `.tsx` |
| Frameworks | `.vue`, `.svelte` | | Frameworks | `.vue`, `.svelte` |
These flags can be combined freely: `--skip-frontend` and `--frontend-only` are mutually exclusive. Both can be combined with `--omit-test`.
dirmd -o docs.md ~/repos/myproject --skip-frontend --omit-test
## Vertical Slices Mode ## Vertical Slices Mode
@@ -123,6 +135,7 @@ Output is designed for RAG ingestion and LLM context windows, not human presenta
| `--proton-drive` | Upload output to Proton Drive after writing locally | false | | `--proton-drive` | Upload output to Proton Drive after writing locally | false |
| `--drive-path` | Full remote path on Proton Drive (e.g. /my-files/md/report.md) | /my-files/md/<filename> | | `--drive-path` | Full remote path on Proton Drive (e.g. /my-files/md/report.md) | /my-files/md/<filename> |
| `--skip-frontend` | Omit frontend file types (.html, .css, .js, .ts, .vue, .svelte, etc.) | false | | `--skip-frontend` | Omit frontend file types (.html, .css, .js, .ts, .vue, .svelte, etc.) | false |
| `--frontend-only` | Include only frontend file types and README.md | false |
| `--omit-test` | Exclude test files (Go *_test.go, Java *Test.java) and strip #[cfg(test)] blocks from Rust | false | | `--omit-test` | Exclude test files (Go *_test.go, Java *Test.java) and strip #[cfg(test)] blocks from Rust | false |
## Proton Drive Integration ## Proton Drive Integration
@@ -158,6 +171,9 @@ For full documentation on the Proton Drive CLI, including installation, authenti
# Skip frontend and omit tests # Skip frontend and omit tests
dirmd -o docs.md ~/repos/project -f --skip-frontend --omit-test dirmd -o docs.md ~/repos/project -f --skip-frontend --omit-test
# Frontend only with test omission
dirmd -o docs.md ~/repos/project -f --frontend-only --omit-test
# Generate, then upload to default remote location # Generate, then upload to default remote location
dirmd -o docs.md ~/repos/project --proton-drive dirmd -o docs.md ~/repos/project --proton-drive
+10 -1
View File
@@ -1,4 +1,3 @@
// cmd/root.go
package cmd package cmd
import ( import (
@@ -42,6 +41,9 @@ Examples:
# Skip frontend files # Skip frontend files
dirmd -o ./docs ~/repos/myproject --skip-frontend dirmd -o ./docs ~/repos/myproject --skip-frontend
# Frontend only
dirmd -o ./docs ~/repos/myproject --frontend-only
# Omit test files and test blocks # Omit test files and test blocks
dirmd -o ./docs ~/repos/myproject --omit-test dirmd -o ./docs ~/repos/myproject --omit-test
@@ -65,6 +67,7 @@ Examples:
drivePath string drivePath string
verticalSlices bool verticalSlices bool
skipFrontend bool skipFrontend bool
frontendOnly bool
omitTest bool omitTest bool
) )
@@ -87,6 +90,7 @@ func init() {
rootCmd.Flags().StringVar(&drivePath, "drive-path", "", "full remote directory on Proton Drive (e.g. /my-files/docs/api). Requires --proton-drive") rootCmd.Flags().StringVar(&drivePath, "drive-path", "", "full remote directory on Proton Drive (e.g. /my-files/docs/api). Requires --proton-drive")
rootCmd.Flags().BoolVar(&verticalSlices, "vertical-slices", false, "split output into root index.md + one markdown per top-level directory") rootCmd.Flags().BoolVar(&verticalSlices, "vertical-slices", false, "split output into root index.md + one markdown per top-level directory")
rootCmd.Flags().BoolVar(&skipFrontend, "skip-frontend", false, "omit frontend file types (.html, .css, .js, .ts, .vue, .svelte, etc.)") rootCmd.Flags().BoolVar(&skipFrontend, "skip-frontend", false, "omit frontend file types (.html, .css, .js, .ts, .vue, .svelte, etc.)")
rootCmd.Flags().BoolVar(&frontendOnly, "frontend-only", false, "include only frontend file types and README.md")
rootCmd.Flags().BoolVar(&omitTest, "omit-test", false, "exclude test files (Go *_test.go, Java *Test.java) and strip #[cfg(test)] blocks from Rust") rootCmd.Flags().BoolVar(&omitTest, "omit-test", false, "exclude test files (Go *_test.go, Java *Test.java) and strip #[cfg(test)] blocks from Rust")
rootCmd.MarkPersistentFlagRequired("output") rootCmd.MarkPersistentFlagRequired("output")
@@ -105,6 +109,10 @@ func run(cmd *cobra.Command, args []string) error {
return fmt.Errorf("--vertical-slices cannot be used with --input-file") return fmt.Errorf("--vertical-slices cannot be used with --input-file")
} }
if skipFrontend && frontendOnly {
return fmt.Errorf("--skip-frontend and --frontend-only are mutually exclusive")
}
excludedExts := append(config.DefaultExts, extensions...) excludedExts := append(config.DefaultExts, extensions...)
if skipFrontend { if skipFrontend {
excludedExts = append(excludedExts, config.FrontendExts...) excludedExts = append(excludedExts, config.FrontendExts...)
@@ -122,6 +130,7 @@ func run(cmd *cobra.Command, args []string) error {
DrivePath: drivePath, DrivePath: drivePath,
VerticalSlices: verticalSlices, VerticalSlices: verticalSlices,
SkipFrontend: skipFrontend, SkipFrontend: skipFrontend,
FrontendOnly: frontendOnly,
OmitTest: omitTest, OmitTest: omitTest,
} }
+9 -2
View File
@@ -1,4 +1,3 @@
// internal/config/config.go
package config package config
import ( import (
@@ -80,6 +79,7 @@ type Config struct {
DrivePath string DrivePath string
VerticalSlices bool VerticalSlices bool
SkipFrontend bool SkipFrontend bool
FrontendOnly bool
OmitTest bool OmitTest bool
} }
@@ -106,6 +106,7 @@ func Parse() (*Config, error) {
drivePath string drivePath string
verticalSlices bool verticalSlices bool
skipFrontend bool skipFrontend bool
frontendOnly bool
omitTest bool omitTest bool
) )
@@ -119,9 +120,10 @@ func Parse() (*Config, error) {
flag.Var(&exts, "extensions", "additional file extensions to skip (repeatable)") flag.Var(&exts, "extensions", "additional file extensions to skip (repeatable)")
flag.BoolVar(&showVer, "version", false, "print version and exit") flag.BoolVar(&showVer, "version", false, "print version and exit")
flag.BoolVar(&protonDrive, "proton-drive", false, "upload output to Proton Drive after writing locally") flag.BoolVar(&protonDrive, "proton-drive", false, "upload output to Proton Drive after writing locally")
flag.StringVar(&drivePath, "drive-path", "", "full remote path on Proton Drive (requires --proton-drive)") 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(&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(&skipFrontend, "skip-frontend", false, "omit frontend file types (.html, .css, .js, .ts, .vue, .svelte, etc.)")
flag.BoolVar(&frontendOnly, "frontend-only", false, "include only frontend file types and README.md")
flag.BoolVar(&omitTest, "omit-test", false, "exclude test files (Go *_test.go, Java *Test.java) and strip #[cfg(test)] blocks from Rust") 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.Usage = PrintUsage
@@ -148,6 +150,10 @@ func Parse() (*Config, error) {
return nil, fmt.Errorf("--vertical-slices cannot be used with --input-file") return nil, fmt.Errorf("--vertical-slices cannot be used with --input-file")
} }
if skipFrontend && frontendOnly {
return nil, fmt.Errorf("--skip-frontend and --frontend-only are mutually exclusive")
}
excludedExts := append(DefaultExts, exts...) excludedExts := append(DefaultExts, exts...)
if skipFrontend { if skipFrontend {
excludedExts = append(excludedExts, FrontendExts...) excludedExts = append(excludedExts, FrontendExts...)
@@ -165,6 +171,7 @@ func Parse() (*Config, error) {
DrivePath: drivePath, DrivePath: drivePath,
VerticalSlices: verticalSlices, VerticalSlices: verticalSlices,
SkipFrontend: skipFrontend, SkipFrontend: skipFrontend,
FrontendOnly: frontendOnly,
OmitTest: omitTest, OmitTest: omitTest,
} }
+22 -6
View File
@@ -1,10 +1,11 @@
// internal/filter/filter.go
package filter package filter
import ( import (
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"dirmd/internal/config"
) )
type Filter struct { type Filter struct {
@@ -12,6 +13,7 @@ type Filter struct {
Extensions []string Extensions []string
Ignores []string Ignores []string
OmitTest bool OmitTest bool
FrontendOnly bool
} }
func (f *Filter) ShouldSkipDir(name string) bool { func (f *Filter) ShouldSkipDir(name string) bool {
@@ -39,14 +41,11 @@ func (f *Filter) ShouldSkipFile(path, name string, info os.FileInfo) bool {
} }
} }
ext := filepath.Ext(path) if info.Size() > f.MaxSize {
for _, bad := range f.Extensions {
if strings.EqualFold(ext, bad) {
return true return true
} }
}
if info.Size() > f.MaxSize { if f.FrontendOnly && !isFrontendOrReadme(path, name) {
return true return true
} }
@@ -54,9 +53,26 @@ func (f *Filter) ShouldSkipFile(path, name string, info os.FileInfo) bool {
return true return true
} }
ext := filepath.Ext(path)
for _, bad := range f.Extensions {
if strings.EqualFold(ext, bad) {
return true
}
}
return false return false
} }
func isFrontendOrReadme(path, name string) bool {
ext := strings.ToLower(filepath.Ext(path))
for _, fe := range config.FrontendExts {
if strings.EqualFold(ext, fe) {
return true
}
}
return strings.EqualFold(name, "README.md")
}
func isTestFile(path, name string) bool { func isTestFile(path, name string) bool {
ext := strings.ToLower(filepath.Ext(path)) ext := strings.ToLower(filepath.Ext(path))
+2
View File
@@ -46,6 +46,7 @@ func processSingleFile(cfg *config.Config) (*Result, error) {
Extensions: cfg.Extensions, Extensions: cfg.Extensions,
Ignores: cfg.Ignores, Ignores: cfg.Ignores,
OmitTest: cfg.OmitTest, OmitTest: cfg.OmitTest,
FrontendOnly: cfg.FrontendOnly,
} }
if flt.ShouldSkipFile(cfg.AbsRoot, filepath.Base(cfg.AbsRoot), info) { if flt.ShouldSkipFile(cfg.AbsRoot, filepath.Base(cfg.AbsRoot), info) {
@@ -66,6 +67,7 @@ func walkDirectory(cfg *config.Config) (*Result, error) {
Extensions: cfg.Extensions, Extensions: cfg.Extensions,
Ignores: cfg.Ignores, Ignores: cfg.Ignores,
OmitTest: cfg.OmitTest, OmitTest: cfg.OmitTest,
FrontendOnly: cfg.FrontendOnly,
} }
result := &Result{AbsRoot: cfg.AbsRoot, OmitTest: cfg.OmitTest} result := &Result{AbsRoot: cfg.AbsRoot, OmitTest: cfg.OmitTest}