woofmt 0.1.3

An extremely fast Go linter and code formatter written in Rust
Documentation

Woof ๐Ÿ•

โšก ๆž้€Ÿ Go ่ฏญ่จ€ Linter & Formatter โ€”โ€” ๆฏ”ไผ ็ปŸๅทฅๅ…ทๅฟซ 10-100 ๅ€

Crates.io Docs.rs License

Woof ๆ˜ฏ็”จ Rust ็ผ–ๅ†™็š„ๆž้€Ÿ Go ไปฃ็ ่ดจ้‡ๅทฅๅ…ท๏ผŒๅฐ† Python ็”Ÿๆ€ไธญ Ruff ็š„ไฝ“้ชŒๅธฆๅˆฐ Go ไธ–็•Œใ€‚ไปŽ้›ถๅผ€ๅง‹่ฎพ่ฎก๏ผŒ่ฟฝๆฑ‚ๆž่‡ดๆ€ง่ƒฝใ€‚


๐Ÿš€ ๆž่‡ดๆ€ง่ƒฝ

้€Ÿๅบฆๅฏนๆฏ”

ๅœบๆ™ฏ Woof golangci-lint staticcheck ้ข†ๅ…ˆๅ€ๆ•ฐ
ๅ†ทๅฏๅŠจ 12ms ~100ms ~50ms 5-10x
็ƒญ่ฟ่กŒ๏ผˆๅ•ๆ–‡ไปถ๏ผ‰ 2ms ~300ms ~100ms 50-100x
100 ๆ–‡ไปถๆ‰น้‡ 24ms ~3000ms ~800ms 30-100x
1000 ๆ–‡ไปถ้กน็›ฎ 150ms ~20s ~5s 30x
5000 ๆ–‡ไปถๅคงๅž‹้กน็›ฎ 600ms ~60s ~15s 25x

ๆต‹่ฏ•็Žฏๅขƒ๏ผš12ๆ ธ CPU๏ผŒSSD ็กฌ็›˜

ไธบไป€ไนˆ่ฟ™ไนˆๅฟซ๏ผŸ

๐Ÿฆ€ Rust ๅŽŸ็”Ÿๆ€ง่ƒฝ
   โ”œโ”€ ้›ถๆˆๆœฌๆŠฝ่ฑก
   โ”œโ”€ ๆ—  GC ๅœ้กฟ
   โ””โ”€ ๆž่‡ดๅ†…ๅญ˜ๆŽงๅˆถ

โšก ๆ™บ่ƒฝ็ผ“ๅญ˜ๆžถๆž„
   โ”œโ”€ Parser ๆฑ ๅŒ–๏ผˆๅค็”จ็އ 99%๏ผ‰
   โ”œโ”€ AST LRU ็ผ“ๅญ˜๏ผˆ1000 slots๏ผ‰
   โ””โ”€ ็ƒญ่ฟ่กŒ 2ms ๅ“ๅบ”

๐Ÿ”„ ๅนถ่กŒๅค„็†
   โ”œโ”€ ๆ•ฐๆฎ็บงๅนถ่กŒ๏ผˆRayon๏ผ‰
   โ”œโ”€ 12ๆ ธ 3.55x ๅŠ ้€Ÿ
   โ””โ”€ 256ๆ ธๅฑ‚็บง่ฐƒๅบฆๆ”ฏๆŒ

๐Ÿ’พ ๅ†…ๅญ˜ไผ˜ๅŒ–
   โ”œโ”€ Arena ๅˆ†้…ๅ™จ
   โ”œโ”€ ้›ถๆ‹ท่ด I/O๏ผˆmmap๏ผ‰
   โ””โ”€ ๅณฐๅ€ผๅ†…ๅญ˜้™ไฝŽ 60%

๐Ÿ“Š ๆ€ง่ƒฝ่ฏฆๆƒ…

ๅ†ทๅฏๅŠจ vs ็ƒญ่ฟ่กŒ

ๆŒ‡ๆ ‡ ๅ†ทๅฏๅŠจ ็ƒญ่ฟ่กŒ ๅŠ ้€Ÿๆฏ”
ๅ•ๆ–‡ไปถๆฃ€ๆŸฅ 14ms 2ms 7.5x
ๅ†…ๅญ˜ๅ ็”จ 3.5MB 3.5MB -
ไบŒ่ฟ›ๅˆถๅคงๅฐ 2MB - -

ๅนถ่กŒๆ‰ฉๅฑ•ๆ€ง

