How the JetBrains Go Feature Generator (featuresgen) Creates FEATURES.md

The featuresgen tool transforms the machine-readable guidelines.json into the human-readable FEATURES.md document by parsing the JSON into Go structs, constructing Markdown tables and anchored sections with strings.Builder, and writing syntax-highlighted code examples.

The featuresgen utility in the JetBrains/go-modern-guidelines repository serves as the bridge between structured data and documentation. This feature generator eliminates manual synchronization errors by programmatically converting the JSON schema output into a comprehensive Markdown reference that includes impact ratings, version information, and before/after code comparisons.

The featuresgen Architecture and Data Flow

Located at internal/guidelines/featuresgen/main.go, the feature generator operates as a single-purpose command-line transformer. It expects exactly two arguments: the source JSON path and the destination Markdown path.

Input and Output Specifications

The tool processes guidelines.json, generated by the schema package, which contains a serialized slice of schema.Guideline structs. Each struct includes fields such as ID, Category, SinceVersion, Impact, Modernizer, Guideline, Details, and Examples. The output is a fully formatted FEATURES.md file featuring a summary table and detailed per-guideline sections with anchored hyperlinks.

Core Dependencies

The program relies on three critical components from the codebase:

  • internal/guidelines/schema/schema.go: Defines the Guideline struct and the Parse(data []byte) function that unmarshals JSON.
  • strings.Builder: Accumulates the Markdown content efficiently without excessive allocations.
  • Standard library: os.ReadFile and os.WriteFile handle filesystem operations.

Step-by-Step Generation Process

The featuresgen pipeline executes in five distinct phases, each handled within the run and render functions.

CLI Argument Validation

The run function strictly validates input before processing. It aborts with a usage error if the argument count differs from two:

if len(args) != 2 { 
    return fmt.Errorf("usage: featuresgen <guidelines.json> <FEATURES.md>") 
}

This ensures the generator receives the correct input JSON and output Markdown file paths.

JSON Parsing with the schema Package

After reading the raw bytes with os.ReadFile(args[0]), the program delegates decoding to the schema package:

guidelines, err := schema.Parse(data)

The schema.Parse function unmarshals the JSON into a []schema.Guideline slice, handling type safety for boolean flags like Modernizer and nested example arrays.

Markdown Construction Pipeline

The render function orchestrates Markdown generation using a strings.Builder instance. The construction occurs in three sequential stages:

  1. Header and Legends: Fixed introductory text explains the modernizer notation and impact level meanings.

  2. Summary Table: A Markdown table links categories to guideline IDs with anchor references:

    fmt.Fprintf(&b,
        "| %s | [`%s`](#%s) | %s | %s | %s |\n",
        guideline.Category,
        guideline.ID,
        guideline.ID,
        modernizerMark(*guideline.Modernizer),
        guideline.SinceVersion,
        guideline.Impact,
    )
  3. Detailed Sections: The tool iterates the guideline slice a second time to emit full documentation sections. Each section includes:

    • An HTML anchor tag (<a id="GUIDELINE_ID"></a>) for intra-document linking
    • Metadata lines showing the modernizer status (via modernizerLabel), Go version, and impact
    • Verbatim Guideline and Details strings
    • Before/After code blocks rendered via writeCodeBlock

File Writing and Persistence

Finally, the accumulated buffer converts to bytes and writes to disk:

err = os.WriteFile(args[1], []byte(b.String()), 0644)

This atomic operation ensures FEATURES.md updates only when the entire document generates successfully.

Key Implementation Details

The render Function Logic

The render function maintains purity by accepting []byte and returning []byte, making it fully testable without side effects. It separates concerns between data transformation (parsing) and presentation (Markdown formatting).

Markdown Table Generation

The modernizerMark helper converts the boolean Modernizer field into visual indicators:

  • [x] indicates the guideline has a supported modernizer
  • [ ] indicates no automated modernization tool exists

Code Block Formatting

The writeCodeBlock utility ensures consistent Go syntax highlighting by wrapping example lines in fenced code blocks:

func writeCodeBlock(b *strings.Builder, lines []string) {
    b.WriteString("```go\n")
    for _, line := range lines {
        b.WriteString(line)
        b.WriteByte('\n')
    }
    b.WriteString("```\n")
}

This produces properly formatted Before/After comparisons for every code example in the guidelines.

Testing and Validation

The repository includes comprehensive unit tests in internal/guidelines/featuresgen/main_test.go that verify the render function output. These tests ensure that:

  • Anchor tags generate correctly for every guideline ID
  • The Markdown table syntax remains valid
  • Special characters in guideline text escape properly

By validating the byte-to-byte transformation, the test suite guarantees that FEATURES.md remains synchronized with guidelines.json across repository updates.

Summary

Frequently Asked Questions

What input format does featuresgen require?

The tool requires a guidelines.json file produced by the schema package containing a JSON array of guideline objects. Each object must include fields like ID, Category, SinceVersion, Impact, Modernizer, Guideline, Details, and Examples to parse correctly via schema.Parse.

How does featuresgen handle code examples in the output?

The writeCodeBlock function wraps example code lines in Go-syntax fenced code blocks (```go). For each guideline, it renders separate "Before" and "After" blocks to demonstrate the modernization pattern, ensuring the output Markdown renders with proper syntax highlighting in GitHub and JetBrains IDEs.

Can I run featuresgen without the full JetBrains repository?

Yes, the tool is self-contained within internal/guidelines/featuresgen. You can execute it independently using go run ./internal/guidelines/featuresgen <input.json> <output.md> provided you have a valid guidelines.json file conforming to the schema defined in internal/guidelines/schema/schema.go.

Why does featuresgen iterate the guideline slice twice?

The first iteration builds the summary table at the top of FEATURES.md, while the second iteration generates the detailed per-guideline sections below. This two-pass approach ensures the table of contents contains anchor links to sections that appear later in the document, creating the navigation structure visible in the final Markdown.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →