first commit
This commit is contained in:
83
docs/gaming/games/ecs/src/errors/ecs-error.md
Normal file
83
docs/gaming/games/ecs/src/errors/ecs-error.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# EcsError & ECS_CODES
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`EcsError` is the typed error class for every failure mode raised by `@suaveplan/ecs`. It extends `SuaveplanError` from `@suaveplan/error`, which means every thrown error carries a stable, fully-qualified `code` string and a structured `context` object documenting the inputs at the failure site. Callers can discriminate failures from this package either by `instanceof EcsError` or by inspecting `error.code`.
|
||||
|
||||
`ECS_CODES` is the canonical registry of every code this package raises. The registry is generated through `defineCodes("ECS", [...])` from `@suaveplan/error`, which fully-qualifies the string literals (e.g., `"ECS.ENTITY_NOT_ALIVE"`) and exposes them as a frozen object.
|
||||
|
||||
## Features
|
||||
|
||||
- Stable, fully-qualified codes — `ECS.ENTITY_NOT_ALIVE`, `ECS.COMPONENT_NOT_REGISTERED`, `ECS.COMPONENT_NAME_CONFLICT`, `ECS.COMPONENT_LIMIT_REACHED`, `ECS.COMPONENT_VALIDATION_FAILED`, `ECS.SYSTEM_NAME_CONFLICT`, `ECS.SNAPSHOT_INVALID`.
|
||||
- Every code is exercised by `src/errors/ecs-error.test.ts` from a real production code path — registry-to-throw-site coverage is a test invariant.
|
||||
- Structured `context` field on every error (`{ entity }`, `{ name }`, `{ issues }`, etc.) so the wire-redacted error envelope remains useful for debugging.
|
||||
- Cause chain preserved through `SuaveplanError`'s base support.
|
||||
- Code type `EcsCode` is a literal union narrowable in `switch` statements.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { createWorld, defineComponent, ECS_CODES, EcsError } from "@suaveplan/ecs";
|
||||
|
||||
const Position = defineComponent("Position", { x: 0, y: 0 });
|
||||
const world = createWorld();
|
||||
const entity = world.spawn();
|
||||
world.despawn(entity);
|
||||
|
||||
try {
|
||||
world.addComponent(entity, Position);
|
||||
} catch (err) {
|
||||
if (err instanceof EcsError && err.code === ECS_CODES.ENTITY_NOT_ALIVE) {
|
||||
console.error("entity was already despawned");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { ECS_CODES, EcsError } from "@suaveplan/ecs";
|
||||
|
||||
function isRetryable(err: unknown): boolean {
|
||||
if (!(err instanceof EcsError)) return false;
|
||||
switch (err.code) {
|
||||
case ECS_CODES.ENTITY_NOT_ALIVE:
|
||||
case ECS_CODES.SNAPSHOT_INVALID:
|
||||
return false;
|
||||
case ECS_CODES.COMPONENT_VALIDATION_FAILED:
|
||||
return false;
|
||||
case ECS_CODES.COMPONENT_LIMIT_REACHED:
|
||||
case ECS_CODES.COMPONENT_NAME_CONFLICT:
|
||||
case ECS_CODES.COMPONENT_NOT_REGISTERED:
|
||||
case ECS_CODES.SYSTEM_NAME_CONFLICT:
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
| Symbol | Description |
|
||||
|---|---|
|
||||
| `EcsError` | `SuaveplanError`-extending class. Constructor: `new EcsError(code, messageKey, options?)`. |
|
||||
| `EcsCode` | Type union over every registered code string. |
|
||||
| `ECS_CODES` | Frozen registry returned by `defineCodes`. |
|
||||
| `ECS_CODES.ENTITY_NOT_ALIVE` | Thrown from `addComponent` / `removeComponent` / `setComponent` for despawned entities. |
|
||||
| `ECS_CODES.COMPONENT_NOT_REGISTERED` | `registry.getId(schema)` on an unknown schema. |
|
||||
| `ECS_CODES.COMPONENT_NAME_CONFLICT` | Two distinct schemas sharing a `name`. |
|
||||
| `ECS_CODES.COMPONENT_LIMIT_REACHED` | `register` past `maxComponents`. |
|
||||
| `ECS_CODES.COMPONENT_VALIDATION_FAILED` | Zod validator rejected merged component data. |
|
||||
| `ECS_CODES.SYSTEM_NAME_CONFLICT` | `addSystem` with a name already registered. |
|
||||
| `ECS_CODES.SNAPSHOT_INVALID` | `restore` payload failed `WorldSnapshotSchema`. |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- Codes are namespaced under `ECS.` so cross-package error log aggregation can filter by the `ECS.*` prefix.
|
||||
- `EcsError` does not override `Error.prototype.toJSON` — `SuaveplanError` already exposes `toWire` / `toSpanEvent` for serialisation, and we don't extend the contract.
|
||||
- The test suite enumerates `Object.values(ECS_CODES)` and triggers every code through a production call. If a new code is added without a real throw site, the test will fail — this is the registered-but-unthrown drift guard required by the spec-conformance checklist (`AGENTS.md` §13).
|
||||
Reference in New Issue
Block a user