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
- Optional upload to Proton Drive after generating output
- 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)
## Build
@@ -40,6 +41,9 @@ Generate markdown documentation from directory structure. Optimized for LLM inge
# Skip frontend files (.html, .css, .js, etc.)
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
# Go: excludes *_test.go
# 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
# 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>)
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.
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` |
| Stylesheets | `.css`, `.scss`, `.sass`, `.less` |
| Scripts | `.js`, `.jsx`, `.mjs`, `.cjs`, `.ts`, `.tsx` |
| JavaScript | `.js`, `.jsx`, `.mjs`, `.cjs` |
| TypeScript | `.ts`, `.tsx` |
| Frameworks | `.vue`, `.svelte` |
These flags can be combined freely:
dirmd -o docs.md ~/repos/myproject --skip-frontend --omit-test
`--skip-frontend` and `--frontend-only` are mutually exclusive. Both can be combined with `--omit-test`.
## 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 |
| `--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 |
| `--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 |
## Proton Drive Integration
@@ -158,6 +171,9 @@ For full documentation on the Proton Drive CLI, including installation, authenti
# Skip frontend and omit tests
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
dirmd -o docs.md ~/repos/project --proton-drive
+10 -1
View File
@@ -1,4 +1,3 @@
// cmd/root.go
package cmd
import (
@@ -42,6 +41,9 @@ Examples:
# Skip frontend files
dirmd -o ./docs ~/repos/myproject --skip-frontend
# Frontend only
dirmd -o ./docs ~/repos/myproject --frontend-only
# Omit test files and test blocks
dirmd -o ./docs ~/repos/myproject --omit-test
@@ -65,6 +67,7 @@ Examples:
drivePath string
verticalSlices bool
skipFrontend bool
frontendOnly 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().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(&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.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")
}
if skipFrontend && frontendOnly {
return fmt.Errorf("--skip-frontend and --frontend-only are mutually exclusive")
}
excludedExts := append(config.DefaultExts, extensions...)
if skipFrontend {
excludedExts = append(excludedExts, config.FrontendExts...)
@@ -122,6 +130,7 @@ func run(cmd *cobra.Command, args []string) error {
DrivePath: drivePath,
VerticalSlices: verticalSlices,
SkipFrontend: skipFrontend,
FrontendOnly: frontendOnly,
OmitTest: omitTest,
}
+9 -2
View File
@@ -1,4 +1,3 @@
// internal/config/config.go
package config
import (
@@ -80,6 +79,7 @@ type Config struct {
DrivePath string
VerticalSlices bool
SkipFrontend bool
FrontendOnly bool
OmitTest bool
}
@@ -106,6 +106,7 @@ func Parse() (*Config, error) {
drivePath string
verticalSlices bool
skipFrontend bool
frontendOnly bool
omitTest bool
)
@@ -119,9 +120,10 @@ func Parse() (*Config, error) {
flag.Var(&exts, "extensions", "additional file extensions to skip (repeatable)")
flag.BoolVar(&showVer, "version", false, "print version and exit")
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(&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.Usage = PrintUsage
@@ -148,6 +150,10 @@ func Parse() (*Config, error) {
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...)
if skipFrontend {
excludedExts = append(excludedExts, FrontendExts...)
@@ -165,6 +171,7 @@ func Parse() (*Config, error) {
DrivePath: drivePath,
VerticalSlices: verticalSlices,
SkipFrontend: skipFrontend,
FrontendOnly: frontendOnly,
OmitTest: omitTest,
}
+22 -6
View File
@@ -1,10 +1,11 @@
// internal/filter/filter.go
package filter
import (
"os"
"path/filepath"
"strings"
"dirmd/internal/config"
)
type Filter struct {
@@ -12,6 +13,7 @@ type Filter struct {
Extensions []string
Ignores []string
OmitTest bool
FrontendOnly 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)
for _, bad := range f.Extensions {
if strings.EqualFold(ext, bad) {
if info.Size() > f.MaxSize {
return true
}
}
if info.Size() > f.MaxSize {
if f.FrontendOnly && !isFrontendOrReadme(path, name) {
return true
}
@@ -54,9 +53,26 @@ func (f *Filter) ShouldSkipFile(path, name string, info os.FileInfo) bool {
return true
}
ext := filepath.Ext(path)
for _, bad := range f.Extensions {
if strings.EqualFold(ext, bad) {
return true
}
}
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 {
ext := strings.ToLower(filepath.Ext(path))
+2
View File
@@ -46,6 +46,7 @@ func processSingleFile(cfg *config.Config) (*Result, error) {
Extensions: cfg.Extensions,
Ignores: cfg.Ignores,
OmitTest: cfg.OmitTest,
FrontendOnly: cfg.FrontendOnly,
}
if flt.ShouldSkipFile(cfg.AbsRoot, filepath.Base(cfg.AbsRoot), info) {
@@ -66,6 +67,7 @@ func walkDirectory(cfg *config.Config) (*Result, error) {
Extensions: cfg.Extensions,
Ignores: cfg.Ignores,
OmitTest: cfg.OmitTest,
FrontendOnly: cfg.FrontendOnly,
}
result := &Result{AbsRoot: cfg.AbsRoot, OmitTest: cfg.OmitTest}