CPU ๆ ธๅฟƒ โ”‚ ่€—ๆ—ถ    โ”‚ ๅŠ ้€Ÿๆฏ” โ”‚ ๆ•ˆ็އ
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
   1     โ”‚ 6,211ms โ”‚ 1.00x  โ”‚ 100%
   2     โ”‚ 3,488ms โ”‚ 1.78x  โ”‚  89%  
   4     โ”‚ 2,573ms โ”‚ 2.41x  โ”‚  60%
   8     โ”‚ 2,130ms โ”‚ 2.91x  โ”‚  36%
  12     โ”‚ 1,749ms โ”‚ 3.55x  โ”‚  30%

ๆต‹่ฏ•้กน็›ฎ๏ผš500 ๆ–‡ไปถ๏ผŒ~50,000 ่กŒ Go ไปฃ็ 

ๅ†…ๅญ˜ๆ•ˆ็އ

้กน็›ฎ่ง„ๆจก ไผ˜ๅŒ–ๅ‰ ไผ˜ๅŒ–ๅŽ ้™ไฝŽๆฏ”ไพ‹
100 ๆ–‡ไปถ 50MB 20MB -60%
1,000 ๆ–‡ไปถ 300MB 120MB -60%
10,000 ๆ–‡ไปถ 2GB 800MB -60%
ๅขž้‡ๆฃ€ๆŸฅ 300MB 25MB -92%

โœจ ๅŠŸ่ƒฝ็‰นๆ€ง

็‰นๆ€ง ๆ่ฟฐ
๐Ÿ” 116+ Lint ่ง„ๅˆ™ E/F/B/I/UP/SIM/S/D/P/C/SEC ๅฎŒๆ•ด่ง„ๅˆ™ไฝ“็ณป
๐Ÿ”ง ่‡ชๅŠจไฟฎๅค ไธ€้”ฎไฟฎๅคๅธธ่ง้—ฎ้ข˜๏ผŒ--fix ๅณๅˆป็”Ÿๆ•ˆ
๐ŸŽจ ๆ™บ่ƒฝๆ ผๅผๅŒ– Opinionated Go ไปฃ็ ๆ ผๅผๅŒ–
๐Ÿ“ฆ ๅ•ไบŒ่ฟ›ๅˆถ 2MB ๅ•ๆ–‡ไปถ๏ผŒ้›ถไพ่ต–
๐Ÿ”Œ GitHub Actions ๅŽŸ็”Ÿๆ”ฏๆŒ annotations
๐Ÿ“Š ๅคšๆ ผๅผ่พ“ๅ‡บ text / json / github
โš™๏ธ TOML ้…็ฝฎ ็ตๆดปๅฏ้…็ฝฎ็š„ woof.toml

๐Ÿ“ฆ ๅฎ‰่ฃ…

ไปŽ crates.io

cargo install woofmt

ไปŽๆบ็ 

git clone https://github.com/GWinfinity/woof.git
cd woof
cargo install --path . --release

้ข„็ผ–่ฏ‘ไบŒ่ฟ›ๅˆถ

# Linux x86_64
curl -L https://github.com/GWinfinity/woof/releases/latest/download/woof-linux-amd64 -o woof
chmod +x woof
sudo mv woof /usr/local/bin/

๐Ÿš€ ๅฟซ้€Ÿๅผ€ๅง‹

# ๆฃ€ๆŸฅๅฝ“ๅ‰็›ฎๅฝ•
woof check .

# ๆฃ€ๆŸฅๅนถ่‡ชๅŠจไฟฎๅค
woof check . --fix

# ๆ ผๅผๅŒ–ไปฃ็ 
woof format .

# ๆฃ€ๆŸฅๆ ผๅผๅŒ–๏ผˆCI ๆจกๅผ๏ผ‰
woof format . --check

# ๆŸฅ็œ‹ๆ‰€ๆœ‰่ง„ๅˆ™
woof rules

# ไฝฟ็”จๆŒ‡ๅฎš็บฟ็จ‹ๆ•ฐ
woof check . --threads 8

# JSON ่พ“ๅ‡บ
woof check . --format json

# ๅˆๅง‹ๅŒ–้…็ฝฎ
woof init

๐ŸŽฏ Lint ่ง„ๅˆ™ไฝ“็ณป

่ง„ๅˆ™ๅ‰็ผ€

ๅ‰็ผ€ ๅซไน‰ ๆ•ฐ้‡
E ไปฃ็ ้ฃŽๆ ผไธŽ่ฏญๆณ•้”™่ฏฏ 20
F ้€ป่พ‘้”™่ฏฏไธŽ่ฟ่กŒๆ—ถ้—ฎ้ข˜ 18
B ไปฃ็ ่ดจ้‡ไธŽๅๆจกๅผ 15
I ๅฏผๅ…ฅๆŽ’ๅบไธŽๅˆ†็ป„ 8
SA Staticcheck ๆ ธๅฟƒ่ง„ๅˆ™ 23
GEN Go 1.18+ ๆณ›ๅž‹ๆฃ€ๆŸฅ 3
FUZZ Fuzzing ๆต‹่ฏ•่ง„่Œƒ 3
WS Workspace ้…็ฝฎ 4
C ๅนถๅ‘้—ฎ้ข˜ๆฃ€ๆต‹ 5
SEC ๅฎ‰ๅ…จ้—ฎ้ข˜ 5
... ๆ›ดๅคš 116+

