Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 125 additions & 14 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This document provides essential context for LLMs performing development tasks i
- Analyze composable definitions and usage across projects
- Compare files across documentation versions
- Count documentation pages and tested code examples
- Generate reports on testable code examples from analytics data

**Target Users**: MongoDB technical writers performing maintenance, scoping work, and reporting.

Expand All @@ -36,29 +37,42 @@ audit-cli/
│ │ └── composables/ # Analyze composable definitions and usage
│ ├── compare/ # Compare files across versions
│ │ └── file-contents/ # Compare file contents
│ └── count/ # Count documentation content
│ ├── tested-examples/ # Count tested code examples
│ └── pages/ # Count documentation pages
│ ├── count/ # Count documentation content
│ │ ├── tested-examples/ # Count tested code examples
│ │ └── pages/ # Count documentation pages
│ └── report/ # Generate reports from documentation data
│ └── testable-code/ # Analyze testable code examples from analytics
├── internal/ # Internal packages (not importable externally)
│ ├── config/ # Configuration management
│ │ ├── config.go # Config loading from file/env/args
│ │ └── config_test.go # Config tests
│ │ ├── config_test.go # Config tests
│ │ ├── url_mapping.go # URL-to-source-file mapping via Snooty Data API
│ │ └── url_mapping_test.go # URL mapping tests
│ ├── language/ # Programming language utilities
│ │ ├── language.go # Language normalization, extensions, products
│ │ └── language_test.go # Language tests
│ ├── projectinfo/ # MongoDB docs project structure utilities
│ │ ├── pathresolver.go # Path resolution
│ │ ├── source_finder.go # Source directory detection
│ │ ├── pathresolver.go # Path resolution
│ │ ├── products.go # Content directory to product mapping
│ │ ├── source_finder.go # Source directory detection
│ │ └── version_resolver.go # Version path resolution
│ └── rst/ # RST parsing utilities
│ ├── parser.go # Generic parsing with includes
│ ├── directive_parser.go # Directive parsing
│ ├── directive_regex.go # Regex patterns for directives
│ ├── parse_procedures.go # Procedure parsing (core logic)
│ ├── get_procedure_variations.go # Variation extraction
│ └── rstspec.go # Fetch and parse canonical rstspec.toml
│ ├── rst/ # RST parsing utilities
│ │ ├── parser.go # Generic parsing with includes
│ │ ├── directive_parser.go # Directive parsing with language resolution
│ │ ├── directive_regex.go # Regex patterns for directives
│ │ ├── parse_procedures.go # Procedure parsing (core logic)
│ │ ├── get_procedure_variations.go # Variation extraction
│ │ ├── rstspec.go # Fetch and parse canonical rstspec.toml
│ │ └── yaml_steps_parser.go # Parse YAML steps files for code examples
│ └── snooty/ # Snooty.toml parsing utilities
│ ├── snooty.go # Parse snooty.toml, find project config
│ └── snooty_test.go # Snooty tests
├── testdata/ # Test fixtures (auto-ignored by Go build)
│ ├── input-files/source/ # Test RST files
│ ├── expected-output/ # Expected extraction results
│ ├── compare/ # Compare command test data
│ └── count-test-monorepo/ # Count command test data
│ ├── count-test-monorepo/ # Count command test data
│ └── testable-code-test/ # Testable code report test data
├── bin/ # Build output directory
├── docs/ # Additional documentation
│ └── PROCEDURE_PARSING.md # Detailed procedure parsing logic
Expand Down Expand Up @@ -393,6 +407,103 @@ func NewExtractCommand() *cobra.Command {
- Support multiple output formats (text, JSON) where applicable
- Use consistent formatting (headers with `=` separators, indentation)

### Network Request Caching

All network requests to external APIs should implement caching to avoid repeated requests and support offline usage. The caching pattern is implemented in `internal/config/url_mapping.go` (for Snooty Data API) and `internal/rst/rstspec.go` (for rstspec.toml).

**Cache Location**: `~/.audit-cli/` directory
- URL mapping cache: `~/.audit-cli/url-mapping-cache.json`
- Rstspec cache: `~/.audit-cli/rstspec-cache.json`

**Cache TTL**: 24 hours (configurable per cache type)

**Implementation Pattern**:

1. **Define cache constants**:
```go
const CacheTTL = 24 * time.Hour
const CacheDir = ".audit-cli"
const CacheFileName = "my-cache.json"
```

2. **Create cache struct** with timestamp and data:
```go
type MyCache struct {
Timestamp time.Time `json:"timestamp"`
Data MyData `json:"data"`
}
```

3. **Implement cache functions**:
```go
// getCachePath returns the path to the cache file
func getCachePath() (string, error) {
homeDir, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("failed to get home directory: %w", err)
}
return filepath.Join(homeDir, CacheDir, CacheFileName), nil
}

// loadCache loads from cache, returns error if missing or expired
func loadCache() (*MyData, error) {
// Read file, unmarshal JSON, check TTL
}

// saveCache saves data to cache with current timestamp
func saveCache(data *MyData) error {
// Create directory if needed, marshal JSON, write file
}

// fetchFromAPI fetches fresh data from the network
func fetchFromAPI() (*MyData, error) {
// HTTP request, parse response
}
```

4. **Main fetch function with fallback logic**:
```go
func FetchData() (*MyData, error) {
// Try cache first
data, err := loadCache()
if err == nil {
return data, nil
}

// Cache miss or expired, try network
data, fetchErr := fetchFromAPI()
if fetchErr != nil {
// Network failed - try expired cache as offline fallback
// (read cache file without TTL check)
if expiredData := loadExpiredCache(); expiredData != nil {
fmt.Fprintf(os.Stderr, "Warning: Using expired cache\n")
return expiredData, nil
}
return nil, fetchErr
}

// Save to cache for next time
if saveErr := saveCache(data); saveErr != nil {
fmt.Fprintf(os.Stderr, "Warning: Could not save cache: %v\n", saveErr)
}

return data, nil
}
```

**Key Behaviors**:
- Cache is stored in user's home directory for persistence across sessions
- Expired cache is used as fallback when network is unavailable (offline support)
- Cache save failures are logged as warnings but don't fail the operation
- JSON format for easy debugging and human readability

**When Adding New Network Calls**:
1. Follow the pattern above
2. Add cache file name constant
3. Implement the four cache functions
4. Use the same `~/.audit-cli/` directory for consistency
5. Consider appropriate TTL (24 hours is default, adjust if data changes more/less frequently)

## Key Design Decisions

### RST Parsing Strategy
Expand Down
54 changes: 54 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,60 @@ All notable changes to audit-cli will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.3.0] - 2025-01-07

