Skip to content

werf/wormatter

Repository files navigation

Wormatter

A DST-based Go source code formatter. Highly opinionated, but very comprehensive. Gofumpt and gci built-in.

Installation

Download the latest binary from GitHub Releases.

Usage

wormatter <file.go|directory>

Formats Go files in place. Recursively processes directories.

Options

  • -c, --check — Check if files need formatting without modifying them. Exits with code 1 if any file needs formatting.
  • -e, --exclude <pattern> — Exclude files matching glob pattern (can be specified multiple times).

Examples

# Format a single file
wormatter main.go

# Format all Go files in a directory
wormatter ./pkg/

# Check if files are formatted (useful for CI)
wormatter --check .

# Exclude test files
wormatter --exclude "*_test.go" .

# Exclude multiple patterns
wormatter --exclude "*.pb.go" --exclude "vendor/*" .

Generated Files

Files starting with any of these comments are automatically skipped:

  • // Code generated
  • // DO NOT EDIT
  • // GENERATED
  • // Autogenerated
  • // auto-generated
  • // Automatically generated

Building

task build

Formatting Rules

Declaration Order (top to bottom)

  1. Imports — unchanged
  2. init functions — preserved in original order
  3. Constants — merged into single const() block
  4. Variables — merged into single var() block
  5. Types — grouped by category, each followed by constructors and methods
  6. Standalone functions — sorted by exportability
  7. main function — always last

Const/Var Block Rules

Grouping (separated by empty lines)

  1. Blank identifier (var _ Interface = ...) — all together, no sub-grouping
  2. Public (uppercase first letter) — sub-grouped by custom type
  3. Private (lowercase first letter) — sub-grouped by custom type

Custom type sub-grouping

Within public and private groups, values with explicit custom types are grouped together:

const (
    ConstA = "a"
    ConstB = "b"

    StatusOK    StatusCode = "ok"
    StatusError StatusCode = "error"

    constPrivate = "private"
)

Within each group/sub-group

  • Sorted alphabetically by first name
  • No empty lines between elements

Block format

  • Single declaration: const X = 1
  • Multiple declarations: const ( ... ) with parentheses

Type Grouping Order

Types are grouped by category (in this order):

  1. Simple types (aliases like type MyString string, function types)
  2. Function interfaces (interfaces with exactly one method)
  3. Non-function interfaces (interfaces with 0 or 2+ methods)
  4. Structs

Types within each category preserve their original order.

Type-Associated Declarations

After each type definition:

  1. Constructors — functions starting with New or new that return the type
  2. Methods — functions with receiver of that type

Constructor Matching

A function is a constructor for type T if:

  • Name starts with New (exported) or new (unexported)
  • Returns T, *T, (T, error), (*T, error), etc.
  • Name after New/new matches T case-insensitively, or starts with T followed by non-lowercase char
    • NewFoo ✓ matches Foo
    • newFoo ✓ matches foo (case-insensitive)
    • NewFooWithOptions ✓ matches Foo
    • newFooWithOptions ✓ matches foo
    • NewFoobar ✗ does NOT match Foo (would match Foobar)

Constructor/Method Sorting

  • Constructors: alphabetically by name
  • Methods: exported first, then unexported; within each group sorted by architectural layer

Standalone Functions Sorting

  • Exported first, then unexported
  • Within each group: sorted by architectural layer (high-level first, utilities last)

Architectural Layer

Layer is determined by call depth to other local functions:

  • Layer 0: functions that call no other local functions (leaves/utilities)
  • Layer 1: functions that only call layer 0 functions
  • Layer N: functions that call layer N-1 or lower
  • Cyclic calls: functions in a cycle share the same layer

Higher layers appear first (orchestrators before utilities).

Struct Field Ordering

Fields grouped into three blocks (separated by empty lines):

  1. Embedded — fields without names, sorted alphabetically by type name
  2. Public — uppercase names, sorted alphabetically
  3. Private — lowercase names, sorted alphabetically

Struct Literal Ordering

When instantiating structs with named fields:

&Config{Timeout: 30, Verbose: true, debug: false}

Fields are reordered to match struct definition order (embedded → public → private). No empty lines between fields in literals.

Function Body Rules

One-line functions

  • Empty body stays one line: func foo() {}
  • Non-empty body expands to multiple lines

Return statements

  • Empty line before return if there's code before it in the same block
  • No empty line if return is the first/only statement

Comments

  • Empty line before line comments (//), unless it's the first statement in a block
  • End-of-line comments don't trigger this rule

Switch/Select statements

  • No empty lines between case clauses
  • Cases are kept compact

Spacing Rules

  • Single blank line between major sections
  • Single blank line between each type definition
  • Single blank line between each function/method/constructor
  • Double blank lines are compacted to single
  • No blank lines within const/var groups (only between groups)

About

Comprehensive opinionated formatter for Go

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors 2

  •  
  •