Initial Commit
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
# error-codes
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The `@suaveplan/font-decompress` package centralises every failure mode it
|
||||
can produce behind a single registry built with
|
||||
`defineCodes("FONT_DECOMPRESS", [...])` from `@suaveplan/error`. The
|
||||
registry is the stable contract callers depend on: code strings are
|
||||
documented, frozen at module load, and never renamed without an
|
||||
explicit migration. This module exports the `FONT_DECOMPRESS_CODES`
|
||||
registry, the derived `FontDecompressErrorCode` literal-union type,
|
||||
and the `FontDecompressError` class that every public failure path
|
||||
raises.
|
||||
|
||||
`FontDecompressError` extends `SuaveplanError<FontDecompressErrorCode>`
|
||||
so `instanceof FontDecompressError` narrows `code` to the union of
|
||||
`FONT_DECOMPRESS.*` strings. The class threads `cause` straight
|
||||
through `SuaveplanError`, so primitive-layer exceptions
|
||||
(`RangeError` from `DataView`, `TypeError` from `TextDecoder`,
|
||||
`@suaveplan/font-convert` errors) remain inspectable through
|
||||
`error.cause`.
|
||||
|
||||
## Features
|
||||
|
||||
- Frozen `FONT_DECOMPRESS_CODES` registry with two namespaced codes
|
||||
- `FontDecompressErrorCode` literal-union type derived from the registry
|
||||
- `FontDecompressError` class extending `SuaveplanError<FontDecompressErrorCode>`
|
||||
- Full `cause`-chain preservation via `SuaveplanError`
|
||||
- Distinct from `FONT_COMPRESS.*` codes — different namespace, different class
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import {
|
||||
FONT_DECOMPRESS_CODES,
|
||||
FontDecompressError,
|
||||
} from "@suaveplan/font-decompress";
|
||||
|
||||
if (data.byteLength < 1) {
|
||||
throw new FontDecompressError(
|
||||
FONT_DECOMPRESS_CODES.INVALID_DATA,
|
||||
"BTF buffer is empty",
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
FONT_DECOMPRESS_CODES,
|
||||
FontDecompressError,
|
||||
} from "@suaveplan/font-decompress";
|
||||
|
||||
try {
|
||||
const font = unpacker.unpack(buffer);
|
||||
} catch (err) {
|
||||
if (err instanceof FontDecompressError) {
|
||||
if (err.code === FONT_DECOMPRESS_CODES.UNPACK_FAILED) {
|
||||
telemetry.increment("font.unpack.failure", {
|
||||
root: err.cause instanceof Error ? err.cause.name : "unknown",
|
||||
});
|
||||
}
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `FONT_DECOMPRESS_CODES`
|
||||
|
||||
A frozen object literal of two namespaced codes:
|
||||
|
||||
| Property | Value |
|
||||
| --------------- | -------------------------------- |
|
||||
| `UNPACK_FAILED` | `"FONT_DECOMPRESS.UNPACK_FAILED"` |
|
||||
| `INVALID_DATA` | `"FONT_DECOMPRESS.INVALID_DATA"` |
|
||||
|
||||
### `type FontDecompressErrorCode`
|
||||
|
||||
The literal union of every value in `FONT_DECOMPRESS_CODES`.
|
||||
|
||||
### `class FontDecompressError extends SuaveplanError<FontDecompressErrorCode>`
|
||||
|
||||
| Member | Type |
|
||||
| ------------------ | ---------------------------------------------------------- |
|
||||
| `code` | `FontDecompressErrorCode` (narrowed) |
|
||||
| `cause?` | `unknown` (inherited) |
|
||||
| `timestamp` | `number` (inherited; `Date.now()` at construction) |
|
||||
| `constructor(...)` | `(code, message, options?: SuaveplanErrorOptions)` |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`defineCodes` returns a `Object.freeze`d record with `null` prototype,
|
||||
so the registry cannot be mutated, reassigned, or extended at runtime.
|
||||
The literal-type machinery preserves the exact `${Namespace}.${Reason}`
|
||||
string template across every consumer, so `switch (err.code)` enjoys
|
||||
exhaustive narrowing without runtime cost.
|
||||
|
||||
The class's constructor passes `message` through to `SuaveplanError`'s
|
||||
`messageKey` parameter. The base class resolves the key via the i18n
|
||||
resolver if one has been registered with `setMessageResolver`, falling
|
||||
back to the raw string otherwise — so this package works without i18n
|
||||
wiring and lights up automatically when `@suaveplan/i18n` is present.
|
||||
|
||||
The split from `@suaveplan/font-compress` preserves namespace
|
||||
distinctness: an `INVALID_DATA` raised by the packer is
|
||||
`FONT_COMPRESS.INVALID_DATA`; an `INVALID_DATA` raised by the unpacker
|
||||
is `FONT_DECOMPRESS.INVALID_DATA`. Consumers dispatching on either
|
||||
class plus its code get fully unambiguous error handling.
|
||||
Reference in New Issue
Block a user