diff --git a/.claude/skills/native-monad-option/SKILL.md b/.claude/skills/native-monad-option/SKILL.md new file mode 100644 index 0000000..0274553 --- /dev/null +++ b/.claude/skills/native-monad-option/SKILL.md @@ -0,0 +1,60 @@ +--- +name: native-monad-option +description: "Option API reference. ALWAYS invoke when using Some, None, Option, OptionPromise, Option.from, Option.all, Option.partition, option.map, option.flatMap, option.match(2 args), option.filter(NO errorFactory). Do not guess Option methods — consult this skill." +--- + +# Option Usage Guide + +## Quick Reference + +| Method | Signature (on Some) | Signature (on None) | +|-------------------------|--------------------------------|---------------------| +| `isSome()` | `this is Some` | `this is never` | +| `isNone()` | `this is never` | `this is None` | +| `map(fn)` | `(fn: (v: T) => U) => Some` | `() => None` | +| `flatMap(fn)` | `(fn: (v: T) => R) => R` | `() => this` | +| `match(onSome, onNone)` | 2 callbacks | 2 callbacks | +| `filter(pred)` | NO errorFactory | `() => None` | +| `toNullable()` | `T` | `null` | +| `toUndefined()` | `T` | `undefined` | +| `toString()` | `string` | `string` | + +## Critical Rules + +1. `match()` takes exactly **2 callbacks**: `(onSome, onNone)`. +2. `filter()` takes ONLY a predicate — NO `errorFactory` (unlike Result). +3. Option has **NO** `mapErr()` or `flatMapErr()` — those are Result/Query only. +4. `flatMap` constraint: `R extends Option` — callback must return an Option. +5. Type guard: after `isSome()`, access `.value`. None has no `.value`. +6. `none()` returns a frozen singleton — do not try to construct `new None()`. +7. `Option.from()` treats only `null | undefined` as None. `0`, `false`, `""` become `Some`. + +## Anti-Patterns + +```typescript +// WRONG — Option.filter does NOT take errorFactory +option.filter((v) => v > 0, () => new Error("bad")); + +// CORRECT — just a predicate +option.filter((v) => v > 0); +``` + +```typescript +// WRONG — mapErr does not exist on Option +option.mapErr((e) => new Error(e)); + +// CORRECT — Option has no error channel. Use Result if you need errors. +``` + +```typescript +// WRONG — fromNullable does not exist +Option.fromNullable(value); + +// CORRECT +Option.from(value); +``` + +## Namespace & Async Methods + +Read `references/api-surface.md` for the complete Option namespace (`.from`, `.all`, `.partition`, `.compact`, `.some`, +`.every`) and OptionPromise namespace. diff --git a/.claude/skills/native-monad-option/references/api-surface.md b/.claude/skills/native-monad-option/references/api-surface.md new file mode 100644 index 0000000..b21f179 --- /dev/null +++ b/.claude/skills/native-monad-option/references/api-surface.md @@ -0,0 +1,101 @@ +# Option API Surface + +These are ALL available methods for Option. Do not use any method not listed here. + +## Types + +```typescript +type Option = Some | None +type OptionPromise = Promise> +type SomePromise = Promise> +type NonePromise = Promise +type OptionPartitionResult = { values: T[]; noneCount: number } +type OptionFromType = /* conditional: Some> if T excludes null|undefined, else Option> */ +``` + +## Factory Functions + +```typescript +function some(value: T): Some +function none(): None // returns frozen singleton +``` + +## Some Instance Methods + +```typescript +class Some { + readonly value: T + + isSome(): this is Some + isNone(): this is never + + map(fn: (value: T) => U): Some + + flatMap>(fn: (value: T) => R): R + + match(onSome: (value: T) => U, onNone: () => U): U + + // Overload 1: type-narrowing predicate + filter(predicate: (value: T) => value is U): Option + // Overload 2: boolean predicate + filter(predicate: (value: T) => boolean): Option + + toNullable(): T + toUndefined(): T + toString(): string +} +``` + +## None Instance Methods + +```typescript +class None { + // None has no .value property + + isSome(): this is never + isNone(): this is None + + map(): None + + flatMap(): this + + match(onSome: (value: never) => U, onNone: () => U): U + + filter(): None + + toNullable(): null + toUndefined(): undefined + toString(): string +} +``` + +## NOT available on Option (Result/Query only) + +- `mapErr()` — does not exist +- `flatMapErr()` — does not exist + +## Option Namespace (Static Methods) + +```typescript +Option.from(value: T): OptionFromType +Option.from(fn: () => T): OptionFromType +Option.isOption(value: unknown): value is Option +Option.all(options: Some[]): Some +Option.all(options: Option[]): Option +Option.partition(options: Option[]): OptionPartitionResult +Option.compact(options: Option[]): T[] +Option.some(options: Option[]): boolean +Option.every(options: Option[]): boolean +``` + +## OptionPromise Namespace (Async Methods) + +```typescript +OptionPromise.from(fn: () => Promise): Promise> +OptionPromise.all(promises: Promise>[]): Promise> +OptionPromise.all(promises: Promise>[]): Promise> +OptionPromise.partition(promises: Promise>[]): Promise> +OptionPromise.compact(promises: Promise>[]): Promise +OptionPromise.some(promises: Promise>[]): Promise +OptionPromise.every(promises: Promise>[]): Promise +``` diff --git a/.claude/skills/native-monad-query/SKILL.md b/.claude/skills/native-monad-query/SKILL.md new file mode 100644 index 0000000..85dbd75 --- /dev/null +++ b/.claude/skills/native-monad-query/SKILL.md @@ -0,0 +1,60 @@ +--- +name: native-monad-query +description: "Query API reference. ALWAYS invoke when using OkSome, OkNone, ErrNone, Query, QueryPromise, Query.from, Query.all, Query.partition, query.match(3 args), query.filter(NO errorFactory). Do not guess Query methods — consult this skill." +--- + +# Query Usage Guide + +## Quick Reference + +Query is a three-state monad: success-with-value (`OkSome`), success-without-value (`OkNone`), error (`ErrNone`). + +| Method | OkSome | OkNone | ErrNone | +|--------|--------|--------|---------| +| `isSome()` | `this is OkSome` | `this is never` | `this is never` | +| `isNone()` | `this is never` | `this is OkNone` | `this is never` | +| `isErr()` | `this is never` | `this is never` | `this is ErrNone` | +| `map(fn)` | `(fn: (v: T) => U) => OkSome` | `() => OkNone` | `() => ErrNone` | +| `mapErr(fn)` | `() => OkSome` | `() => OkNone` | `(fn: (e: E) => F) => ErrNone` | +| `flatMap(fn)` | `(fn: (v: T) => R) => R` | `() => this` | `() => this` | +| `flatMapErr(fn)` | `() => this` | `() => this` | `(fn: (e: E) => R) => R` | +| `match(a, b, c)` | 3 callbacks | 3 callbacks | 3 callbacks | +| `filter(pred)` | NO errorFactory | `() => OkNone` | `() => ErrNone` | +| `toNullable()` | `T` | `null` | `null` | +| `toUndefined()` | `T` | `undefined` | `undefined` | + +## Critical Rules + +1. `match()` takes exactly **3 callbacks**: `(onSome, onNone, onErr)` — NOT 2. +2. `filter()` takes ONLY a predicate — NO `errorFactory` (unlike Result). Failed filter returns `OkNone`, not `ErrNone`. +3. `flatMap` constraint: `R extends Query` — callback must return a Query. +4. `flatMapErr` constraint: `R extends Query` — callback must return a Query. +5. Type guards: `isSome()` → `.value`, `isErr()` → `.err`. `OkNone` has neither. +6. `OkSome` stores `.value`. `ErrNone` stores `.err`. `OkNone` has no data properties. +7. `okNone()` returns a frozen singleton. + +## Anti-Patterns + +```typescript +// WRONG — match with 2 callbacks (that's Result/Option, not Query) +query.match(onSome, onErr); + +// CORRECT — Query.match always takes 3 +query.match( + (value) => handleValue(value), + () => handleEmpty(), + (error) => handleError(error), +); +``` + +```typescript +// WRONG — filter with errorFactory (that's Result, not Query) +query.filter((v) => v > 0, () => new Error("bad")); + +// CORRECT — Query.filter only takes predicate, returns OkNone on failure +query.filter((v) => v > 0); +``` + +## Namespace & Async Methods + +Read `references/api-surface.md` for the complete Query namespace (`.from`, `.all`, `.partition`, `.compact`, `.some`, `.every`) and QueryPromise namespace. diff --git a/.claude/skills/native-monad-query/references/api-surface.md b/.claude/skills/native-monad-query/references/api-surface.md new file mode 100644 index 0000000..92561e0 --- /dev/null +++ b/.claude/skills/native-monad-query/references/api-surface.md @@ -0,0 +1,130 @@ +# Query API Surface + +These are ALL available methods for Query. Do not use any method not listed here. + +## Types + +```typescript +type Query = OkSome | OkNone | ErrNone +type QueryPromise = Promise> +type OkSomePromise = Promise> +type OkNonePromise = Promise +type ErrNonePromise = Promise> +type QueryPartitionResult = { values: T[]; noneCount: number; errors: E[] } +type QueryFromType = /* conditional: OkSome> if T excludes null|undefined, else OkSome> | OkNone */ +``` + +## Factory Functions + +```typescript +function okSome(value: T): OkSome +function okNone(): OkNone // returns frozen singleton +function errNone(error: E): ErrNone +``` + +## OkSome Instance Methods + +```typescript +class OkSome { + readonly value: T + + isSome(): this is OkSome + isNone(): this is never + isErr(): this is never + + map(fn: (value: T) => U): OkSome + mapErr(): OkSome + + flatMap>(fn: (value: T) => R): R + flatMapErr(): this + + match(onSome: (value: T) => U, onNone: () => U, onErr: (error: never) => U): U + + // Overload 1: type-narrowing predicate + filter(predicate: (value: T) => value is U): OkSome | OkNone + // Overload 2: boolean predicate + filter(predicate: (value: T) => boolean): OkSome | OkNone + + toNullable(): T + toUndefined(): T + toString(): string +} +``` + +## OkNone Instance Methods + +```typescript +class OkNone { + // OkNone has no .value or .err property + + isSome(): this is never + isNone(): this is OkNone + isErr(): this is never + + map(): OkNone + mapErr(): OkNone + + flatMap(): this + flatMapErr(): this + + match(onSome: (value: never) => U, onNone: () => U, onErr: (error: never) => U): U + + filter(): OkNone + + toNullable(): null + toUndefined(): undefined + toString(): string +} +``` + +## ErrNone Instance Methods + +```typescript +class ErrNone { + readonly err: E + + isSome(): this is never + isNone(): this is never + isErr(): this is ErrNone + + map(): ErrNone + mapErr(fn: (error: E) => F): ErrNone + + flatMap(): this + flatMapErr>(fn: (error: E) => R): R + + match(onSome: (value: never) => U, onNone: () => U, onErr: (error: E) => U): U + + filter(): ErrNone + + toNullable(): null + toUndefined(): undefined + toString(): string +} +``` + +## Query Namespace (Static Methods) + +```typescript +Query.from(value: T): QueryFromType +Query.from(fn: () => T, errorMap?: (error: unknown) => E): QueryFromType | ErrNone +Query.isQuery(value: unknown): value is Query +Query.all(queries: OkSome[]): OkSome +Query.all(queries: Query[]): Query +Query.partition(queries: Query[]): QueryPartitionResult +Query.compact(queries: Query[]): T[] +Query.some(queries: Query[]): boolean +Query.every(queries: Query[]): boolean +``` + +## QueryPromise Namespace (Async Methods) + +```typescript +QueryPromise.from(fn: () => Promise, errorMap?: (error: unknown) => E): Promise | ErrNone> +QueryPromise.all(promises: Promise>[]): Promise> +QueryPromise.all(promises: Promise>[]): Promise> +QueryPromise.partition(promises: Promise>[]): Promise> +QueryPromise.compact(promises: Promise>[]): Promise +QueryPromise.some(promises: Promise>[]): Promise +QueryPromise.every(promises: Promise>[]): Promise +``` diff --git a/.claude/skills/native-monad-result/SKILL.md b/.claude/skills/native-monad-result/SKILL.md new file mode 100644 index 0000000..057f56c --- /dev/null +++ b/.claude/skills/native-monad-result/SKILL.md @@ -0,0 +1,54 @@ +--- +name: native-monad-result +description: "Result API reference. ALWAYS invoke when using Ok, Err, Result, ResultPromise, Result.from, Result.all, Result.partition, result.map, result.flatMap, result.match(2 args), result.filter(needs errorFactory). Do not guess Result methods — consult this skill." +--- + +# Result Usage Guide + +## Quick Reference + +| Method | Signature (on Ok) | Signature (on Err) | +|------------------------------|------------------------------|-------------------------------| +| `isOk()` | `this is Ok` | `this is never` | +| `isErr()` | `this is never` | `this is Err` | +| `map(fn)` | `(fn: (v: T) => U) => Ok` | `() => Err` | +| `mapErr(fn)` | `(fn: (e: E) => F) => Ok` | `(fn: (e: E) => F) => Err` | +| `flatMap(fn)` | `(fn: (v: T) => R) => R` | `() => this` | +| `flatMapErr(fn)` | `() => this` | `(fn: (e: E) => R) => R` | +| `match(onOk, onErr)` | 2 callbacks | 2 callbacks | +| `filter(pred, errorFactory)` | requires `errorFactory` | `() => Err` | +| `toNullable()` | `T` | `null` | +| `toUndefined()` | `T` | `undefined` | +| `toString()` | `string` | `string` | + +## Critical Rules + +1. `match()` takes exactly **2 callbacks**: `(onOk, onErr)`. +2. `filter()` REQUIRES an `errorFactory` parameter — it produces `Err` when the predicate fails. +3. `flatMap` constraint: `R extends Result` — the callback must return a Result. +4. `flatMapErr` constraint: `R extends Result` — the callback must return a Result. +5. Type guard: after `isOk()`, access `.value`. After `isErr()`, access `.err`. +6. `Ok` stores `.value`. `Err` stores `.err` (not `.error`, not `.value`). + +## Anti-Patterns + +```typescript +// WRONG — filter without errorFactory +result.filter((v) => v > 0); + +// CORRECT — filter always needs errorFactory +result.filter((v) => v > 0, (v) => new Error(`Invalid: ${v}`)); +``` + +```typescript +// WRONG — match with 3 callbacks (that's Query, not Result) +result.match(onOk, onNone, onErr); + +// CORRECT — Result.match takes exactly 2 +result.match(onOk, onErr); +``` + +## Namespace & Async Methods + +Read `references/api-surface.md` for the complete Result namespace (`.from`, `.all`, `.partition`, `.compact`, `.some`, +`.every`) and ResultPromise namespace. diff --git a/.claude/skills/native-monad-result/references/api-surface.md b/.claude/skills/native-monad-result/references/api-surface.md new file mode 100644 index 0000000..251aa65 --- /dev/null +++ b/.claude/skills/native-monad-result/references/api-surface.md @@ -0,0 +1,98 @@ +# Result API Surface + +These are ALL available methods for Result. Do not use any method not listed here. + +## Types + +```typescript +type Result = Ok | Err +type ResultPromise = Promise> +type OkPromise = Promise> +type ErrPromise = Promise> +type ResultPartitionResult = { values: T[]; errors: E[] } +``` + +## Factory Functions + +```typescript +function ok(value: T): Ok +function err(error: E): Err +``` + +## Ok Instance Methods + +```typescript +class Ok { + readonly value: T + + isOk(): this is Ok + isErr(): this is never + + map(fn: (value: T) => U): Ok + mapErr(fn: (error: never) => F): Ok + + flatMap>(fn: (value: T) => R): R + flatMapErr(): this + + match(onOk: (value: T) => U, onErr: (error: never) => U): U + + // Overload 1: type-narrowing predicate + filter(predicate: (value: T) => value is U, errorFactory: (value: T) => F): Ok | Err + // Overload 2: boolean predicate + filter(predicate: (value: T) => boolean, errorFactory: (value: T) => F): Ok | Err + + toNullable(): T + toUndefined(): T + toString(): string +} +``` + +## Err Instance Methods + +```typescript +class Err { + readonly err: E + + isOk(): this is never + isErr(): this is Err + + map(): Err + mapErr(fn: (error: E) => F): Err + + flatMap(): this + flatMapErr>(fn: (error: E) => R): R + + match(onOk: (value: never) => U, onErr: (error: E) => U): U + + filter(): Err + + toNullable(): null + toUndefined(): undefined + toString(): string +} +``` + +## Result Namespace (Static Methods) + +```typescript +Result.from(fn: () => T, errorMap?: (error: unknown) => E): Result +Result.isResult(value: unknown): value is Result +Result.all(results: Ok[]): Ok +Result.all(results: Result[]): Result +Result.partition(results: Result[]): ResultPartitionResult +Result.compact(results: Result[]): T[] +Result.some(results: Result[]): boolean +Result.every(results: Result[]): boolean +``` + +## ResultPromise Namespace (Async Methods) + +```typescript +ResultPromise.from(fn: () => Promise, errorMap?: (error: unknown) => E): ResultPromise +ResultPromise.all(promises: Promise>[]): Promise> +ResultPromise.all(promises: Promise>[]): Promise> +ResultPromise.partition(promises: Promise>[]): Promise> +ResultPromise.compact(promises: Promise>[]): Promise +ResultPromise.some(promises: Promise>[]): Promise +ResultPromise.every(promises: Promise>[]): Promise +``` diff --git a/.claude/skills/native-monad/SKILL.md b/.claude/skills/native-monad/SKILL.md new file mode 100644 index 0000000..f3bf45d --- /dev/null +++ b/.claude/skills/native-monad/SKILL.md @@ -0,0 +1,49 @@ +--- +name: native-monad +description: "@gs-ts/native-monad shared conventions. ALWAYS invoke when importing ok/err/some/none/okSome/okNone/errNone, using ResultPromise/OptionPromise/QueryPromise, or when tempted to write unwrap/orElse/fold/Promise. Do not write Promise> — use ResultPromise." +--- + +# "@gs-ts/native-monad — Shared Conventions + +## Sugar Types (MANDATORY) + +Never wrap monads in raw Promise. Use these sugar types: + +| Wrong | Correct | Import from | +|-------------------------|-----------------------|----------------| +| `Promise>` | `ResultPromise` | `native-monad` | +| `Promise>` | `OkPromise` | `native-monad` | +| `Promise>` | `ErrPromise` | `native-monad` | +| `Promise>` | `OptionPromise` | `native-monad` | +| `Promise>` | `SomePromise` | `native-monad` | +| `Promise` | `NonePromise` | `native-monad` | +| `Promise>` | `QueryPromise` | `native-monad` | +| `Promise>` | `OkSomePromise` | `native-monad` | +| `Promise` | `OkNonePromise` | `native-monad` | +| `Promise>` | `ErrNonePromise` | `native-monad` | + +## Factory Functions + +| Function | Returns | Notes | +|------------------|--------------|--------------------------| +| `ok(value)` | `Ok` | | +| `err(error)` | `Err` | | +| `some(value)` | `Some` | | +| `none()` | `None` | Returns frozen singleton | +| `okSome(value)` | `OkSome` | | +| `okNone()` | `OkNone` | Returns frozen singleton | +| `errNone(error)` | `ErrNone` | | + +## Critical Rules + +1. Use `match()` for value extraction — never invent `unwrap()` or `getOrElse()`. +2. Use `map()`/`flatMap()` for chaining — never invent `andThen()` or `chain()`. +3. Use sugar types for async return types — never write `Promise>`. +4. The three modules (Result, Option, Query) are independent — no cross-type conversions exist. +5. `Falsy` means only `null | undefined`. Values like `0`, `false`, `""` are NOT falsy. + +## Anti-Patterns + +Read `references/forbidden-patterns.md` for the exhaustive list of banned methods and wrong patterns. + +Read `references/type-mappings.md` for the full sugar type reference. diff --git a/.claude/skills/native-monad/references/forbidden-patterns.md b/.claude/skills/native-monad/references/forbidden-patterns.md new file mode 100644 index 0000000..78672e2 --- /dev/null +++ b/.claude/skills/native-monad/references/forbidden-patterns.md @@ -0,0 +1,74 @@ +# Forbidden Patterns + +## Banned Method Names + +These methods DO NOT EXIST in native-monad. Never suggest, generate, or reference them: + +`unwrap`, `unwrapOr`, `unwrapOrElse`, `expect`, `or`, `orElse`, `and`, `andThen`, +`inspect`, `getOrElse`, `fold`, `contains`, `zip`, `unzip`, `transpose`, `chain`, +`recover`, `tap`, `peek`, `bimap`, `cata`, `either`, `maybe`, `fromNullable`, +`tryCatch`, `encase`. + +## Anti-Pattern Examples + +### Value extraction + +```typescript +// WRONG — unwrap does not exist +const value = result.unwrap(); +const value = result.unwrapOr(defaultValue); +const value = result.expect("should be ok"); + +// CORRECT — use match() +const value = result.match( + (v) => v, + (e) => defaultValue, +); +``` + +### Chaining + +```typescript +// WRONG — orElse/andThen do not exist +const next = result.orElse((e) => ok(fallback)); +const next = result.andThen((v) => ok(v + 1)); + +// CORRECT — use flatMap/flatMapErr +const next = result.flatMapErr((e) => ok(fallback)); +const next = result.flatMap((v) => ok(v + 1)); +``` + +### Async return types + +```typescript +// WRONG — raw Promise wrapping +async function fetchUser(id: string): Promise> { ... } +async function findItem(id: string): Promise> { ... } +async function query(id: string): Promise> { ... } + +// CORRECT — sugar types +async function fetchUser(id: string): ResultPromise { ... } +async function findItem(id: string): OptionPromise { ... } +async function query(id: string): QueryPromise { ... } +``` + +### Side-effect inspection + +```typescript +// WRONG — inspect/tap do not exist +result.inspect((v) => console.log(v)); +option.tap((v) => log(v)); + +// CORRECT — use map with side effect + return, or match +const logged = result.map((v) => { console.log(v); return v; }); +``` + +### Nullability conversion + +```typescript +// WRONG — fromNullable does not exist +const opt = Option.fromNullable(maybeNull); + +// CORRECT — use Option.from() +const opt = Option.from(maybeNull); +``` diff --git a/.claude/skills/native-monad/references/type-mappings.md b/.claude/skills/native-monad/references/type-mappings.md new file mode 100644 index 0000000..d8fa34e --- /dev/null +++ b/.claude/skills/native-monad/references/type-mappings.md @@ -0,0 +1,36 @@ +# Type Mappings — Sugar Types + +All sugar types are simple type aliases. They exist to keep signatures clean. + +## Result Sugar Types + +| Sugar Type | Expands To | Use When | +|------------|-----------|----------| +| `ResultPromise` | `Promise>` | Async function returning Result | +| `OkPromise` | `Promise>` | Async function guaranteed to succeed | +| `ErrPromise` | `Promise>` | Async function guaranteed to fail | + +## Option Sugar Types + +| Sugar Type | Expands To | Use When | +|------------|-----------|----------| +| `OptionPromise` | `Promise>` | Async function returning Option | +| `SomePromise` | `Promise>` | Async function guaranteed to have value | +| `NonePromise` | `Promise` | Async function guaranteed to be empty | + +## Query Sugar Types + +| Sugar Type | Expands To | Use When | +|------------|-----------|----------| +| `QueryPromise` | `Promise>` | Async function returning Query | +| `OkSomePromise` | `Promise>` | Async function guaranteed to have value | +| `OkNonePromise` | `Promise` | Async function guaranteed empty-success | +| `ErrNonePromise` | `Promise>` | Async function guaranteed to error | + +## Partition Result Types + +| Type | Shape | Module | +|------|-------|--------| +| `ResultPartitionResult` | `{ values: T[]; errors: E[] }` | Result | +| `OptionPartitionResult` | `{ values: T[]; noneCount: number }` | Option | +| `QueryPartitionResult` | `{ values: T[]; noneCount: number; errors: E[] }` | Query | diff --git a/CLAUDE.md b/CLAUDE.md index f273500..6b5ab18 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,5 +1,9 @@ # CLAUDE.md +## native-monad API +NEVER write `Promise>` / `Promise>` / `Promise>` — use `ResultPromise` / `OptionPromise` / `QueryPromise`. +See `/native-monad-result`, `/native-monad-option`, `/native-monad-query` skills for complete API before writing monad code. + ## Build & Test Commands ```bash diff --git a/src/option/CLAUDE.md b/src/option/CLAUDE.md new file mode 100644 index 0000000..b23b61d --- /dev/null +++ b/src/option/CLAUDE.md @@ -0,0 +1,11 @@ +# Option conventions + +- `match()` takes **2 callbacks**: `(onSome, onNone)` +- `filter()` takes ONLY a predicate — **no errorFactory** (unlike Result) +- `mapErr()` and `flatMapErr()` do **NOT exist** on Option +- `none()` returns a frozen singleton +- `Option.from()` treats only `null | undefined` as None — `0`, `false`, `""` become `Some` +- `flatMap` callback must return `Option` +- Async return type: `OptionPromise` — never `Promise>` + +See `/native-monad-option` skill for full API reference. diff --git a/src/query/CLAUDE.md b/src/query/CLAUDE.md new file mode 100644 index 0000000..339e85d --- /dev/null +++ b/src/query/CLAUDE.md @@ -0,0 +1,11 @@ +# Query conventions + +- `match()` takes **3 callbacks**: `(onSome, onNone, onErr)` — NOT 2 +- `filter()` takes ONLY a predicate — **no errorFactory** (unlike Result). Returns `OkNone` on failure. +- Three states: `OkSome` (has `.value`), `OkNone` (no data), `ErrNone` (has `.err`) +- Has `mapErr()` and `flatMapErr()` (unlike Option) +- `okNone()` returns a frozen singleton +- `flatMap`/`flatMapErr` callbacks must return `Query` +- Async return type: `QueryPromise` — never `Promise>` + +See `/native-monad-query` skill for full API reference. diff --git a/src/result/CLAUDE.md b/src/result/CLAUDE.md new file mode 100644 index 0000000..67a3e5f --- /dev/null +++ b/src/result/CLAUDE.md @@ -0,0 +1,10 @@ +# Result conventions + +- `match()` takes **2 callbacks**: `(onOk, onErr)` +- `filter()` **requires errorFactory** — `filter(pred, errorFactory)` — unlike Option/Query +- `Ok` stores `.value`, `Err` stores `.err` (not `.error`) +- Has `mapErr()` and `flatMapErr()` (unlike Option) +- `flatMap`/`flatMapErr` callbacks must return `Result` +- Async return type: `ResultPromise` — never `Promise>` + +See `/native-monad-result` skill for full API reference.