Merge commit '36c66dd290d3ce6eb1ccd310d0c658d4a32bb8eb' as 'repos/effect'
This commit is contained in:
102
repos/effect/.patterns/effect.md
Normal file
102
repos/effect/.patterns/effect.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# Effect Library Development Patterns
|
||||
|
||||
## NEVER: try-catch in Effect.gen
|
||||
|
||||
**REASON**: Effect generators handle errors through the Effect type system, not JavaScript exceptions.
|
||||
|
||||
```typescript
|
||||
// ❌ WRONG - This will cause runtime errors
|
||||
Effect.gen(function*() {
|
||||
try {
|
||||
const result = yield* someEffect
|
||||
return result
|
||||
} catch (error) {
|
||||
// This will never be reached and breaks Effect semantics
|
||||
console.error(error)
|
||||
}
|
||||
})
|
||||
|
||||
// ✅ CORRECT - Use Effect's built-in error handling
|
||||
Effect.gen(function*() {
|
||||
const result = yield* Effect.result(someEffect)
|
||||
if (result._tag === "Failure") {
|
||||
// Handle error case properly
|
||||
console.error("Effect failed:", result.cause)
|
||||
return yield* Effect.fail("Handled error")
|
||||
}
|
||||
return result.value
|
||||
})
|
||||
```
|
||||
|
||||
## return yield* Pattern for Errors
|
||||
|
||||
**CRITICAL**: Always use `return yield*` when yielding terminal effects.
|
||||
|
||||
```typescript
|
||||
// ✅ CORRECT - Makes termination explicit
|
||||
Effect.gen(function*() {
|
||||
if (invalidCondition) {
|
||||
return yield* Effect.fail("Validation failed")
|
||||
}
|
||||
|
||||
if (shouldInterrupt) {
|
||||
return yield* Effect.interrupt
|
||||
}
|
||||
|
||||
// Continue with normal flow
|
||||
const result = yield* someOtherEffect
|
||||
return result
|
||||
})
|
||||
|
||||
// ❌ WRONG - Missing return keyword leads to unreachable code
|
||||
Effect.gen(function*() {
|
||||
if (invalidCondition) {
|
||||
yield* Effect.fail("Validation failed") // Missing return!
|
||||
// Unreachable code after error!
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## `Effect.gen` and `Effect.fnUntraced`
|
||||
|
||||
Prefer `Effect.fnUntraced` over functions that only return `Effect.gen`.
|
||||
|
||||
```typescript
|
||||
// ❌ AVOID - Function only wraps Effect.gen
|
||||
const fn = (param: string) =>
|
||||
Effect.gen(function*() {
|
||||
// ...
|
||||
})
|
||||
|
||||
// ✅ PREFER - Reusable untraced Effect function
|
||||
const fn = Effect.fnUntraced(function*(param: string) {
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
## When to Use What
|
||||
|
||||
**Use `Effect.gen`** when:
|
||||
|
||||
- Writing inline effect composition
|
||||
- One-off operations that don't need to be reused
|
||||
- Inside other functions already being traced
|
||||
|
||||
**Use `Effect.fnUntraced`** when:
|
||||
|
||||
- Building library implementations
|
||||
- Performance is critical (hot paths)
|
||||
- Function is called many times per operation
|
||||
- Tracing overhead is unacceptable
|
||||
|
||||
## `Context.Service`
|
||||
|
||||
Prefer the class syntax when working with `Context.Service`.
|
||||
|
||||
```typescript
|
||||
import { Context } from "effect"
|
||||
|
||||
class MyService extends Context.Service<MyService, {
|
||||
readonly doSomething: (input: string) => number
|
||||
}>()("MyService") {}
|
||||
```
|
||||
53
repos/effect/.patterns/jsdoc.md
Normal file
53
repos/effect/.patterns/jsdoc.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# JSDoc Patterns
|
||||
|
||||
## `@category` Guidance
|
||||
|
||||
When adding or vetting JSDoc categories in public source files:
|
||||
|
||||
- Use exactly one `@category` tag for each public JSDoc block that represents a documented API.
|
||||
- Use shared categories consistently across the repository. Domain-specific categories are allowed when they improve navigation within a file or package, but avoid one-off categories unless they name an important API/domain concept.
|
||||
- Prefer lowercase category names by default, plural nouns for API buckets, and gerunds for operation families.
|
||||
- Preserve canonical casing for acronyms and proper API/domain names, such as `type IDs`, `DateTime`, `Undici`, and `HttpAgent`.
|
||||
- Prefer shared API-shape categories for common Effect/library patterns, and use domain-topic categories only when they provide clearer navigation.
|
||||
- Avoid vague fallback categories. Do not use `utils`, `common`, or `misc`; pick a specific shared or domain category instead.
|
||||
|
||||
## Common Shared Categories
|
||||
|
||||
- API shapes: `constructors`, `destructors`, `models`, `schemas`, `guards`, `predicates`, `getters`, `accessors`, `instances`, `constants`, `protocols`, `prototypes`, `re-exports`, `unsafe`, `testing`
|
||||
- Effect/service concepts: `services`, `tags`, `layers`, `context`, `resource management`, `running`
|
||||
- Type-level APIs: `utility types` for type-level helpers/contracts; use `models` for exported type/interface/class shapes that represent domain data
|
||||
- Error APIs: `errors` for error models/classes/types, `error handling` for recovery/catching/mapping APIs
|
||||
- Operations: `combinators`, `filtering`, `mapping`, `sequencing`, `zipping`, `combining`, `merging`, `converting`, `transforming`, `folding`, `splitting`, `repetition`
|
||||
- Encoding/data formats: `encoding`, `decoding`, `serialization`
|
||||
- Observability: `tracing`, `metrics`, `logging`
|
||||
- Other common concepts: `annotations`, `references`, `symbols`, `type IDs`, `configuration`, `math`, `comparisons`, `ordering`
|
||||
|
||||
## Category Normalization
|
||||
|
||||
Normalize category names before adding or reviewing JSDoc:
|
||||
|
||||
- Lowercase plain category names. Preserve established acronyms and proper
|
||||
names, such as `type IDs`, `DateTime`, `JSON getters`, `Base64 getters`, and
|
||||
`Standard Schema`.
|
||||
- Prefer shared plural buckets when the meaning is the same, such as
|
||||
`constructors`, `models`, `schemas`, `guards`, `getters`, `services`,
|
||||
`layers`, `generators`, `subscriptions`, `cookies`, and `sizes`.
|
||||
- Prefer shared operation families over narrow synonyms when precision is not
|
||||
important, such as `combining`, `mapping`, `filtering`, `folding`,
|
||||
`converting`, `transforming`, `sequencing`, and `repetition`.
|
||||
- Replace vague fallback categories such as `utils`, `common`, `misc`, or
|
||||
`helpers` with a specific shared or domain category.
|
||||
- Use `services` for `Context.Service` and `Context.Reference` exports, and
|
||||
use `tags` only for `Context.Tag` exports.
|
||||
- Fix obvious typos and compact variants during cleanup, such as
|
||||
`transferables`, `re-exports`, `resource management`, and `Standard Schema`.
|
||||
|
||||
## Distinctions
|
||||
|
||||
Keep these distinctions:
|
||||
|
||||
- `services` are `Context.Service` / `Context.Reference` exports and service contracts/shapes, `tags` are `Context.Tag` exports, and `layers` provide services.
|
||||
- `getters` retrieve values/properties, while `accessors` are contextual service or environment access helpers.
|
||||
- `errors` are error data types, while `error handling` is for APIs that handle failures.
|
||||
- `models` describe domain/API data structures, while `schemas` are schema values/combinators and `utility types` are type-level helpers/contracts.
|
||||
- `guards` are TypeScript type guards, `predicates` are boolean tests, and `filtering` is for filtering operations.
|
||||
44
repos/effect/.patterns/testing.md
Normal file
44
repos/effect/.patterns/testing.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Testing Patterns
|
||||
|
||||
## Testing Framework Selection
|
||||
|
||||
Use `it.effect` for tests that return Effects.
|
||||
|
||||
```typescript
|
||||
import { assert, describe, it } from "@effect/vitest"
|
||||
import { Effect } from "effect"
|
||||
|
||||
it.effect("should work with Effects", () =>
|
||||
Effect.gen(function*() {
|
||||
const result = yield* someEffect
|
||||
assert.strictEqual(result, expectedValue)
|
||||
}))
|
||||
```
|
||||
|
||||
Use regular `it` for pure synchronous TypeScript functions.
|
||||
|
||||
```typescript
|
||||
import { assert, describe, it } from "@effect/vitest"
|
||||
|
||||
it("should work with pure functions", () => {
|
||||
const result = pureFunction(input)
|
||||
assert.strictEqual(result, expectedValue)
|
||||
})
|
||||
```
|
||||
|
||||
## Testing Rules
|
||||
|
||||
- Never use `Effect.runSync` in tests
|
||||
- Never use `expect` from Vitest; use `assert` methods instead
|
||||
- Always use `TestClock` for time-dependent operations
|
||||
- Group related tests using `describe`
|
||||
|
||||
## Type-Level Tests
|
||||
|
||||
Type-level tests are located in `packages/*/typetest/` and use Tstyche.
|
||||
|
||||
Run targeted type-level tests with:
|
||||
|
||||
```sh
|
||||
pnpm test-types <filename>
|
||||
```
|
||||
Reference in New Issue
Block a user