Skip to content

Commit 5be8006

Browse files
docs: add examples and usage guides
- Add example TypeScript project with migration scenarios - Include sample config files for different use cases - Add README with setup instructions and common patterns Amp-Thread-ID: https://ampcode.com/threads/T-5a47b294-ce3a-450b-b4fb-f2d13c01d3c2 Co-authored-by: Amp <amp@ampcode.com>
1 parent 8fab747 commit 5be8006

25 files changed

Lines changed: 1678 additions & 0 deletions

examples/README.md

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
# effect-migrate Examples
2+
3+
This directory contains example projects demonstrating effect-migrate in action.
4+
5+
## Examples
6+
7+
### `file-processor/` - Legacy File Processing
8+
9+
A TypeScript project with heavy async/await, Promise-based patterns, and imperative error handling. Perfect for demonstrating a full migration audit.
10+
11+
**Patterns detected:**
12+
- 15 async/await functions
13+
- 14 try/catch blocks
14+
- 8 console.* calls
15+
- 5 Promise.then chains
16+
- 3 Promise.all calls
17+
- 3 new Promise constructors
18+
19+
### `legacy-api/` - Database & API Layer
20+
21+
Example with database connections, REST API handlers, and nested error handling.
22+
23+
### `mid-migration/` - Partial Migration
24+
25+
Shows a project in the middle of migrating to Effect, with some files migrated and others not.
26+
27+
### `ecommerce-orders/` - E-Commerce Order Processing (Amp Optimized)
28+
29+
E-commerce order processing system in partial Effect migration. Demonstrates:
30+
- Mixed Effect and Promise-based patterns
31+
- Callback hell in legacy code
32+
- Architectural boundary violations
33+
- Amp context generation with `--amp-out`
34+
35+
### `clean-effect/` - Migrated Code
36+
37+
Already migrated to Effect patterns - shows zero violations and success state.
38+
39+
## Quick Start
40+
41+
Build the CLI first:
42+
```bash
43+
pnpm --filter @effect-migrate/cli build
44+
```
45+
46+
Then navigate to any example and run:
47+
```bash
48+
node ../../packages/cli/dist/index.js audit
49+
node ../../packages/cli/dist/index.js metrics
50+
```
51+
52+
---
53+
54+
## Creating New Examples
55+
56+
### Step 1: Setup Directory Structure
57+
58+
```bash
59+
mkdir -p examples/my-example/src/{services,repositories,controllers}
60+
mkdir -p examples/my-example/.amp
61+
```
62+
63+
### Step 2: Create Config File
64+
65+
Create `effect-migrate.config.json` (or `.ts`) with **all required fields**:
66+
67+
```json
68+
{
69+
"version": 1,
70+
"paths": {
71+
"root": "./src",
72+
"exclude": ["node_modules/**", "dist/**"]
73+
},
74+
"patterns": [
75+
{
76+
"id": "my-pattern-rule",
77+
"files": "**/*.ts", // ⚠️ REQUIRED - don't forget this!
78+
"pattern": "some-regex",
79+
"severity": "warning", // Must be "error" or "warning"
80+
"message": "Description of the issue",
81+
"tags": ["category", "type"] // Optional but recommended
82+
}
83+
]
84+
}
85+
```
86+
87+
**⚠️ Common Mistakes:**
88+
- Missing `files` field in pattern rules
89+
- Invalid `severity` (must be `"error"` or `"warning"`)
90+
- Forgetting to escape regex special characters (use `\\` not `\`)
91+
- Using `.config.ts` extension but not having TypeScript config export
92+
93+
### Step 3: Create Source Files
94+
95+
Create TypeScript files that demonstrate the patterns you want to detect:
96+
97+
```typescript
98+
// src/example.ts - Shows anti-pattern
99+
async function oldWay() {
100+
try {
101+
const result = await somePromise()
102+
return result
103+
} catch (error) {
104+
throw new Error(`Failed: ${error}`)
105+
}
106+
}
107+
108+
// src/migrated.ts - Shows Effect pattern
109+
const newWay = Effect.gen(function* () {
110+
const result = yield* Effect.tryPromise(() => somePromise())
111+
return result
112+
})
113+
```
114+
115+
### Step 4: Add package.json (Optional)
116+
117+
```json
118+
{
119+
"name": "my-example",
120+
"type": "module",
121+
"description": "Example showing X pattern migration"
122+
}
123+
```
124+
125+
### Step 5: Test Without Amp Output
126+
127+
```bash
128+
cd examples/my-example
129+
130+
# Test config loads correctly
131+
node ../../packages/cli/dist/index.js audit --config effect-migrate.config.json
132+
133+
# Check metrics calculation
134+
node ../../packages/cli/dist/index.js metrics --config effect-migrate.config.json
135+
```
136+
137+
**Expected output:**
138+
- ✓ Loaded config from...
139+
- Running N rules...
140+
- Findings displayed
141+
142+
**Common errors:**
143+
- `Config validation failed: ["patterns"][0]["files"] is missing` → Add `files` field
144+
- `Received unknown argument` → Check flag spelling (`--amp-out` not `--amp-output`)
145+
146+
### Step 6: Test With Amp Output
147+
148+
```bash
149+
# Generate Amp context files
150+
node ../../packages/cli/dist/index.js audit --config effect-migrate.config.json --amp-out .amp
151+
152+
# Generate metrics for Amp
153+
node ../../packages/cli/dist/index.js metrics --config effect-migrate.config.json --amp-out .amp
154+
```
155+
156+
**Expected output:**
157+
- ✓ audit.json
158+
- ✓ index.json
159+
- ✓ badges.md
160+
- ✓ metrics.json (from metrics command)
161+
- ✓ Wrote Amp context to .amp
162+
163+
**Verify generated files:**
164+
```bash
165+
ls .amp/
166+
# Should show: audit.json badges.md index.json metrics.json
167+
```
168+
169+
### Step 7: Document Your Example
170+
171+
Create `README.md` in your example:
172+
173+
```markdown
174+
# My Example - Description
175+
176+
## Project Status
177+
178+
**Migration Progress:** ~X% complete
179+
180+
## Known Issues
181+
182+
1. Issue category 1
183+
2. Issue category 2
184+
185+
## Using effect-migrate
186+
187+
\`\`\`bash
188+
effect-migrate audit
189+
effect-migrate metrics
190+
191+
# For Amp users
192+
effect-migrate audit --amp-out .amp
193+
\`\`\`
194+
195+
## For Amp Users
196+
197+
The `.amp/` directory contains migration context that helps Amp understand:
198+
- Current migration state (audit.json)
199+
- Quantitative metrics (metrics.json)
200+
- Quick reference badges (badges.md)
201+
```
202+
203+
### Step 8: Validate Schema
204+
205+
Double-check your config against the schema:
206+
207+
**Pattern Rule Required Fields:**
208+
-`id` (string)
209+
-`files` (string or array of strings)
210+
-`pattern` (string or regex object)
211+
-`severity` ("error" | "warning")
212+
-`message` (string)
213+
214+
**Pattern Rule Optional Fields:**
215+
- `negativePattern` (string) - exclude matches
216+
- `docsUrl` (string) - link to docs
217+
- `tags` (array of strings) - categorization
218+
219+
**Boundary Rule Required Fields:**
220+
-`id` (string)
221+
-`from` (string glob)
222+
-`disallow` (array of strings)
223+
-`severity` ("error" | "warning")
224+
-`message` (string)
225+
226+
### Debugging Tips
227+
228+
**Config won't load:**
229+
```bash
230+
# Test just the config
231+
cat effect-migrate.config.json | jq
232+
# Should parse as valid JSON
233+
```
234+
235+
**Pattern not matching:**
236+
```bash
237+
# Add --log-level debug for verbose output
238+
node ../../packages/cli/dist/index.js audit --log-level debug
239+
```
240+
241+
**Amp output not generating:**
242+
```bash
243+
# Check permissions
244+
mkdir -p .amp
245+
chmod 755 .amp
246+
247+
# Verify path
248+
node ../../packages/cli/dist/index.js audit --amp-out .amp
249+
# NOT: --amp-out (without directory)
250+
```
251+
252+
---
253+
254+
## Testing All Examples
255+
256+
From the root:
257+
258+
```bash
259+
# Build CLI
260+
pnpm --filter @effect-migrate/cli build
261+
262+
# Test all examples
263+
for dir in examples/*/; do
264+
if [ -f "$dir/effect-migrate.config.json" ] || [ -f "$dir/effect-migrate.config.ts" ]; then
265+
echo "Testing: $dir"
266+
cd "$dir"
267+
node ../../packages/cli/dist/index.js audit
268+
cd ../..
269+
fi
270+
done
271+
```
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
export default {
2+
version: 1,
3+
paths: {
4+
root: "src",
5+
include: ["**/*.ts"],
6+
exclude: ["node_modules/**", "dist/**"]
7+
},
8+
patterns: [
9+
{
10+
id: "no-async-await",
11+
pattern: "\\basync\\s+(function\\s+\\w+|(\\([^)]*\\)|[\\w]+)\\s*=>)",
12+
files: "**/*.ts",
13+
message: "Replace async/await with Effect.gen",
14+
severity: "warning"
15+
}
16+
],
17+
concurrency: 4
18+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Already migrated to Effect - should have no violations
2+
import { Effect } from "effect"
3+
import * as FileSystem from "@effect/platform/FileSystem"
4+
5+
export const readConfig = (path: string) =>
6+
Effect.gen(function* () {
7+
const fs = yield* FileSystem.FileSystem
8+
const content = yield* fs.readFileString(path)
9+
return JSON.parse(content)
10+
})
11+
12+
export const processData = (input: string) =>
13+
Effect.gen(function* () {
14+
const result = input.toUpperCase()
15+
return result
16+
})
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
export default {
2+
version: 1,
3+
paths: {
4+
root: "src",
5+
include: ["**/*.ts"],
6+
exclude: ["node_modules/**", "dist/**"]
7+
},
8+
patterns: [
9+
{
10+
id: "no-async-await",
11+
pattern: "\\basync\\s+(function\\s+\\w+|(\\([^)]*\\)|[\\w]+)\\s*=>)",
12+
files: "**/*.ts",
13+
message: "Replace async/await with Effect.gen for composable async operations",
14+
severity: "warning",
15+
docsUrl: "https://effect.website/docs/essentials/effect-type"
16+
},
17+
{
18+
id: "no-promise-constructor",
19+
pattern: "new\\s+Promise\\s*<",
20+
files: "**/*.ts",
21+
message: "Replace new Promise() with Effect.async or Effect.tryPromise",
22+
severity: "warning",
23+
docsUrl: "https://effect.website/docs/guides/observability/logging"
24+
},
25+
{
26+
id: "no-try-catch",
27+
pattern: "\\btry\\s*\\{",
28+
files: "**/*.ts",
29+
message: "Replace try/catch with Effect.catchAll or Effect.catchTag for typed errors",
30+
severity: "warning",
31+
docsUrl: "https://effect.website/docs/essentials/error-management"
32+
},
33+
{
34+
id: "no-promise-all",
35+
pattern: "Promise\\.all\\s*\\(",
36+
files: "**/*.ts",
37+
message: "Replace Promise.all with Effect.forEach for concurrent Effect execution",
38+
severity: "warning",
39+
docsUrl: "https://effect.website/docs/guides/concurrency"
40+
},
41+
{
42+
id: "no-promise-chaining",
43+
pattern: "\\.then\\s*\\(",
44+
files: "**/*.ts",
45+
message: "Replace Promise.then chaining with Effect.gen or pipe for better composition",
46+
severity: "warning",
47+
docsUrl: "https://effect.website/docs/essentials/pipeline"
48+
},
49+
{
50+
id: "console-log",
51+
pattern: "console\\.(log|error|warn)\\s*\\(",
52+
files: "**/*.ts",
53+
message: "Replace console.* with Effect Console service for testable logging",
54+
severity: "warning",
55+
docsUrl: "https://effect.website/docs/guides/observability/logging"
56+
}
57+
],
58+
concurrency: 4
59+
}

0 commit comments

Comments
 (0)