74 lines
4.9 KiB
Markdown
74 lines
4.9 KiB
Markdown
<!-- markdownlint-disable MD024 -->
|
|
|
|
# Spec Delta — react-ui-i18n deferred tooling
|
|
|
|
## ADDED Requirements
|
|
|
|
### Requirement: Stories ship for every i18n primitive
|
|
|
|
Every primitive added by the `react-ui-i18n` capability SHALL ship a sibling `.stories.tsx` alongside its implementation. Each story file SHALL contain a `default` export plus a `playground` and at least one variants story (the chassis-wide stories convention). Stories SHALL render inside `<TranslationProvider>` + `<RegistryProvider>` + `<ReactUiI18nBridge>` so the rendered surface matches production-runtime composition. Story-snapshot tests SHALL run as part of the package's test suite.
|
|
|
|
The covered surfaces are: `<FormattedNumber>`, `<FormattedCurrency>`, `<FormattedDate>`, `<FormattedList>`, `<FormattedRelativeTime>`, `<Plural>`, `<FormattedMessage>`, `<ReactUiI18nBridge>`, `formattedCell`, `useValidationMessageBridge`, and `<InputNumber>`.
|
|
|
|
**Verified by:** per-feature story-snapshot tests (one `*.stories.test.tsx` per primitive) plus a presence check in `scripts/check-i18n-stories.test.ts` (or equivalent).
|
|
|
|
#### Scenario: every i18n primitive has a `.stories.tsx` sibling
|
|
|
|
- GIVEN the directory `src/i18n/<primitive>/`
|
|
- WHEN the chassis `*.stories.tsx` walker runs
|
|
- THEN every public primitive listed in the capability spec has a matching `<primitive>.stories.tsx` file
|
|
|
|
### Requirement: bun run check:i18n-keys catches translation-key drift
|
|
|
|
The package SHALL ship `scripts/check-i18n-keys.ts` invoked via `bun run check:i18n-keys`. The script SHALL AST-walk every `*.{ts,tsx}` under `src/components/**` and `src/i18n/**` looking for translation-key references — `t("react-ui.…")`, `tDynamic("react-ui.…")`, `<FormattedMessage i18nKey="react-ui.…" />`, `<Trans i18nKey="react-ui.…" />` — and SHALL diff the discovered key set against `src/locales/en-GB.json`. The script SHALL exit non-zero when any key is referenced in code but absent from the bundle (`MISSING`) or present in the bundle but referenced nowhere in code (`ORPHAN`). The script SHALL be wired into `bunx turbo lint` so CI fails on drift.
|
|
|
|
**Verified by:** `scripts/check-i18n-keys.test.ts` — fixture directory exercising the missing, orphan, and clean paths.
|
|
|
|
#### Scenario: missing key in code fails the gate
|
|
|
|
- GIVEN a source file referencing `t("react-ui.foo.absent")` and `en-GB.json` lacking that key
|
|
- WHEN `bun run check:i18n-keys` runs
|
|
- THEN the script exits non-zero and prints `MISSING: react-ui.foo.absent` with the source path
|
|
|
|
#### Scenario: orphan key in bundle fails the gate
|
|
|
|
- GIVEN `en-GB.json` containing `react-ui.foo.unused` and no source reference
|
|
- WHEN `bun run check:i18n-keys` runs
|
|
- THEN the script exits non-zero and prints `ORPHAN: react-ui.foo.unused`
|
|
|
|
#### Scenario: clean source + bundle pair passes
|
|
|
|
- GIVEN every key in `en-GB.json` is referenced in code AND every code-referenced key is in the bundle
|
|
- WHEN `bun run check:i18n-keys` runs
|
|
- THEN the script exits zero with no diagnostics
|
|
|
|
### Requirement: bun run check:registry-eject verifies shadcn ejection
|
|
|
|
The package SHALL ship `scripts/check-registry-eject.ts` invoked via `bun run check:registry-eject`. For every `registry/r/<name>.json` entry the script SHALL:
|
|
|
|
1. Resolve the listed source files.
|
|
2. Apply the registry transform (rewriting `@suaveplan/react-ui` imports to local relative paths, preserving `@suaveplan/react-i18n` imports).
|
|
3. Run `tsc --noEmit` against the transformed tree using a synthesized consumer `tsconfig.json` that declares `@suaveplan/react-i18n` and React peers via `compilerOptions.paths`.
|
|
|
|
The script SHALL exit non-zero when any registry entry's transformed source fails to type-check, surfacing the underlying tsc diagnostics with the entry name as context. The script SHALL also detect missing registry entries — public components / primitives in `src/components/**` and `src/i18n/**` lacking a corresponding `registry/r/<name>.json` SHALL trigger a `MISSING REGISTRY ENTRY` diagnostic. The script SHALL be wired into `bunx turbo lint`.
|
|
|
|
**Verified by:** `scripts/check-registry-eject.test.ts` — fixture-driven happy-path + failure-path tests.
|
|
|
|
#### Scenario: ejected primitive type-checks against react-i18n
|
|
|
|
- GIVEN the registry entry `formatted-number.json`
|
|
- WHEN the transform is applied to its files and the result is type-checked
|
|
- THEN `tsc --noEmit` exits 0 and the import `import { useFormatter } from "@suaveplan/react-i18n"` resolves
|
|
|
|
#### Scenario: missing registry entry for a public primitive fails the gate
|
|
|
|
- GIVEN a public primitive at `src/i18n/<new>/<new>.tsx` with no corresponding `registry/r/<new>.json`
|
|
- WHEN `bun run check:registry-eject` runs
|
|
- THEN the script exits non-zero with `MISSING REGISTRY ENTRY: src/i18n/<new>/<new>.tsx`
|
|
|
|
#### Scenario: corrupted transform output fails the gate
|
|
|
|
- GIVEN a registry entry whose source references a symbol the transform fails to rewrite correctly
|
|
- WHEN the transformed source is type-checked
|
|
- THEN the script exits non-zero with `EJECT FAILURE: <name>` and the underlying tsc diagnostics
|