69 lines
3.7 KiB
Markdown
69 lines
3.7 KiB
Markdown
# `registry.schemas`
|
|
|
|
## Purpose
|
|
|
|
Strict-object Zod schemas for every plugin kind accepted by `ReactI18nRegistry`. The schemas are the boundary at which a malformed plugin shape is rejected at registration time — before any callsite has a chance to consume the bad plugin and throw a less-actionable runtime error elsewhere. Each schema is `.strict()`-locked so extra fields on a plugin (typos, stale fields from an older registry version) trigger validation failure rather than silently passing through.
|
|
|
|
## Features
|
|
|
|
- One schema per plugin kind — `DetectorPluginSchema`, `FormatterPluginSchema`, `PostProcessorPluginSchema`, `LocaleAdapterPluginSchema`.
|
|
- Non-empty id enforced (`z.string().min(1)`) so every plugin has a stable lookup key.
|
|
- Function-shape fields validated structurally; their semantic correctness is exercised by the tests of each consumer (e.g. `useFormatter` test calls the registered plugin's `format` and asserts the output).
|
|
- Schemas surface failure as a Zod `ZodError`, which the registry wraps in a `ReactI18nError(REACT_I18N.PLUGIN_INVALID)` with the issues attached to `cause`.
|
|
|
|
## Usage: Basic Example
|
|
|
|
```ts
|
|
import { FormatterPluginSchema } from "@suaveplan/react-i18n/registry";
|
|
|
|
const result = FormatterPluginSchema.safeParse({
|
|
id: "duration",
|
|
format: (locale, args) => String(args.ms),
|
|
});
|
|
|
|
result.success; // true
|
|
```
|
|
|
|
## Usage: Advanced Example
|
|
|
|
The schemas accept generic `format` / `process` / `resolve` / `detect` functions because their signatures cannot be expressed as a closed Zod shape. The schema verifies the function is *present* and is a function; the actual `(locale, args) => result` contract is enforced at the type-system level via `FormatterPlugin<TArgs, TResult>` and at the test level by exercising the plugin's behavior.
|
|
|
|
```ts
|
|
import { DetectorPluginSchema } from "@suaveplan/react-i18n/registry";
|
|
|
|
const malformed = {
|
|
id: "ab",
|
|
priority: 0,
|
|
detect: { name: "ab" /* missing environment */ },
|
|
};
|
|
|
|
const result = DetectorPluginSchema.safeParse(malformed);
|
|
result.success; // false
|
|
result.error.issues; // [{ path: ["detect", "environment"], message: "Required" }]
|
|
```
|
|
|
|
## API Reference
|
|
|
|
### `DetectorPluginSchema`
|
|
|
|
Validates `{ id: string; priority: number; detect: { name; environment; detect?; detectAsync?; cache? } }`. The inner `detect` object is `passthrough` because `LocaleDetector` from `@suaveplan/i18n-detector` may carry forward-compatible fields the registry does not own.
|
|
|
|
### `FormatterPluginSchema`
|
|
|
|
Validates `{ id: string; schema?: unknown; defaultOptions?: unknown; format: function }`. The `schema` field is opaque (`z.unknown()`) because it is a Zod schema reference and Zod cannot meaningfully validate "is this a Zod schema."
|
|
|
|
### `PostProcessorPluginSchema`
|
|
|
|
Validates `{ id: string; priority: number; process: function }`.
|
|
|
|
### `LocaleAdapterPluginSchema`
|
|
|
|
Validates `{ id: string; resolve: function }`.
|
|
|
|
## Implementation Notes
|
|
|
|
- All schemas are `.strict()` — extra keys cause validation failure. This catches stale fields from older registry versions and typos in plugin objects.
|
|
- The schemas are exported from a single file rather than co-located with their plugin types so a consumer importing `@suaveplan/react-i18n/registry` for runtime validation does not pay the bundle cost of the plugin function code.
|
|
- Validation errors are passed through to the registry which decorates them with stable error codes; consumers should never `safeParse` directly against these schemas — register through `ReactI18nRegistry.register*` to get the decorated error.
|
|
- The schemas live in this package rather than in `@suaveplan/types` because they validate React-specific plugin shapes; the `ReactI18nRegistry` is itself React-bound (consumed via context).
|