Skip to content

Commit 45516dc

Browse files
committed
feat: add scripts to generate rules by skill level, use case, and compact format
1 parent 12879ff commit 45516dc

30 files changed

Lines changed: 7235 additions & 540 deletions

content/accumulate-multiple-errors-with-either.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ However, for tasks like validating a user's input, this is poor user experience.
4040

4141
Using `Schema.decode` with the `allErrors: true` option demonstrates this pattern perfectly. The underlying mechanism uses `Either` to collect all parsing errors into an array instead of stopping at the first one.
4242

43-
```typescript
43+
````typescript
4444
import { Effect, Schema } from "effect";
4545

4646
const UserSchema = Schema.Struct({
@@ -72,15 +72,15 @@ Validation failed with multiple errors:
7272
1. name must be a string at least 3 character(s) long
7373
2. email must be a string matching the pattern /@/
7474
*/
75-
```
75+
````
7676

7777
---
7878

7979
## Anti-Pattern
8080

8181
Using `Effect`'s error channel for validation that requires multiple error messages. The code below will only ever report the first error it finds, because `Effect.fail` short-circuits the entire `Effect.gen` block.
8282

83-
```typescript
83+
````typescript
8484
import { Effect } from "effect";
8585

8686
const validateWithEffect = (input: { name: string; email: string }) =>
@@ -94,4 +94,4 @@ const validateWithEffect = (input: { name: string; email: string }) =>
9494
}
9595
return yield* Effect.succeed(input);
9696
});
97-
```
97+
````

content/distinguish-not-found-from-errors.mdx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ By using `Option` inside the success channel of an `Effect`, you keep the error
4343

4444
This function to find a user can fail if the database is down, or it can succeed but find no user. The return type ``Effect.Effect<Option.Option<User>, DatabaseError>`` makes this contract perfectly clear.
4545

46-
```typescript
46+
````typescript
4747
import { Effect, Option, Data } from "effect";
4848

4949
interface User {
@@ -79,12 +79,13 @@ const program = (id: number) =>
7979
}),
8080
}),
8181
);
82+
````
8283

8384
## Anti-Pattern
8485

8586
A common alternative is to create a specific NotFoundError and put it in the error channel alongside other errors.
8687

87-
```typescript
88+
````typescript
8889
class NotFoundError extends Data.TaggedError("NotFoundError") {}
8990

9091
// ❌ This signature conflates two different kinds of failure.
@@ -94,8 +95,8 @@ class NotFoundError extends Data.TaggedError("NotFoundError") {}
9495
// ...
9596
return Effect.fail(new NotFoundError());
9697
};
97-
```
98+
````
9899

99100
While this works, it can be less expressive. It treats a "not found" result—which might be a normal part of your application's flow—the same as a catastrophic DatabaseError.
100101

101-
Using ```Effect<Option<A>>``` often leads to clearer and more precise business logic.
102+
Using ````Effect<Option<A>>```` often leads to clearer and more precise business logic.

content/provide-config-layer.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Integrating configuration as a `Layer` plugs it directly into Effect's dependenc
2323

2424
## Good Example
2525

26-
```typescript
26+
````typescript
2727
import { Config, Effect, Layer } from "effect";
2828

2929
const ServerConfig = Config.all({ port: Config.number("PORT") });
@@ -33,7 +33,7 @@ const program = Effect.log("Application starting...");
3333
const configLayer = Config.layer(ServerConfig);
3434

3535
const runnable = Effect.provide(program, configLayer);
36-
```
36+
````
3737

3838
**Explanation:**
3939
This approach makes configuration available contextually, supporting better testing and modularity.

content/stream-retry-on-failure.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ The `retry` operator, combined with the `Schedule` module, provides a powerful a
4242

4343
This example simulates an API that fails the first two times it's called. The stream processes a list of IDs, and the `retry` operator ensures that the failing operation for `id: 2` is automatically retried until it succeeds.
4444

45-
```typescript
45+
````typescript
4646
import { Effect, Stream, Schedule } from 'effect';
4747

4848
let attempts = 0;
@@ -82,13 +82,13 @@ Output:
8282
... level=INFO msg="Attempting to process item 2..."
8383
... level=INFO msg="Attempting to process item 3..."
8484
*/
85-
```
85+
````
8686

8787
## Anti-Pattern
8888

8989
The anti-pattern is to either have no retry logic at all, or to write manual, imperative retry loops inside your processing function.
9090

91-
```typescript
91+
````typescript
9292
import { Effect, Stream } from 'effect';
9393
// ... same mock processItem function ...
9494

@@ -110,6 +110,6 @@ Output:
110110
... level=INFO msg="Item 2 failed, attempt 1."
111111
Pipeline failed: Error: API is temporarily down
112112
*/
113-
```
113+
````
114114

115115
This "fail-fast" approach is brittle. A single, temporary network blip would cause the entire pipeline to terminate, even if subsequent items could have been processed successfully. While manual retry logic inside `processItem` is possible, it pollutes the core logic with concerns about timing and attempt counting, and is far less composable and reusable than a `Schedule`.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
"rules": "bun scripts/generate_rules.ts"
1212
},
1313
"dependencies": {
14-
"effect": "^3.16.8"
14+
"effect": "^3.16.8",
15+
"process": "^0.11.10"
1516
},
1617
"devDependencies": {
1718
"@types/node": "^24.0.3",

pnpm-lock.yaml

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)