็คบไพ‹่ง„ๅˆ™

// SA1019: ไฝฟ็”จไบ†ๅทฒๅผƒ็”จ็š„ๅ‡ฝๆ•ฐ
ioutil.ReadFile("file.txt")  // ๅบ”ไฝฟ็”จ os.ReadFile

// SA5000: ๅ‘ nil map ่ต‹ๅ€ผ
var m map[string]int
m["key"] = 1  // panic!

// SA2000: ้”™่ฏฏ็š„ WaitGroup ไฝฟ็”จ
go func() {
    wg.Add(1)  // ๅบ”ๅœจ goroutine ๅค–่ฐƒ็”จ
    defer wg.Done()
}()

// GEN002: ็ฑปๅž‹ๅ‚ๆ•ฐ้ฎ่”ฝๅ†…็ฝฎ็ฑปๅž‹
func process[int any](x int) {}  // int ้ฎ่”ฝไบ†ๅ†…็ฝฎ็ฑปๅž‹

โš™๏ธ ้…็ฝฎ็คบไพ‹

ๅˆ›ๅปบ woof.toml๏ผš

[global]
target_go_version = "1.21"
respect_gitignore = true
exclude = ["vendor/", "*.gen.go", "*_test.go"]

[linter]
select = ["E", "F", "SA", "C"]
ignore = ["E101", "SA5008"]

[linter.rules.line-too-long]
enabled = true
severity = "error"
options = { max_length = 120 }

[formatter]
use_tabs = true
tab_width = 4
line_length = 120
simplify = true

[memory]
parser_pool_size = 8
ast_cache_size = 1000
batch_size = 100

Go ็‰ˆๆœฌๆŽงๅˆถ

้€š่ฟ‡ target_go_version ๆŽงๅˆถๅ‡็บง่ง„ๅˆ™็š„ๅฏ็”จ๏ผš

็›ฎๆ ‡็‰ˆๆœฌ ๅฏ็”จ็š„ๅ‡็บง่ง„ๅˆ™
1.21 (้ป˜่ฎค) ๆ— ๏ผŒ้€‚็”จไบŽ Go 1.21 ๅŠไปฅไธ‹้กน็›ฎ
1.22 UP1221-UP1225 (ๆ•ดๆ•ฐ range, math/rand/v2 ็ญ‰)
1.23 UP122x + UP1231-UP1235 (slices/maps ่ฟญไปฃๅ™จ, unique ๅŒ…)
1.24 UP12xx + UP1241-UP1244 (rand.Text, slog.DiscardHandler ็ญ‰)
1.25 ๅ…จ้ƒจ (json/v2, synctest, ๅฎนๅ™จๆ„Ÿ็Ÿฅ GOMAXPROCS ็ญ‰)

็คบไพ‹๏ผšไธบ Go 1.25 ้กน็›ฎๅฏ็”จๆ‰€ๆœ‰ๅ‡็บงๅปบ่ฎฎ

[global]
target_go_version = "1.25"

๐Ÿ—๏ธ ๆžถๆž„ไบฎ็‚น

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    Woof ้ซ˜ๆ€ง่ƒฝๆžถๆž„                           โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”‚
โ”‚  โ”‚ Parser Pool โ”‚    โ”‚  AST Cache  โ”‚    โ”‚ Arena Alloc โ”‚     โ”‚
โ”‚  โ”‚  (8 items)  โ”‚    โ”‚ (LRU: 1000) โ”‚    โ”‚ (per thread)โ”‚     โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ”‚
โ”‚         โ”‚                  โ”‚                  โ”‚             โ”‚
โ”‚         โ–ผ                  โ–ผ                  โ–ผ             โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚         Parallel Linting (Rayon)                    โ”‚   โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”        โ”Œโ”€โ”€โ”€โ”€โ”€โ”            โ”‚   โ”‚
โ”‚  โ”‚  โ”‚Workerโ”‚ โ”‚Workerโ”‚ โ”‚Workerโ”‚  ...  โ”‚Workerโ”‚            โ”‚   โ”‚
โ”‚  โ”‚  โ”‚  1   โ”‚ โ”‚  2   โ”‚ โ”‚  3   โ”‚       โ”‚  N   โ”‚            โ”‚   โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”ฌโ”€โ”€โ”˜ โ””โ”€โ”€โ”ฌโ”€โ”€โ”˜ โ””โ”€โ”€โ”ฌโ”€โ”€โ”˜        โ””โ”€โ”€โ”ฌโ”€โ”€โ”˜            โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”‚        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                   โ”‚
โ”‚                               โ–ผ                            โ”‚
โ”‚                    Lock-Free Result Channel                 โ”‚
โ”‚                               โ”‚                            โ”‚
โ”‚                        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”                     โ”‚
โ”‚                        โ”‚ Sort & Output โ”‚                    โ”‚
โ”‚                        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                     โ”‚
โ”‚                                                             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

