React wrapper-layer codegen — restore the idioms over the kernel
The harness was written against the MIZAN.md oracle (<MizanContext>,
provider-per-context, useMizan, etc.) but the codegen had been narrowed
to just hooks-direct-on-kernel after the kernel split. Restoring the
React-idiomatic layer on top of the kernel.
backends/mizan-django/generate/generator/lib/adapters/react.mjs:
- Emits <MizanContext baseUrl="…"> root provider that calls configure()
once and (if a global context is registered) wraps children in
<GlobalContextProvider>.
- Emits <GlobalContextProvider> + <{Name}Context> per named context —
kernel registration happens once per provider mount, not per hook
call. Consumers read from React Context.
- Base hooks: useGlobalContext() / use{Name}Context() return full
ContextState<T> (data + status + error).
- Convenience hooks per context-function (use{Fn}() returns data | null)
and per regular function/mutation (use{Fn}() returns
{ mutate, isPending, error }).
- useMizan() returns { call, fetch } as an imperative escape hatch
for test harnesses or rare cases where typed hooks don't fit.
- Re-exports MizanError, configure, initSession, ContextState from
@mizan/base.
backends/mizan-django/generate/generator/cli.mjs:
- After Stage 2, appends `export * from './<adapter>'` to index.ts so
`import { useEcho, MizanContext } from './api'` works as a barrel.
Bug fixes surfaced during integration:
- react.mjs was generating `from '../index'` (wrong path); flat layout
needs `./index`.
- harness django.config.mjs had `output: 'src/api/generated.ts'` which
the codegen treated as a directory; corrected to `output: 'src/api'`.
- example testapp/clients.py imported from the deleted
mizan.setup.registry path; routed through mizan.setup aggregator.
harness/package.json: adds @mizan/base dep so the generated react.tsx
can resolve its kernel imports.
harness/src/fixtures.tsx:
- DjangoError → MizanError (kernel error class, backend-agnostic).
- useChatChannel sourced from ./api/channels.hooks directly (not
re-exported from the unified index for now).
- Form fixtures removed — forms codegen deferred per Blazr scope.
Verified: harness `vite build` succeeds, 53 modules transformed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -23,11 +23,10 @@ import {
|
||||
useBuggyFn,
|
||||
usePermissionCheckFn,
|
||||
useCurrentUser,
|
||||
DjangoError,
|
||||
MizanError,
|
||||
useMizan,
|
||||
useChatChannel,
|
||||
} from './api'
|
||||
import { useContactForm, useLoginForm } from './api/generated.forms'
|
||||
import { useChatChannel } from './api/channels.hooks'
|
||||
|
||||
// ─── Fixture router ─────────────────────────────────────────────────────────
|
||||
|
||||
@@ -55,9 +54,7 @@ export function Fixtures() {
|
||||
case 'permission-error': return <PermissionError_ />
|
||||
case 'permission-success': return <PermissionSuccess />
|
||||
case 'context-current-user': return <ContextCurrentUser />
|
||||
case 'form-login-schema': return <FormLoginSchema />
|
||||
case 'form-contact-schema': return <FormContactSchema />
|
||||
case 'form-contact-submit': return <FormContactSubmit />
|
||||
// Form fixtures removed — forms codegen deferred per Blazr scope
|
||||
case 'channel-chat': return <ChannelChatFixture />
|
||||
default: return <div data-testid="ready">Harness ready. Set #hash.</div>
|
||||
}
|
||||
@@ -74,10 +71,10 @@ function Result({ data, error }: { data?: unknown; error?: unknown }) {
|
||||
{error !== undefined && error !== null && (
|
||||
<>
|
||||
<div data-testid="error-type">
|
||||
{error instanceof DjangoError ? 'DjangoError' : 'Error'}
|
||||
{error instanceof MizanError ? 'MizanError' : 'Error'}
|
||||
</div>
|
||||
<div data-testid="error-code">
|
||||
{error instanceof DjangoError ? error.code : ''}
|
||||
{error instanceof MizanError ? error.code : ''}
|
||||
</div>
|
||||
<pre data-testid="error-message">
|
||||
{error instanceof Error ? error.message : String(error)}
|
||||
@@ -187,44 +184,6 @@ function ContextCurrentUser() {
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Form fixtures (using generated form hooks) ─────────────────────────────
|
||||
|
||||
function FormLoginSchema() {
|
||||
const form = useLoginForm()
|
||||
if (form.loading) return <div>loading...</div>
|
||||
return <pre data-testid="result">{JSON.stringify(form.schema)}</pre>
|
||||
}
|
||||
|
||||
function FormContactSchema() {
|
||||
const form = useContactForm()
|
||||
if (form.loading) return <div>loading...</div>
|
||||
return <pre data-testid="result">{JSON.stringify(form.schema)}</pre>
|
||||
}
|
||||
|
||||
function FormContactSubmit() {
|
||||
const form = useContactForm()
|
||||
const [result, setResult] = useState<unknown>()
|
||||
const [submitted, setSubmitted] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (!form.loading && !submitted) {
|
||||
form.set('name', 'Test User')
|
||||
form.set('email', 'test@example.com')
|
||||
form.set('message', 'Hello from e2e')
|
||||
setSubmitted(true)
|
||||
}
|
||||
}, [form.loading, submitted, form])
|
||||
|
||||
useEffect(() => {
|
||||
if (submitted && !result) {
|
||||
form.submit().then(setResult)
|
||||
}
|
||||
}, [submitted, result, form])
|
||||
|
||||
if (!result) return <div>loading...</div>
|
||||
return <pre data-testid="result">{JSON.stringify(result)}</pre>
|
||||
}
|
||||
|
||||
// ─── Channel fixtures ───────────────────────────────────────────────────────
|
||||
|
||||
function ChannelChatFixture() {
|
||||
|
||||
Reference in New Issue
Block a user