schemock 0.0.4-alpha.14 → 0.0.4-alpha.16

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/dist/cli/index.js CHANGED
@@ -3118,6 +3118,7 @@ function generateEndpointHandlers(endpoints) {
3118
3118
  function generateHandler(code, endpoint) {
3119
3119
  const { name, method, path, params, body, pathParams } = endpoint;
3120
3120
  const httpMethod = method.toLowerCase();
3121
+ const hasBody = body.length > 0;
3121
3122
  code.comment(`${method} ${path}`);
3122
3123
  code.block(`http.${httpMethod}('${path}', async ({ request, params: pathParams }) => {`, () => {
3123
3124
  if (method === "GET" && params.length > 0) {
@@ -3139,20 +3140,21 @@ function generateHandler(code, endpoint) {
3139
3140
  }
3140
3141
  }, "};");
3141
3142
  code.line();
3143
+ } else {
3144
+ code.line("const params = {};");
3145
+ code.line();
3142
3146
  }
3143
- if (body.length > 0) {
3147
+ if (hasBody) {
3144
3148
  code.line("const body = await request.json();");
3145
- code.line();
3149
+ } else {
3150
+ code.line("const body = {};");
3146
3151
  }
3147
- const ctxParts = ["db"];
3148
- if (params.length > 0 || pathParams.length > 0) ctxParts.push("params");
3149
- if (body.length > 0) ctxParts.push("body");
3152
+ code.line();
3150
3153
  code.line("const headers: Record<string, string> = {};");
3151
3154
  code.line("request.headers.forEach((value, key) => { headers[key] = value; });");
3152
- ctxParts.push("headers");
3153
3155
  code.line();
3154
3156
  code.block("try {", () => {
3155
- code.line(`const result = await endpointResolvers.${name}({ ${ctxParts.join(", ")} });`);
3157
+ code.line(`const result = await endpointResolvers.${name}({ db, params, body, headers });`);
3156
3158
  code.line("return HttpResponse.json(result);");
3157
3159
  }, "} catch (error) {");
3158
3160
  code.indent();
@@ -3197,15 +3199,24 @@ function generateEndpointResolvers(endpoints, outputDir) {
3197
3199
  code.comment("consider using named exported functions instead - they will be automatically imported.");
3198
3200
  code.line();
3199
3201
  code.line("import type { Database } from './db';");
3202
+ code.line("import type * as Types from './types';");
3200
3203
  code.line();
3201
- code.comment("Resolver context with typed database access");
3202
- code.block("export interface ResolverContext {", () => {
3203
- code.line("params: Record<string, unknown>;");
3204
- code.line("body: Record<string, unknown>;");
3204
+ code.comment("Base resolver context with typed database access");
3205
+ code.block("export interface ResolverContext<TParams = Record<string, unknown>, TBody = Record<string, unknown>> {", () => {
3206
+ code.line("params: TParams;");
3207
+ code.line("body: TBody;");
3205
3208
  code.line("db: Database;");
3206
3209
  code.line("headers: Record<string, string>;");
3207
3210
  });
3208
3211
  code.line();
3212
+ code.comment("Per-endpoint typed resolver contexts");
3213
+ for (const endpoint of endpoints) {
3214
+ const { pascalName, params, body } = endpoint;
3215
+ const paramsType = params.length > 0 ? `Types.${pascalName}Params` : "Record<string, never>";
3216
+ const bodyType = body.length > 0 ? `Types.${pascalName}Body` : "Record<string, never>";
3217
+ code.line(`export type ${pascalName}ResolverContext = ResolverContext<${paramsType}, ${bodyType}>;`);
3218
+ }
3219
+ code.line();
3209
3220
  code.comment("Error class for HTTP errors in resolvers");
3210
3221
  code.block("export class HttpError extends Error {", () => {
3211
3222
  code.line("readonly status: number;");
@@ -3237,7 +3248,8 @@ function generateEndpointResolvers(endpoints, outputDir) {
3237
3248
  if (!inlineDependencies.has(key)) {
3238
3249
  inlineDependencies.set(key, {
3239
3250
  name: dep.name,
3240
- importPath: dep.from
3251
+ importPath: dep.from,
3252
+ sourceFile: endpoint.sourceFile
3241
3253
  });
3242
3254
  }
3243
3255
  }
@@ -3280,33 +3292,63 @@ function generateEndpointResolvers(endpoints, outputDir) {
3280
3292
  if (inlineDependencies.size > 0) {
3281
3293
  code.line();
3282
3294
  code.comment("Dependencies used by inline resolvers");
3283
- const importsByPath = /* @__PURE__ */ new Map();
3284
- for (const { name, importPath } of inlineDependencies.values()) {
3285
- if (!importsByPath.has(importPath)) {
3286
- importsByPath.set(importPath, []);
3295
+ const importsByResolvedPath = /* @__PURE__ */ new Map();
3296
+ for (const { name, importPath, sourceFile } of inlineDependencies.values()) {
3297
+ let resolvedPath = importPath;
3298
+ if (importPath.startsWith(".") && sourceFile && outputDir) {
3299
+ const toPosix = (p) => p.replace(/\\/g, "/");
3300
+ const sourceDir = toPosix(sourceFile).replace(/\/[^/]+$/, "");
3301
+ const parts = sourceDir.split("/").filter(Boolean);
3302
+ const importParts = importPath.split("/");
3303
+ for (const part of importParts) {
3304
+ if (part === "..") {
3305
+ parts.pop();
3306
+ } else if (part !== ".") {
3307
+ parts.push(part);
3308
+ }
3309
+ }
3310
+ const absolutePath = "/" + parts.join("/");
3311
+ resolvedPath = calculateRelativePath(absolutePath);
3312
+ }
3313
+ if (!importsByResolvedPath.has(resolvedPath)) {
3314
+ importsByResolvedPath.set(resolvedPath, []);
3287
3315
  }
3288
- const names = importsByPath.get(importPath);
3316
+ const names = importsByResolvedPath.get(resolvedPath);
3289
3317
  if (!names.includes(name)) {
3290
3318
  names.push(name);
3291
3319
  }
3292
3320
  }
3293
- for (const [importPath, names] of importsByPath) {
3294
- code.line(`import { ${names.join(", ")} } from '${importPath}';`);
3321
+ for (const [resolvedPath, names] of importsByResolvedPath) {
3322
+ code.line(`import { ${names.join(", ")} } from '${resolvedPath}';`);
3295
3323
  }
3296
3324
  }
3297
3325
  code.line();
3298
- code.line("type ResolverFn = (ctx: ResolverContext) => unknown | Promise<unknown>;");
3326
+ code.comment("Typed resolver function types");
3327
+ for (const endpoint of endpoints) {
3328
+ const { pascalName } = endpoint;
3329
+ code.line(
3330
+ `type ${pascalName}ResolverFn = (ctx: ${pascalName}ResolverContext) => Types.${pascalName}Response | Promise<Types.${pascalName}Response>;`
3331
+ );
3332
+ }
3333
+ code.line();
3334
+ code.comment("Typed endpoint resolvers interface");
3335
+ code.block("export interface EndpointResolvers {", () => {
3336
+ for (const endpoint of endpoints) {
3337
+ const { name, pascalName } = endpoint;
3338
+ code.line(`${name}: ${pascalName}ResolverFn;`);
3339
+ }
3340
+ });
3299
3341
  code.line();
3300
- code.block("export const endpointResolvers: Record<string, ResolverFn> = {", () => {
3342
+ code.block("export const endpointResolvers: EndpointResolvers = {", () => {
3301
3343
  for (const endpoint of endpoints) {
3302
3344
  code.comment(`${endpoint.method} ${endpoint.path}`);
3303
3345
  if (endpoint.description) {
3304
3346
  code.comment(endpoint.description);
3305
3347
  }
3306
3348
  if (endpoint.mockResolverName) {
3307
- code.line(`${endpoint.name}: ${endpoint.mockResolverName},`);
3349
+ code.line(`${endpoint.name}: ${endpoint.mockResolverName} as ${endpoint.pascalName}ResolverFn,`);
3308
3350
  } else {
3309
- code.line(`${endpoint.name}: ${endpoint.mockResolverSource},`);
3351
+ code.line(`${endpoint.name}: (${endpoint.mockResolverSource}) as ${endpoint.pascalName}ResolverFn,`);
3310
3352
  }
3311
3353
  code.line();
3312
3354
  }