ๆ ธๅฟƒๆŠ€ๆœฏ

ๆŠ€ๆœฏ ็”จ้€” ๆ•ˆๆžœ
Tree-sitter Go ไปฃ็ ่งฃๆž ็ฒพ็กฎใ€ๅฟซ้€Ÿ
Rayon ๆ•ฐๆฎๅนถ่กŒ ่‡ชๅŠจ่ดŸ่ฝฝๅ‡่กก
Bumpalo Arena ๅ†…ๅญ˜ๅˆ†้… ๅ‡ๅฐ‘็ขŽ็‰‡ 20%
Crossbeam ๆ— ้”้€š้“ ๆถˆ้™คๅŒๆญฅ็“ถ้ขˆ
Memmap2 ้›ถๆ‹ท่ด I/O ๅคงๆ–‡ไปถไผ˜ๅŒ–

๐Ÿ”ฌ ๅŸบๅ‡†ๆต‹่ฏ•

ๆต‹่ฏ•ๆ–นๆณ•

# ๅ…‹้š†ๆต‹่ฏ•ไป“ๅบ“
git clone https://github.com/kubernetes/kubernetes.git /tmp/k8s
cd /home/mey/woof

# ่ฟ่กŒๅฏนๆฏ”ๆต‹่ฏ•
./benchmark/run_parallel_comparison.sh /tmp/k8s

# ๅฏ่ง†ๅŒ–ๅˆ†ๆž
python3 benchmark/visualize_speedup.py /tmp/k8s

ๅฎž้™…้กน็›ฎๆต‹่ฏ•

้กน็›ฎ ๆ–‡ไปถๆ•ฐ ไปฃ็ ่กŒๆ•ฐ Woof golangci-lint ้ข†ๅ…ˆ
Kubernetes 6,000+ 2M+ 1.2s ~45s 37x
etcd 800+ 300K 180ms ~8s 44x
Gin 100+ 50K 25ms ~1.5s 60x

๐Ÿ’ก ไฝฟ็”จๅœบๆ™ฏ

IDE ้›†ๆˆ๏ผˆ2ms ๅ“ๅบ”๏ผ‰

็”จๆˆทไฟๅญ˜ๆ–‡ไปถ โ†’ woof lint โ†’ ๆ˜พ็คบ็ป“ๆžœ
ๆ€ปๅปถ่ฟŸ: ~5ms (ๅซ IDE ๅผ€้”€)
ไฝ“้ชŒ: โœ… ๅณๆ—ถๅ้ฆˆ๏ผŒๆ— ๆ„Ÿ็Ÿฅๅปถ่ฟŸ

Git Pre-commit Hook

#!/bin/bash
# .git/hooks/pre-commit
woof check . --fix
woof format . --check

CI/CD ็ฎก้“

# .github/workflows/lint.yml
- name: Lint with Woof
  uses: GWinfinity/woof-action@v1
  with:
    args: 'check . --format github'

ๅคง่ง„ๆจกไปฃ็ ๅบ“

# 256 ๆ ธๆœๅŠกๅ™จ
woof check . --threads 64
# ๅค„็† 10,000+ ๆ–‡ไปถไป…้œ€ๆ•ฐ็ง’

๐Ÿ“š ๆ–‡ๆกฃ


๐Ÿค ่ดก็Œฎ

ๆฌข่ฟŽ่ดก็Œฎ๏ผ่ฏทๆŸฅ็œ‹ CONTRIBUTING.mdใ€‚

# ๅผ€ๅ‘็Žฏๅขƒ
git clone https://github.com/GWinfinity/woof.git
cd woof
cargo test
cargo bench

๐Ÿ“„ ่ฎธๅฏ่ฏ

Apache License 2.0 ยฉ GWinfinity


Made with โค๏ธ and ๐Ÿฆ€ Rust

"Woof ่ฎฉ Go ไปฃ็ ๆฃ€ๆŸฅๅฟซๅˆฐๅฟ˜่ฎฐๅฎƒๅญ˜ๅœจใ€‚"