### Added

#### Report Commands
- `report testable-code` - Analyze testable code examples on pages from analytics data
- Takes a CSV file with page rankings and URLs from analytics
- Resolves URLs to source files using the Snooty Data API
- Collects code examples (literalinclude, code, code-block, io-code-block) from each page
- Determines product context from tabs, composables, and content directories
- Identifies tested vs testable vs "maybe testable" code examples
- Supports multiple output formats: text, JSON, CSV
- Flags:
- `--format, -f` - Output format (text, json, csv)
- `--output, -o` - Output file path (default: stdout)
- `--details` - Show detailed per-product breakdown

#### Internal Packages
- `internal/language` - Programming language utilities (refactored from code-examples)
- Language normalization (e.g., "ts" → "typescript", "py" → "python")
- File extension mapping for all supported languages
- Language-to-product mapping for MongoDB drivers
- Non-driver language detection (bash, json, yaml, etc.)
- MongoDB Shell language detection
- Language resolution with priority: argument > option > file extension
- `internal/snooty` - Snooty.toml parsing utilities
- Parse snooty.toml configuration files
- Find project snooty.toml from source file paths
- Build composable ID-to-title mappings
- Extract project and version from snooty.toml paths
- `internal/config/url_mapping.go` - URL-to-source-file mapping
- Fetches project metadata from Snooty Data API
- Resolves documentation URLs to source file paths
- Caches API responses for 24 hours in `~/.audit-cli/`
- Supports offline usage with expired cache fallback
- `internal/projectinfo/products.go` - Content directory to product mapping
- Maps driver content directories to display product names
- Supports all MongoDB driver documentation projects
- `internal/rst/yaml_steps_parser.go` - YAML steps file parsing
- Parses legacy YAML-native code examples in steps files
- Extracts code blocks with language and content
- `internal/rst/directive_parser.go` - Enhanced directive parsing
- Added `ResolveLanguage()` method to Directive type
- Added `ResolveLanguage()` method to SubDirective type
- Language resolution follows priority: argument > option > file extension

### Changed

- Refactored language handling from `commands/extract/code-examples/language.go` to `internal/language` package
- All language-related utilities now centralized and reusable
- Added product mapping and non-driver language detection
- Enhanced `internal/rst` directive parsing with language resolution methods
- Updated `analyze usage` to use new language package for file extension handling

## [0.2.0] - 2025-12-12

### Added
Expand Down
Loading
Loading