Skip to content

Commit 0232f05

Browse files
ernadoclaude
andcommitted
test: cover entities, chat actions, edit-media variants, media groups
Round-trip every message entity type, exercise all SendChatAction actions, EditMessageMedia for video/animation/audio/document/photo by id/url/upload, and document/video media groups plus the non-upload rejection. Root coverage ~73%→77%. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent cf6a259 commit 0232f05

4 files changed

Lines changed: 748 additions & 0 deletions

File tree

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
---
2+
name: golang-refactor-tools
3+
description: >
4+
Go code refactoring with automated tools: gofmt -r, gopatch, and rsc.io/rf.
5+
Use this skill when performing mechanical rewrites across a codebase — renaming
6+
identifiers, migrating API calls, moving types between packages, rewriting
7+
expressions, or replacing deprecated patterns. Triggers when the task involves
8+
bulk code transformation, API migration, structural rewrite, or the user mentions
9+
gofmt -r, rf, gopatch, coccinelle-style patching, or large-scale rename/move in Go.
10+
---
11+
12+
# Go Refactoring Tools
13+
14+
## Decision table
15+
16+
| Situation | Tool |
17+
|---|---|
18+
| Swap one expression for another | `gofmt -r` |
19+
| Structural multi-line or multi-statement rewrite | `gopatch` |
20+
| Type-sensitive expression rewrite | `rf ex` |
21+
| Rename / move identifier, type, function, package | `rf mv` |
22+
| Delete declarations | `rf rm` |
23+
24+
> **Workflow**: dry-run first (`gopatch -d` / `rf -diff`), review the diff, then apply.
25+
> After any tool run: `goimports -w . && go build ./... && go test ./...`. Commit before bulk rewrites.
26+
27+
---
28+
29+
## `gofmt -r` — quickest, ships with Go
30+
31+
Syntax-aware but **not type-aware**. Pattern variables must be **single lowercase letters**; everything else is matched literally. `-w .` recurses naturally — `./...` is a Go package pattern and will error.
32+
33+
```bash
34+
gofmt -r 'a.OldMethod(b) -> a.NewMethod(b)' -w .
35+
gofmt -r 'ioutil.ReadAll(a) -> io.ReadAll(a)' -w . # ioutil/io are literal; a is wildcard
36+
```
37+
38+
After running: fix imports with `goimports -w .` (gofmt -r never touches imports).
39+
40+
---
41+
42+
## `gopatch` — structural patch files
43+
44+
Operates on syntax, understands statements and imports. Can work on partially-invalid code.
45+
46+
```bash
47+
go install github.com/uber-go/gopatch@latest
48+
gopatch -p my.patch ./... # rewrite in place
49+
gopatch -d -p my.patch ./... # dry-run: print diff
50+
gopatch ./... <<'EOF' # read patch from stdin (omit -p)
51+
...
52+
EOF
53+
```
54+
55+
### Patch anatomy
56+
57+
```patch
58+
# Description (shown in -d output)
59+
@@
60+
var x expression # matches any Go expression
61+
var n identifier # matches any single identifier
62+
@@
63+
-old code
64+
+new code
65+
```
66+
67+
**Metavariable types**: `expression` (calls, field accesses, literals…), `identifier` (single name).
68+
**Undeclared identifiers** are matched literally — `a`, `b`, `c` in the body match only args named exactly `a`, `b`, `c`. Use `...` (elision) or declare `var a expression` explicitly.
69+
**`...`**: matches zero or more statements/arguments. Multiple `@@…@@` blocks = multiple patches run in order.
70+
71+
### Examples
72+
73+
**Replace call + fix import in one patch:**
74+
```patch
75+
@@
76+
@@
77+
-import "io/ioutil"
78+
+import "io"
79+
80+
-ioutil.ReadAll(...)
81+
+io.ReadAll(...)
82+
```
83+
84+
**Remove boilerplate with elision:**
85+
```patch
86+
# Delete redundant gomock.Controller.Finish()
87+
@@
88+
var ctrl, gomock identifier
89+
var t expression
90+
@@
91+
import gomock "github.com/golang/mock/gomock"
92+
93+
ctrl := gomock.NewController(t)
94+
...
95+
-defer ctrl.Finish()
96+
```
97+
98+
**Replace expression with sub-expression wildcard:**
99+
```patch
100+
@@
101+
var x expression
102+
@@
103+
-time.Now().Sub(x)
104+
+time.Since(x)
105+
```
106+
107+
---
108+
109+
## `rsc.io/rf` — rename, move, expression rewrite
110+
111+
> **Experimental**: rf's README says *"incredibly rough and likely to be buggy and change incompatibly."* Prefer `gopatch` for structural work; use `rf` when type-awareness is required (renames, moves, typed expression rewrites).
112+
113+
Takes a **single script argument** and operates on the module in the current directory — no `./...`.
114+
115+
```bash
116+
go install rsc.io/rf@latest
117+
rf -diff 'mv Foo Bar' # show diff without writing
118+
```
119+
120+
### `mv` — rename or move
121+
122+
```bash
123+
rf 'mv OldType NewType'
124+
rf 'mv pkg.OldFunc pkg.NewFunc'
125+
rf 'mv mypkg.Foo otherpkg.Foo'
126+
rf 'mv MyStruct.OldField MyStruct.NewField'
127+
```
128+
129+
### `ex` — type-aware expression rewrite
130+
131+
Variables inside `{ }` are **typed** metavariables — only values of the declared type match, so there are no false positives on same-named identifiers from other packages. If a type doesn't precisely match the AST node, the rule is silently skipped. Multiple rules go in one block.
132+
133+
```bash
134+
rf 'ex {
135+
var s string
136+
var r io.Reader
137+
fmt.Sprintf("%s", s) -> s
138+
ioutil.ReadAll(r) -> io.ReadAll(r)
139+
}'
140+
```
141+
142+
`avoid` prevents rewriting inside named method bodies:
143+
```bash
144+
rf 'ex {
145+
var m myMap
146+
var k, v int
147+
avoid myMap.Get
148+
m[k] -> m.Get(k)
149+
}'
150+
```
151+
152+
### `rm` / `add`
153+
154+
```bash
155+
rf 'rm OldFunc'
156+
rf 'rm MyType.DeprecatedField'
157+
rf 'add MyStruct.NewField int `json:"new_field"`'
158+
```
159+
160+
---
161+
162+
## Common recipes
163+
164+
### Rename a public type
165+
166+
```bash
167+
rf 'mv pkg.OldName pkg.NewName'
168+
```

0 commit comments

Comments
 (0)