๐Ÿš€ Grammar-Aware Code Formatter: Structure through separation (supports Go, JavaScript, TypeScript, JSX, and TSX)
go formatter code-formatter javascript typescript jsx tsx
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Go 100.0%
1 1 0

Clone this repository

https://tangled.org/fuwn.net/iku https://tangled.org/did:plc:g4lsi6ub2d3kqklfokk3dvmy/iku
git@tangled.org:fuwn.net/iku git@tangled.org:did:plc:g4lsi6ub2d3kqklfokk3dvmy/iku

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

๐Ÿš€ Iku#

Grammar-Aware Go Formatter

Iku is a grammar-based Go formatter that enforces consistent blank-line placement by AST node type.

Philosophy#

Code structure should be visually apparent from its formatting. Iku groups statements by grammatical type and separates them with blank lines, making the code flow easier to read at a glance.

Rules#

  1. Same AST type means no blank line: Consecutive statements of the same type stay together
  2. Different AST type means blank line: Transitions between statement types get visual separation
  3. Scoped statements get blank lines: if, for, switch, select always have blank lines before them
  4. Top-level declarations are separated: Functions, types, and variables at the package level get blank lines between them

How It Works#

Iku runs go fmt first, then applies its grammar-based blank-line rules on top of it. Your code gets standard Go formatting plus structural separation.

Installation#

go install github.com/Fuwn/iku@latest

Usage#

# Format stdin
echo 'package main...' | iku

# Format and print to stdout
iku file.go

# Format in-place
iku -w file.go

# Format entire directory
iku -w ./...

# List files that need formatting
iku -l .

# Show diff
iku -d file.go

Flags#

Flag Description
-w Write result to file instead of stdout
-l List files whose formatting differs
-d Display diffs instead of rewriting
--comments Comment attachment mode: follow, precede, standalone
--version Print version

Examples#

Before#

package main

func main() {
    x := 1
    y := 2
    var config = loadConfig()
    defer cleanup()
    defer closeDB()
    if err != nil {
        return err
    }
    if x > 0 {
        process(x)
    }
    go worker()
    return nil
}

After#

package main

func main() {
    x := 1
    y := 2

    var config = loadConfig()

    defer cleanup()
    defer closeDB()

    if err != nil {
        return err
    }

    if x > 0 {
        process(x)
    }

    go worker()

    return nil
}

Notice how:

  • x := 1 and y := 2 (both AssignStmt) stay together
  • var config (DeclStmt) gets separated from assignments
  • defer statements stay grouped together
  • Each if statement gets a blank line before it (scoped statement)
  • go worker() (GoStmt) is separated from the if above
  • return (ReturnStmt) is separated from the go statement

Top-Level Declarations#

// Before
package main
type Config struct {
    Name string
}
var defaultConfig = Config{}
func main() {
    run()
}
func run() {
    process()
}

// After
package main

type Config struct {
    Name string
}

var defaultConfig = Config{}

func main() {
    run()
}

func run() {
    process()
}

Switch Statements#

// Before
func process(x int) {
    result := compute(x)
    switch result {
    case 1:
        handleOne()
        if needsExtra {
            doExtra()
        }
    case 2:
        handleTwo()
    }
    cleanup()
}

// After
func process(x int) {
    result := compute(x)

    switch result {
    case 1:
        handleOne()

        if needsExtra {
            doExtra()
        }
    case 2:
        handleTwo()
    }

    cleanup()
}

AST Node Types#

For reference, here are common Go statement types that Iku distinguishes:

Type Examples
*ast.AssignStmt x := 1, x = 2
*ast.DeclStmt var x = 1
*ast.ExprStmt fmt.Println(), doSomething()
*ast.ReturnStmt return x
*ast.IfStmt if x > 0 { }
*ast.ForStmt for i := 0; i < n; i++ { }
*ast.RangeStmt for k, v := range m { }
*ast.SwitchStmt switch x { }
*ast.SelectStmt select { }
*ast.DeferStmt defer f()
*ast.GoStmt go f()
*ast.SendStmt ch <- x

License#

This project is licensed under the GNU General Public License v3.0.