Files
gibidify/templates/types.go
Ismo Vuorinen 95b7ef6dd3 chore: modernize workflows, security scanning, and linting configuration (#50)
* build: update Go 1.25, CI workflows, and build tooling

- Upgrade to Go 1.25
- Add benchmark targets to Makefile
- Implement parallel gosec execution
- Lock tool versions for reproducibility
- Add shellcheck directives to scripts
- Update CI workflows with improved caching

* refactor: migrate from golangci-lint to revive

- Replace golangci-lint with revive for linting
- Configure comprehensive revive rules
- Fix all EditorConfig violations
- Add yamllint and yamlfmt support
- Remove deprecated .golangci.yml

* refactor: rename utils to shared and deduplicate code

- Rename utils package to shared
- Add shared constants package
- Deduplicate constants across packages
- Address CodeRabbit review feedback

* fix: resolve SonarQube issues and add safety guards

- Fix all 73 SonarQube OPEN issues
- Add nil guards for resourceMonitor, backpressure, metricsCollector
- Implement io.Closer for headerFileReader
- Propagate errors from processing helpers
- Add metrics and templates packages
- Improve error handling across codebase

* test: improve test infrastructure and coverage

- Add benchmarks for cli, fileproc, metrics
- Improve test coverage for cli, fileproc, config
- Refactor tests with helper functions
- Add shared test constants
- Fix test function naming conventions
- Reduce cognitive complexity in benchmark tests

* docs: update documentation and configuration examples

- Update CLAUDE.md with current project state
- Refresh README with new features
- Add usage and configuration examples
- Add SonarQube project configuration
- Consolidate config.example.yaml

* fix: resolve shellcheck warnings in scripts

- Use ./*.go instead of *.go to prevent dash-prefixed filenames
  from being interpreted as options (SC2035)
- Remove unreachable return statement after exit (SC2317)
- Remove obsolete gibidiutils/ directory reference

* chore(deps): upgrade go dependencies

* chore(lint): megalinter fixes

* fix: improve test coverage and fix file descriptor leaks

- Add defer r.Close() to fix pipe file descriptor leaks in benchmark tests
- Refactor TestProcessorConfigureFileTypes with helper functions and assertions
- Refactor TestProcessorLogFinalStats with output capture and keyword verification
- Use shared constants instead of literal strings (TestFilePNG, FormatMarkdown, etc.)
- Reduce cognitive complexity by extracting helper functions

* fix: align test comments with function names

Remove underscores from test comments to match actual function names:
- benchmark/benchmark_test.go (2 fixes)
- fileproc/filetypes_config_test.go (4 fixes)
- fileproc/filetypes_registry_test.go (6 fixes)
- fileproc/processor_test.go (6 fixes)
- fileproc/resource_monitor_types_test.go (4 fixes)
- fileproc/writer_test.go (3 fixes)

* fix: various test improvements and bug fixes

- Remove duplicate maxCacheSize check in filetypes_registry_test.go
- Shorten long comment in processor_test.go to stay under 120 chars
- Remove flaky time.Sleep in collector_test.go, use >= 0 assertion
- Close pipe reader in benchmark_test.go to fix file descriptor leak
- Use ContinueOnError in flags_test.go to match ResetFlags behavior
- Add nil check for p.ui in processor_workers.go before UpdateProgress
- Fix resource_monitor_validation_test.go by setting hardMemoryLimitBytes directly

* chore(yaml): add missing document start markers

Add --- document start to YAML files to satisfy yamllint:
- .github/workflows/codeql.yml
- .github/workflows/build-test-publish.yml
- .github/workflows/security.yml
- .github/actions/setup/action.yml

* fix: guard nil resourceMonitor and fix test deadlock

- Guard resourceMonitor before CreateFileProcessingContext call
- Add ui.UpdateProgress on emergency stop and path error returns
- Fix potential deadlock in TestProcessFile using wg.Go with defer close
2025-12-10 19:07:11 +02:00

223 lines
7.9 KiB
Go

// Package templates provides output formatting templates and customization options.
package templates
import (
"time"
"github.com/ivuorinen/gibidify/shared"
)
// OutputTemplate represents a customizable output template.
type OutputTemplate struct {
Name string `json:"name" yaml:"name"`
Description string `json:"description" yaml:"description"`
Format string `json:"format" yaml:"format"` // markdown, json, yaml
Header string `json:"header" yaml:"header"`
Footer string `json:"footer" yaml:"footer"`
FileHeader string `json:"file_header" yaml:"file_header"`
FileFooter string `json:"file_footer" yaml:"file_footer"`
Metadata MetadataOptions `json:"metadata" yaml:"metadata"`
Markdown MarkdownOptions `json:"markdown" yaml:"markdown"`
Variables map[string]string `json:"variables" yaml:"variables"`
}
// MetadataOptions controls what metadata to include in the output.
type MetadataOptions struct {
IncludeStats bool `json:"include_stats" yaml:"include_stats"`
IncludeTimestamp bool `json:"include_timestamp" yaml:"include_timestamp"`
IncludeFileCount bool `json:"include_file_count" yaml:"include_file_count"`
IncludeSourcePath bool `json:"include_source_path" yaml:"include_source_path"`
IncludeFileTypes bool `json:"include_file_types" yaml:"include_file_types"`
IncludeProcessingTime bool `json:"include_processing_time" yaml:"include_processing_time"`
IncludeTotalSize bool `json:"include_total_size" yaml:"include_total_size"`
IncludeMetrics bool `json:"include_metrics" yaml:"include_metrics"`
}
// MarkdownOptions controls markdown-specific formatting.
type MarkdownOptions struct {
UseCodeBlocks bool `json:"use_code_blocks" yaml:"use_code_blocks"`
IncludeLanguage bool `json:"include_language" yaml:"include_language"`
HeaderLevel int `json:"header_level" yaml:"header_level"` // 1-6 for # levels
TableOfContents bool `json:"table_of_contents" yaml:"table_of_contents"`
UseCollapsible bool `json:"use_collapsible" yaml:"use_collapsible"`
SyntaxHighlighting bool `json:"syntax_highlighting" yaml:"syntax_highlighting"`
LineNumbers bool `json:"line_numbers" yaml:"line_numbers"`
FoldLongFiles bool `json:"fold_long_files" yaml:"fold_long_files"`
MaxLineLength int `json:"max_line_length" yaml:"max_line_length"`
CustomCSS string `json:"custom_css" yaml:"custom_css"`
}
// TemplateContext provides data available for template substitution.
type TemplateContext struct {
// Basic information
Timestamp time.Time `json:"timestamp"`
SourcePath string `json:"source_path"`
Format string `json:"format"`
// File statistics
TotalFiles int `json:"total_files"`
ProcessedFiles int `json:"processed_files"`
SkippedFiles int `json:"skipped_files"`
ErrorFiles int `json:"error_files"`
TotalSize int64 `json:"total_size"`
// Processing metrics
ProcessingTime string `json:"processing_time"`
FilesPerSecond float64 `json:"files_per_second"`
BytesPerSecond float64 `json:"bytes_per_second"`
FileTypes map[string]int `json:"file_types"`
// Custom variables
Variables map[string]string `json:"variables"`
}
// FileContext provides data for individual file formatting.
type FileContext struct {
Path string `json:"path"`
RelativePath string `json:"relative_path"`
Name string `json:"name"`
Extension string `json:"extension"`
Language string `json:"language"`
Size int64 `json:"size"`
ModTime time.Time `json:"mod_time"`
Content string `json:"content"`
LineCount int `json:"line_count"`
IsLarge bool `json:"is_large"`
Truncated bool `json:"truncated"`
}
// BuiltinTemplates contains predefined templates.
var BuiltinTemplates = map[string]OutputTemplate{
"default": {
Name: "Default",
Description: "Standard output template",
Format: shared.FormatMarkdown,
Header: "# {{.SourcePath}}\n\nGenerated on {{.Timestamp.Format \"2006-01-02 15:04:05\"}}\n",
Footer: "\n---\nGenerated by gibidify\n",
FileHeader: "## {{.Path}}\n\n```{{.Language}}\n",
FileFooter: "```\n\n",
Metadata: MetadataOptions{
IncludeStats: true,
IncludeTimestamp: true,
IncludeFileCount: true,
IncludeSourcePath: true,
},
Markdown: MarkdownOptions{
UseCodeBlocks: true,
IncludeLanguage: true,
HeaderLevel: 2,
SyntaxHighlighting: true,
},
},
"minimal": {
Name: "Minimal",
Description: "Minimal output with just file contents",
Format: shared.FormatMarkdown,
Header: "",
Footer: "",
FileHeader: "<!-- {{.Path}} -->\n",
FileFooter: "\n",
Metadata: MetadataOptions{
IncludeStats: false,
IncludeTimestamp: false,
IncludeFileCount: false,
IncludeSourcePath: false,
},
Markdown: MarkdownOptions{
UseCodeBlocks: false,
IncludeLanguage: false,
},
},
"detailed": {
Name: "Detailed",
Description: "Comprehensive output with full metadata",
Format: shared.FormatMarkdown,
Header: `# Project Analysis: {{.SourcePath}}
Generated on {{.Timestamp.Format "January 2, 2006 at 3:04 PM"}}
## Summary
- **Total Files**: {{.TotalFiles}}
- **Processed Files**: {{.ProcessedFiles}}
- **Total Size**: {{.TotalSize}} bytes
- **Processing Time**: {{.ProcessingTime}}
- **Rate**: {{.FilesPerSecond}} files/sec
`,
Footer: "\n---\n*Generated by gibidify*\n",
FileHeader: "### {{.RelativePath}}\n\n**Language**: {{.Language}} \n" +
"**Size**: {{.Size}} bytes \n**Lines**: {{.LineCount}} \n\n```{{.Language}}\n",
FileFooter: "```\n\n",
Metadata: MetadataOptions{
IncludeStats: true,
IncludeTimestamp: true,
IncludeFileCount: true,
IncludeSourcePath: true,
IncludeFileTypes: true,
IncludeProcessingTime: true,
IncludeTotalSize: true,
IncludeMetrics: true,
},
Markdown: MarkdownOptions{
UseCodeBlocks: true,
IncludeLanguage: true,
HeaderLevel: 3,
TableOfContents: true,
SyntaxHighlighting: true,
LineNumbers: false,
},
},
"compact": {
Name: "Compact",
Description: "Space-efficient output with collapsible sections",
Format: shared.FormatMarkdown,
Header: "# {{.SourcePath}}\n\n<details><summary>📊 Stats ({{.TotalFiles}} files)</summary>\n\n" +
"- Processed: {{.ProcessedFiles}}\n- Size: {{.TotalSize}} bytes\n" +
"- Time: {{.ProcessingTime}}\n\n</details>\n\n",
Footer: "\n---\n*Compressed with gibidify*\n",
FileHeader: "<details><summary>📄 {{.RelativePath}} ({{.Size}} bytes)</summary>\n\n```{{.Language}}\n",
FileFooter: "```\n\n</details>\n\n",
Metadata: MetadataOptions{
IncludeStats: true,
IncludeFileCount: true,
IncludeTotalSize: true,
},
Markdown: MarkdownOptions{
UseCodeBlocks: true,
IncludeLanguage: true,
UseCollapsible: true,
SyntaxHighlighting: true,
},
},
}
// DefaultMetadataOptions returns the default metadata options.
func DefaultMetadataOptions() MetadataOptions {
return MetadataOptions{
IncludeStats: true,
IncludeTimestamp: true,
IncludeFileCount: true,
IncludeSourcePath: true,
IncludeFileTypes: false,
IncludeProcessingTime: false,
IncludeTotalSize: false,
IncludeMetrics: false,
}
}
// DefaultMarkdownOptions returns the default markdown options.
func DefaultMarkdownOptions() MarkdownOptions {
return MarkdownOptions{
UseCodeBlocks: true,
IncludeLanguage: true,
HeaderLevel: 2,
TableOfContents: false,
UseCollapsible: false,
SyntaxHighlighting: true,
LineNumbers: false,
FoldLongFiles: false,
MaxLineLength: 120,
}
}