schemock 0.0.4-alpha.7 → 0.0.4-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -0
- package/dist/cli/index.js +124 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +124 -3
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli.js +132 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1148,6 +1148,56 @@ const user = await api.user.get('123');
|
|
|
1148
1148
|
await api.post.create({ title: 'Hello', authorId: '123' });
|
|
1149
1149
|
```
|
|
1150
1150
|
|
|
1151
|
+
### Using with React Hooks (SchemockProvider)
|
|
1152
|
+
|
|
1153
|
+
To use the configured client with generated React hooks, wrap your app with `SchemockProvider`:
|
|
1154
|
+
|
|
1155
|
+
```tsx
|
|
1156
|
+
import { SchemockProvider, createClient, useUsers, useCreateUser } from './generated';
|
|
1157
|
+
|
|
1158
|
+
// 1. Create configured client
|
|
1159
|
+
const api = createClient({
|
|
1160
|
+
onRequest: (ctx) => {
|
|
1161
|
+
const token = localStorage.getItem('authToken');
|
|
1162
|
+
if (token) {
|
|
1163
|
+
ctx.headers.Authorization = `Bearer ${token}`;
|
|
1164
|
+
}
|
|
1165
|
+
return ctx;
|
|
1166
|
+
},
|
|
1167
|
+
onError: (error) => {
|
|
1168
|
+
if (error.status === 401) window.location.href = '/login';
|
|
1169
|
+
}
|
|
1170
|
+
});
|
|
1171
|
+
|
|
1172
|
+
// 2. Wrap your app
|
|
1173
|
+
function App() {
|
|
1174
|
+
return (
|
|
1175
|
+
<SchemockProvider client={api}>
|
|
1176
|
+
<UserList />
|
|
1177
|
+
</SchemockProvider>
|
|
1178
|
+
);
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
// 3. Hooks automatically use the configured client
|
|
1182
|
+
function UserList() {
|
|
1183
|
+
const { data, isLoading } = useUsers();
|
|
1184
|
+
const createUser = useCreateUser();
|
|
1185
|
+
|
|
1186
|
+
if (isLoading) return <div>Loading...</div>;
|
|
1187
|
+
|
|
1188
|
+
return (
|
|
1189
|
+
<div>
|
|
1190
|
+
{data?.data.map(user => <div key={user.id}>{user.name}</div>)}
|
|
1191
|
+
<button onClick={() => createUser.mutate({ name: 'New User' })}>
|
|
1192
|
+
Add User
|
|
1193
|
+
</button>
|
|
1194
|
+
</div>
|
|
1195
|
+
);
|
|
1196
|
+
}
|
|
1197
|
+
```
|
|
1198
|
+
|
|
1199
|
+
Without `SchemockProvider`, hooks use the default unconfigured client (no auth).
|
|
1200
|
+
|
|
1151
1201
|
### Creating Mock JWT Tokens
|
|
1152
1202
|
|
|
1153
1203
|
For testing different user contexts:
|
package/dist/cli/index.js
CHANGED
|
@@ -4285,7 +4285,7 @@ function generateHooks(schemas) {
|
|
|
4285
4285
|
code.comment("GENERATED BY SCHEMOCK - DO NOT EDIT");
|
|
4286
4286
|
code.line("import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';");
|
|
4287
4287
|
code.line("import { useMemo } from 'react';");
|
|
4288
|
-
code.line("import {
|
|
4288
|
+
code.line("import { useSchemockClient } from './provider';");
|
|
4289
4289
|
code.line("import type * as Types from './types';");
|
|
4290
4290
|
code.line();
|
|
4291
4291
|
generateStableKeyHelper(code);
|
|
@@ -4362,6 +4362,7 @@ function generateEntityHooks(code, schema) {
|
|
|
4362
4362
|
code.line("enabled?: boolean;");
|
|
4363
4363
|
}, "}) {");
|
|
4364
4364
|
code.indent();
|
|
4365
|
+
code.line("const api = useSchemockClient();");
|
|
4365
4366
|
code.comment("Use stable query key to prevent unnecessary refetches");
|
|
4366
4367
|
code.line(`const queryKey = useStableQueryKey('${pluralName}', options);`);
|
|
4367
4368
|
code.block("return useQuery({", () => {
|
|
@@ -4380,6 +4381,7 @@ function generateEntityHooks(code, schema) {
|
|
|
4380
4381
|
code.line("enabled?: boolean;");
|
|
4381
4382
|
}, "}) {");
|
|
4382
4383
|
code.indent();
|
|
4384
|
+
code.line("const api = useSchemockClient();");
|
|
4383
4385
|
if (hasRelations) {
|
|
4384
4386
|
code.comment("Use stable query key for includes array");
|
|
4385
4387
|
code.line(`const queryKey = useStableQueryKey('${pluralName}', id, options?.include);`);
|
|
@@ -4407,6 +4409,7 @@ function generateEntityHooks(code, schema) {
|
|
|
4407
4409
|
}
|
|
4408
4410
|
code.docComment(`Create a new ${pascalName}`);
|
|
4409
4411
|
code.block(`export function useCreate${pascalName}() {`, () => {
|
|
4412
|
+
code.line("const api = useSchemockClient();");
|
|
4410
4413
|
code.line("const queryClient = useQueryClient();");
|
|
4411
4414
|
code.block("return useMutation({", () => {
|
|
4412
4415
|
code.line(`mutationFn: (data: Types.${pascalName}Create) => api.${name}.create(data),`);
|
|
@@ -4418,6 +4421,7 @@ function generateEntityHooks(code, schema) {
|
|
|
4418
4421
|
code.line();
|
|
4419
4422
|
code.docComment(`Update an existing ${pascalName}`);
|
|
4420
4423
|
code.block(`export function useUpdate${pascalName}() {`, () => {
|
|
4424
|
+
code.line("const api = useSchemockClient();");
|
|
4421
4425
|
code.line("const queryClient = useQueryClient();");
|
|
4422
4426
|
code.block("return useMutation({", () => {
|
|
4423
4427
|
code.line(`mutationFn: ({ id, data }: { id: string; data: Types.${pascalName}Update }) =>`);
|
|
@@ -4431,6 +4435,7 @@ function generateEntityHooks(code, schema) {
|
|
|
4431
4435
|
code.line();
|
|
4432
4436
|
code.docComment(`Delete a ${pascalName}`);
|
|
4433
4437
|
code.block(`export function useDelete${pascalName}() {`, () => {
|
|
4438
|
+
code.line("const api = useSchemockClient();");
|
|
4434
4439
|
code.line("const queryClient = useQueryClient();");
|
|
4435
4440
|
code.block("return useMutation({", () => {
|
|
4436
4441
|
code.line(`mutationFn: (id: string) => api.${name}.delete(id),`);
|
|
@@ -4442,6 +4447,113 @@ function generateEntityHooks(code, schema) {
|
|
|
4442
4447
|
code.line();
|
|
4443
4448
|
}
|
|
4444
4449
|
|
|
4450
|
+
// src/cli/generators/provider.ts
|
|
4451
|
+
function generateProvider() {
|
|
4452
|
+
const code = new CodeBuilder();
|
|
4453
|
+
code.comment("GENERATED BY SCHEMOCK - DO NOT EDIT");
|
|
4454
|
+
code.line("import { createContext, useContext, type ReactNode } from 'react';");
|
|
4455
|
+
code.line("import { type ApiClient, api as defaultApi } from './client';");
|
|
4456
|
+
code.line();
|
|
4457
|
+
code.multiDocComment([
|
|
4458
|
+
"React Context for the Schemock API client.",
|
|
4459
|
+
"",
|
|
4460
|
+
"This context provides the API client to all hooks in the component tree.",
|
|
4461
|
+
"By default, it uses the unconfigured `api` client."
|
|
4462
|
+
]);
|
|
4463
|
+
code.line("const SchemockContext = createContext<ApiClient>(defaultApi);");
|
|
4464
|
+
code.line();
|
|
4465
|
+
code.multiDocComment([
|
|
4466
|
+
"Props for the SchemockProvider component."
|
|
4467
|
+
]);
|
|
4468
|
+
code.block("export interface SchemockProviderProps {", () => {
|
|
4469
|
+
code.docComment("Optional configured API client. If not provided, uses the default unconfigured client.");
|
|
4470
|
+
code.line("client?: ApiClient;");
|
|
4471
|
+
code.docComment("Child components that will have access to the API client.");
|
|
4472
|
+
code.line("children: ReactNode;");
|
|
4473
|
+
});
|
|
4474
|
+
code.line();
|
|
4475
|
+
code.multiDocComment([
|
|
4476
|
+
"Provider component for injecting a configured API client into hooks.",
|
|
4477
|
+
"",
|
|
4478
|
+
"Use this to provide an auth-configured client to all Schemock hooks.",
|
|
4479
|
+
"",
|
|
4480
|
+
"@example",
|
|
4481
|
+
"```tsx",
|
|
4482
|
+
"import { SchemockProvider, createClient } from './generated';",
|
|
4483
|
+
"",
|
|
4484
|
+
"// Create a client with auth interceptors",
|
|
4485
|
+
"const api = createClient({",
|
|
4486
|
+
" onRequest: (ctx) => {",
|
|
4487
|
+
' const token = localStorage.getItem("authToken");',
|
|
4488
|
+
" if (token) {",
|
|
4489
|
+
" ctx.headers.Authorization = `Bearer ${token}`;",
|
|
4490
|
+
" }",
|
|
4491
|
+
" return ctx;",
|
|
4492
|
+
" },",
|
|
4493
|
+
" onError: (error) => {",
|
|
4494
|
+
" if (error.status === 401) {",
|
|
4495
|
+
' window.location.href = "/login";',
|
|
4496
|
+
" }",
|
|
4497
|
+
" }",
|
|
4498
|
+
"});",
|
|
4499
|
+
"",
|
|
4500
|
+
"// Wrap your app with the provider",
|
|
4501
|
+
"function App() {",
|
|
4502
|
+
" return (",
|
|
4503
|
+
" <SchemockProvider client={api}>",
|
|
4504
|
+
" <MyComponent />",
|
|
4505
|
+
" </SchemockProvider>",
|
|
4506
|
+
" );",
|
|
4507
|
+
"}",
|
|
4508
|
+
"",
|
|
4509
|
+
"// Now all hooks automatically use the configured client",
|
|
4510
|
+
"function MyComponent() {",
|
|
4511
|
+
" const { data } = useUsers(); // Uses auth-configured client",
|
|
4512
|
+
" return <div>{data?.data.map(u => u.name)}</div>;",
|
|
4513
|
+
"}",
|
|
4514
|
+
"```"
|
|
4515
|
+
]);
|
|
4516
|
+
code.block("export function SchemockProvider({ client, children }: SchemockProviderProps): JSX.Element {", () => {
|
|
4517
|
+
code.line("return (");
|
|
4518
|
+
code.line(" <SchemockContext.Provider value={client ?? defaultApi}>");
|
|
4519
|
+
code.line(" {children}");
|
|
4520
|
+
code.line(" </SchemockContext.Provider>");
|
|
4521
|
+
code.line(");");
|
|
4522
|
+
});
|
|
4523
|
+
code.line();
|
|
4524
|
+
code.multiDocComment([
|
|
4525
|
+
"Hook to access the API client from context.",
|
|
4526
|
+
"",
|
|
4527
|
+
"This is used internally by generated hooks to access the configured client.",
|
|
4528
|
+
"You can also use it directly if you need to call API methods outside of hooks.",
|
|
4529
|
+
"",
|
|
4530
|
+
"@returns The API client from context (or default if no provider)",
|
|
4531
|
+
"",
|
|
4532
|
+
"@example",
|
|
4533
|
+
"```tsx",
|
|
4534
|
+
"import { useSchemockClient } from './generated';",
|
|
4535
|
+
"",
|
|
4536
|
+
"function MyComponent() {",
|
|
4537
|
+
" const api = useSchemockClient();",
|
|
4538
|
+
"",
|
|
4539
|
+
" const handleClick = async () => {",
|
|
4540
|
+
" // Direct API call using the configured client",
|
|
4541
|
+
' await api.user.create({ name: "John" });',
|
|
4542
|
+
" };",
|
|
4543
|
+
"",
|
|
4544
|
+
" return <button onClick={handleClick}>Create User</button>;",
|
|
4545
|
+
"}",
|
|
4546
|
+
"```"
|
|
4547
|
+
]);
|
|
4548
|
+
code.block("export function useSchemockClient(): ApiClient {", () => {
|
|
4549
|
+
code.line("return useContext(SchemockContext);");
|
|
4550
|
+
});
|
|
4551
|
+
code.line();
|
|
4552
|
+
code.comment("Re-export client types for convenience");
|
|
4553
|
+
code.line("export type { ApiClient } from './client';");
|
|
4554
|
+
return code.toString();
|
|
4555
|
+
}
|
|
4556
|
+
|
|
4445
4557
|
// src/cli/generators/form-schemas.ts
|
|
4446
4558
|
function generateFormSchemas(schemas) {
|
|
4447
4559
|
const code = new CodeBuilder();
|
|
@@ -6506,6 +6618,9 @@ async function generateClientTarget(target, schemas, endpoints, config, options)
|
|
|
6506
6618
|
console.log(" \u26A0\uFE0F GraphQL target not yet implemented");
|
|
6507
6619
|
break;
|
|
6508
6620
|
}
|
|
6621
|
+
const providerCode = generateProvider();
|
|
6622
|
+
await writeOutput3(path.join(outputDir, "provider.ts"), providerCode, options.dryRun);
|
|
6623
|
+
files.push("provider.ts");
|
|
6509
6624
|
const hooksCode = generateHooks(targetSchemas);
|
|
6510
6625
|
await writeOutput3(path.join(outputDir, "hooks.ts"), hooksCode, options.dryRun);
|
|
6511
6626
|
files.push("hooks.ts");
|
|
@@ -6632,7 +6747,8 @@ function generateClientIndex(targetType, hasEndpoints = false) {
|
|
|
6632
6747
|
"",
|
|
6633
6748
|
"export * from './types';",
|
|
6634
6749
|
"export * from './hooks';",
|
|
6635
|
-
"export
|
|
6750
|
+
"export * from './provider';",
|
|
6751
|
+
"export { api, createClient } from './client';"
|
|
6636
6752
|
];
|
|
6637
6753
|
if (targetType === "mock") {
|
|
6638
6754
|
lines.push("export { db } from './db';");
|
|
@@ -6801,6 +6917,10 @@ async function generate(options) {
|
|
|
6801
6917
|
default:
|
|
6802
6918
|
throw new Error(`Unknown adapter: ${adapter}`);
|
|
6803
6919
|
}
|
|
6920
|
+
console.log("\n\u{1F3A3} Generating React Context provider...");
|
|
6921
|
+
const providerCode = generateProvider();
|
|
6922
|
+
await writeOutput4(path.join(outputDir, "provider.ts"), providerCode, options.dryRun);
|
|
6923
|
+
console.log(" \u2713 provider.ts (SchemockProvider + useSchemockClient)");
|
|
6804
6924
|
console.log("\n\u269B\uFE0F Generating React hooks...");
|
|
6805
6925
|
const hooksCode = generateHooks(analyzed);
|
|
6806
6926
|
await writeOutput4(path.join(outputDir, "hooks.ts"), hooksCode, options.dryRun);
|
|
@@ -6892,7 +7012,8 @@ function generateIndex(adapter, hasEndpoints = false) {
|
|
|
6892
7012
|
"",
|
|
6893
7013
|
"export * from './types';",
|
|
6894
7014
|
"export * from './hooks';",
|
|
6895
|
-
"export
|
|
7015
|
+
"export * from './provider';",
|
|
7016
|
+
"export { api, createClient } from './client';"
|
|
6896
7017
|
];
|
|
6897
7018
|
if (adapter === "mock") {
|
|
6898
7019
|
lines.push("export { db } from './db';");
|