hono-takibi 0.9.99993 → 0.9.99994

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 CHANGED
@@ -486,6 +486,11 @@ export default defineConfig({
486
486
 
487
487
  mock: {
488
488
  output: './src/mock.ts',
489
+ useExamples: true,
490
+ locale: 'en',
491
+ delay: false,
492
+ arrayMin: 1,
493
+ arrayMax: 10,
489
494
  },
490
495
 
491
496
  docs: {
@@ -280,6 +280,14 @@ declare const ConfigSchema: z.ZodReadonly<z.ZodObject<{
280
280
  }, z.core.$strip>>>;
281
281
  mock: z.ZodExactOptional<z.ZodReadonly<z.ZodObject<{
282
282
  output: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
283
+ useExamples: z.ZodExactOptional<z.ZodBoolean>;
284
+ locale: z.ZodExactOptional<z.ZodString>;
285
+ delay: z.ZodExactOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodLiteral<false>, z.ZodReadonly<z.ZodObject<{
286
+ min: z.ZodNumber;
287
+ max: z.ZodNumber;
288
+ }, z.core.$strip>>]>>;
289
+ arrayMin: z.ZodExactOptional<z.ZodNumber>;
290
+ arrayMax: z.ZodExactOptional<z.ZodNumber>;
283
291
  }, z.core.$strip>>>;
284
292
  docs: z.ZodExactOptional<z.ZodDiscriminatedUnion<[z.ZodReadonly<z.ZodObject<{
285
293
  output: z.ZodTemplateLiteral<`${string}.md`>;
@@ -565,6 +573,14 @@ declare function parseConfig(config: unknown): {
565
573
  }>;
566
574
  mock?: Readonly<{
567
575
  output: string;
576
+ useExamples?: boolean;
577
+ locale?: string;
578
+ delay?: number | false | Readonly<{
579
+ min: number;
580
+ max: number;
581
+ }>;
582
+ arrayMin?: number;
583
+ arrayMax?: number;
568
584
  }>;
569
585
  docs?: Readonly<{
570
586
  output: `${string}.md`;
@@ -852,6 +868,14 @@ declare function readConfig(): Promise<{
852
868
  }>;
853
869
  mock?: Readonly<{
854
870
  output: string;
871
+ useExamples?: boolean;
872
+ locale?: string;
873
+ delay?: number | false | Readonly<{
874
+ min: number;
875
+ max: number;
876
+ }>;
877
+ arrayMin?: number;
878
+ arrayMax?: number;
855
879
  }>;
856
880
  docs?: Readonly<{
857
881
  output: `${string}.md`;
@@ -1136,6 +1160,14 @@ declare function defineConfig(config: z.input<typeof ConfigSchema>): Readonly<{
1136
1160
  }>;
1137
1161
  mock?: Readonly<{
1138
1162
  output: string;
1163
+ useExamples?: boolean;
1164
+ locale?: string;
1165
+ delay?: number | false | Readonly<{
1166
+ min: number;
1167
+ max: number;
1168
+ }>;
1169
+ arrayMin?: number;
1170
+ arrayMax?: number;
1139
1171
  }>;
1140
1172
  docs?: Readonly<{
1141
1173
  output: `${string}.md`;
@@ -148,7 +148,21 @@ const ConfigSchema = z.object({
148
148
  "bun"
149
149
  ]).default("vitest").exactOptional()
150
150
  }).readonly().exactOptional(),
151
- mock: z.object({ output: FileOutputSchema }).readonly().exactOptional(),
151
+ mock: z.object({
152
+ output: FileOutputSchema,
153
+ useExamples: z.boolean().exactOptional(),
154
+ locale: z.string().regex(/^[A-Za-z_]{1,40}$/, { error: "Invalid faker locale. Use a code like 'ja', 'en', or 'zh_CN'." }).exactOptional(),
155
+ delay: z.union([
156
+ z.number().int().nonnegative().max(6e4),
157
+ z.literal(false),
158
+ z.object({
159
+ min: z.number().int().nonnegative().max(6e4),
160
+ max: z.number().int().nonnegative().max(6e4)
161
+ }).readonly().refine((v) => v.min <= v.max, { message: "delay.min must be <= delay.max. Swap the values or remove one." })
162
+ ]).exactOptional(),
163
+ arrayMin: z.number().int().nonnegative().max(1e3).exactOptional(),
164
+ arrayMax: z.number().int().nonnegative().max(1e3).exactOptional()
165
+ }).readonly().refine((v) => v.arrayMin === void 0 || v.arrayMax === void 0 || v.arrayMin <= v.arrayMax, { message: "arrayMin must be <= arrayMax. Swap the values or remove one." }).exactOptional(),
152
166
  docs: z.discriminatedUnion("curl", [z.object({
153
167
  output: z.templateLiteral([z.string().min(1), z.enum([".md"])], { error: "must be .md file" }),
154
168
  curl: z.literal(true),
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { readConfig } from "./config/index.js";
3
3
  import { r as setFormatOptions } from "./emit-CFR63U4L.js";
4
- import { n as parseOpenAPI, r as takibi, t as makeJob } from "./shared-DC4zuL9A.js";
4
+ import { n as parseOpenAPI, r as takibi, t as makeJob } from "./shared-n3ZMLfl9.js";
5
5
  import { existsSync } from "node:fs";
6
6
  import { resolve } from "node:path";
7
7
  //#region src/cli/index.ts
@@ -514,7 +514,7 @@ const FORMAT_TO_FAKER = {
514
514
  gender: "faker.person.gender()",
515
515
  bic: "faker.finance.bic()",
516
516
  iban: "faker.finance.iban()",
517
- binary: "new Blob([faker.string.alphanumeric(100)])",
517
+ binary: "new File([faker.string.alphanumeric(100)], faker.system.fileName())",
518
518
  byte: "btoa(faker.string.alphanumeric(10))",
519
519
  int32: "faker.number.int({ min: -2147483648, max: 2147483647 })",
520
520
  int64: "faker.number.bigInt({ min: 0n, max: 9007199254740991n })",
@@ -615,7 +615,9 @@ function schemaToFaker(schema, propertyName, options = {}) {
615
615
  if (schema.type === "array" && schema.items) {
616
616
  const itemSchema = Array.isArray(schema.items) ? schema.items[0] : schema.items;
617
617
  if (!itemSchema) return "[]";
618
- return `Array.from({ length: faker.number.int({ min: 1, max: 5 }) }, () => (${schemaToFaker(itemSchema, void 0, options)}))`;
618
+ const itemFaker = schemaToFaker(itemSchema, void 0, options);
619
+ const min = schema.minItems ?? options.arrayMin ?? 1;
620
+ return `Array.from({ length: faker.number.int({ min: ${min}, max: ${schema.maxItems ?? options.arrayMax ?? Math.max(min, 10)} }) }, () => (${itemFaker}))`;
619
621
  }
620
622
  const renderProps = (properties, required) => {
621
623
  const requiredSet = new Set(required || []);
@@ -655,7 +657,8 @@ function schemaToFaker(schema, propertyName, options = {}) {
655
657
  if (schema.type && typeof schema.type === "string" && TYPE_TO_FAKER[schema.type]) {
656
658
  if (schema.type === "string") {
657
659
  if (schema.pattern) return `faker.helpers.fromRegExp(/${escapeRegexLiteral(schema.pattern)}/)`;
658
- return `faker.string.alpha({ length: { min: ${schema.minLength ?? 5}, max: ${schema.maxLength ?? 20} } })`;
660
+ const min = schema.minLength ?? 5;
661
+ return `faker.string.alpha({ length: { min: ${min}, max: ${schema.maxLength ?? Math.max(min, 20)} } })`;
659
662
  }
660
663
  if (schema.type === "integer" || schema.type === "number") return numericFaker(schema, numericRange(schema, schema.type === "integer"));
661
664
  return TYPE_TO_FAKER[schema.type];
@@ -759,8 +762,11 @@ function schemaClosure(roots, schemas) {
759
762
  }
760
763
  return used;
761
764
  }
762
- function makeMockFunction(name, schema, schemas, isCircular) {
763
- const mockBody = schemaToFaker(schema, void 0, { schemas });
765
+ function makeMockFunction(name, schema, schemas, isCircular, fakerOptions) {
766
+ const mockBody = schemaToFaker(schema, void 0, {
767
+ schemas,
768
+ ...fakerOptions
769
+ });
764
770
  const returnType = isCircular ? ": any" : "";
765
771
  const sanitized = name.replace(/\./g, "");
766
772
  const schemaConst = toIdentifierPascalCase(ensureSuffix(name, "Schema"));
@@ -896,64 +902,34 @@ function extractMediaExample(media, components) {
896
902
  }
897
903
  return "value" in first ? first.value : void 0;
898
904
  }
899
- const PAGE_PARAM_NAMES = [
900
- "page",
901
- "pageNumber",
902
- "page_number"
903
- ];
904
- const OFFSET_PARAM_NAMES = ["offset", "skip"];
905
- const ROWS_PARAM_NAMES = [
906
- "rows",
907
- "limit",
908
- "perPage",
909
- "per_page",
910
- "pageSize",
911
- "page_size",
912
- "size",
913
- "take"
914
- ];
915
- function detectPagination(operation) {
916
- if (operation["x-pagination"] !== true) return void 0;
917
- const queryParams = (operation.parameters ?? []).filter((p) => "in" in p && p.in === "query");
918
- const rows = queryParams.find((p) => ROWS_PARAM_NAMES.includes(p.name));
919
- if (!rows) return void 0;
920
- const pageParam = queryParams.find((p) => PAGE_PARAM_NAMES.includes(p.name));
921
- const offsetParam = pageParam ? void 0 : queryParams.find((p) => OFFSET_PARAM_NAMES.includes(p.name));
922
- const cursor = pageParam ?? offsetParam;
923
- if (!cursor) return void 0;
924
- const defaultRows = typeof rows.schema?.default === "number" ? rows.schema.default : 20;
925
- return {
926
- rowsParam: rows.name,
927
- cursorParam: cursor.name,
928
- offsetStyle: offsetParam !== void 0,
929
- defaultRows
930
- };
931
- }
932
905
  function makeHandlerBody(args) {
933
- const { statusCode, jsonSchema, textSchema, schemas, allRefs, exampleValue, exampleCast, pagination } = args;
906
+ const { statusCode, jsonSchema, textSchema, schemas, fakerOptions, allRefs, exampleValue, exampleCast } = args;
934
907
  if (exampleValue !== void 0) {
935
908
  const cast = exampleCast ? ` as z.infer<typeof ${exampleCast}>` : "";
936
909
  return `return c.json(${JSON.stringify(exampleValue)}${cast}, ${statusCode})`;
937
910
  }
938
- if (pagination && jsonSchema?.type === "array" && jsonSchema.items) {
939
- collectRefs(jsonSchema, allRefs);
940
- const itemFaker = schemaToFaker(Array.isArray(jsonSchema.items) ? jsonSchema.items[0] : jsonSchema.items, void 0, { schemas });
941
- const startExpr = pagination.offsetStyle ? `const start = query.${pagination.cursorParam} ?? 0` : `const page = query.${pagination.cursorParam} ?? 1\nconst start = (page - 1) * rows`;
942
- return `const query = c.req.valid('query')
943
- const rows = query.${pagination.rowsParam} ?? ${pagination.defaultRows}
944
- ${startExpr}
945
- const items = Array.from({ length: ${pagination.totalConst} }, () => (${itemFaker}))
946
- return c.json(items.slice(start, start + rows), ${statusCode})`;
947
- }
948
911
  if (jsonSchema) {
949
912
  collectRefs(jsonSchema, allRefs);
950
- return `return c.json(${schemaToFaker(jsonSchema, void 0, { schemas })}, ${statusCode})`;
913
+ return `return c.json(${schemaToFaker(jsonSchema, void 0, {
914
+ schemas,
915
+ ...fakerOptions
916
+ })}, ${statusCode})`;
951
917
  }
952
- if (textSchema) return `return c.text(${schemaToFaker(textSchema, void 0, { schemas })}, ${statusCode})`;
918
+ if (textSchema) return `return c.text(${schemaToFaker(textSchema, void 0, {
919
+ schemas,
920
+ ...fakerOptions
921
+ })}, ${statusCode})`;
953
922
  if (statusCode === 204) return `return new Response(null, { status: 204 })`;
954
923
  return `return c.body(null, ${statusCode})`;
955
924
  }
925
+ function delayMiddlewareCode(delay) {
926
+ const ms = typeof delay === "number" ? `${delay}` : typeof delay === "object" && delay !== null ? `faker.number.int({ min: ${delay.min}, max: ${delay.max} })` : void 0;
927
+ if (ms === void 0) return "";
928
+ return `\n\napp.use(async (_c, next) => {\n await new Promise((resolve) => setTimeout(resolve, ${ms}))\n await next()\n})`;
929
+ }
956
930
  function makeMock(openapi, basePath, options = {}) {
931
+ const { useExamples: useExamplesOption, locale, delay, readonly: readonlyOption, ...fakerOptions } = options;
932
+ const useExamples = useExamplesOption ?? true;
957
933
  const filteredOpenapi = filterToJsonContentTypes(openapi);
958
934
  const paths = filteredOpenapi.paths;
959
935
  const schemas = openapi.components?.schemas ?? {};
@@ -972,24 +948,17 @@ function makeMock(openapi, basePath, options = {}) {
972
948
  const textMedia = successResponse?.content?.["text/plain"];
973
949
  const jsonSchema = jsonMedia && isMediaWithSchema(jsonMedia) ? jsonMedia.schema : void 0;
974
950
  const textSchema = textMedia && isMediaWithSchema(textMedia) ? textMedia.schema : void 0;
975
- const exampleValue = jsonMedia ? extractMediaExample(jsonMedia, openapi.components) : void 0;
976
- const exampleCast = exampleValue !== void 0 && jsonSchema?.$ref ? toIdentifierPascalCase(ensureSuffix(jsonSchema.$ref.split("/").at(-1) ?? "", "Schema")) : void 0;
977
- const pag = detectPagination(operation);
978
- const pagination = pag && exampleValue === void 0 && jsonSchema?.type === "array" && jsonSchema.items ? {
979
- totalConst: `${routeId}Total`,
980
- ...pag
981
- } : void 0;
951
+ const exampleValue = useExamples && jsonMedia ? extractMediaExample(jsonMedia, openapi.components) : void 0;
982
952
  const handlerBody = makeHandlerBody({
983
953
  statusCode,
984
954
  jsonSchema,
985
955
  textSchema,
986
956
  schemas,
957
+ fakerOptions,
987
958
  allRefs,
988
959
  exampleValue,
989
- exampleCast,
990
- pagination
960
+ exampleCast: exampleValue !== void 0 && jsonSchema?.$ref ? toIdentifierPascalCase(ensureSuffix(jsonSchema.$ref.split("/").at(-1) ?? "", "Schema")) : void 0
991
961
  });
992
- const paginationDecl = pagination ? `const ${pagination.totalConst} = faker.number.int({ min: 0, max: ${Math.min(pagination.defaultRows * 3, 3e3)} })` : "";
993
962
  const authCheck = makeAuthCheck(security, operation.responses?.[String(401)] !== void 0);
994
963
  const handler = `const ${routeId}RouteHandler: RouteHandler<typeof ${routeId}Route> = async (${handlerBody.includes("c.") || authCheck !== "" ? "c" : "_c"}) => {${authCheck}${handlerBody}}`;
995
964
  return [{
@@ -999,18 +968,16 @@ function makeMock(openapi, basePath, options = {}) {
999
968
  path: p,
1000
969
  requiresAuth
1001
970
  },
1002
- handler,
1003
- paginationDecl
971
+ handler
1004
972
  }];
1005
973
  }));
1006
974
  const routeMetas = processed.map(({ entry }) => entry);
1007
975
  const handlers = processed.map(({ handler }) => handler);
1008
- const paginationDecls = processed.flatMap(({ paginationDecl }) => paginationDecl.length > 0 ? [paginationDecl] : []);
1009
976
  const allDeps = /* @__PURE__ */ new Set();
1010
977
  for (const ref of allRefs) collectAllDependencies(ref, schemas, allDeps);
1011
978
  const sortedRefs = topologicalSort(allDeps, schemas);
1012
979
  const circularSchemas = detectCircularSchemas$1(schemas);
1013
- const mockFunctions = sortedRefs.filter((refName) => schemas[refName]).map((refName) => makeMockFunction(refName, schemas[refName], schemas, circularSchemas.has(refName)));
980
+ const mockFunctions = sortedRefs.filter((refName) => schemas[refName]).map((refName) => makeMockFunction(refName, schemas[refName], schemas, circularSchemas.has(refName), fakerOptions));
1014
981
  const rootRefs = collectSchemaRefs$1(filteredOpenapi.paths, /* @__PURE__ */ new Set());
1015
982
  if (openapi.components) {
1016
983
  collectSchemaRefs$1(openapi.components.responses, rootRefs);
@@ -1042,14 +1009,16 @@ function makeMock(openapi, basePath, options = {}) {
1042
1009
  exportPathItems: false,
1043
1010
  exportMediaTypes: false,
1044
1011
  exportMediaTypesTypes: false,
1045
- ...options.readonly !== void 0 ? { readonly: options.readonly } : {}
1012
+ ...readonlyOption !== void 0 ? { readonly: readonlyOption } : {}
1046
1013
  }) : "";
1047
- const routes = routeCode(filteredOpenapi, options.readonly);
1014
+ const routes = routeCode(filteredOpenapi, readonlyOption);
1048
1015
  const appSetup = routeMetas.map(({ routeId }) => `.openapi(${routeId}Route, ${routeId}RouteHandler)`).join("");
1049
1016
  const handlersJoined = handlers.join("\n\n");
1017
+ const needsCookieImport = handlersJoined.includes("getCookie(c,");
1050
1018
  const imports = `import { OpenAPIHono, createRoute, z, type RouteHandler } from '@hono/zod-openapi'
1051
- import { faker } from '@faker-js/faker'${handlersJoined.includes("getCookie(c,") ? `\nimport { getCookie } from 'hono/cookie'` : ""}`;
1052
- const appCode = `const app = new OpenAPIHono()${basePath !== "/" ? `.basePath('${basePath}')` : ""}
1019
+ ${locale ? `import { faker } from '@faker-js/faker/locale/${locale}'` : `import { faker } from '@faker-js/faker'`}${needsCookieImport ? `\nimport { getCookie } from 'hono/cookie'` : ""}`;
1020
+ const delayMiddleware = delayMiddlewareCode(delay);
1021
+ const appCode = `const app = new OpenAPIHono()${basePath !== "/" ? `.basePath('${basePath}')` : ""}${delayMiddleware}
1053
1022
 
1054
1023
  export const api = app${appSetup}
1055
1024
 
@@ -1059,15 +1028,14 @@ export default app`;
1059
1028
  components,
1060
1029
  routes,
1061
1030
  mockFunctions.join("\n\n"),
1062
- paginationDecls.join("\n"),
1063
1031
  handlersJoined,
1064
1032
  appCode
1065
1033
  ].filter((s) => s.length > 0).join("\n\n");
1066
1034
  }
1067
1035
  //#endregion
1068
1036
  //#region src/core/mock/index.ts
1069
- async function mock(openAPI, output, basePath, readonly) {
1070
- const emitResult = await emit(makeMock(openAPI, basePath, readonly !== void 0 ? { readonly } : {}), path.dirname(output), output);
1037
+ async function mock(openAPI, output, basePath, options = {}) {
1038
+ const emitResult = await emit(makeMock(openAPI, basePath, options), path.dirname(output), output);
1071
1039
  if (!emitResult.ok) return {
1072
1040
  ok: false,
1073
1041
  error: emitResult.error
@@ -2912,7 +2880,10 @@ function makeJob(openAPI, config) {
2912
2880
  name: "mock",
2913
2881
  output: config.mock.output,
2914
2882
  split: false,
2915
- run: (output) => mock(openAPI, output, config.basePath, config.readonly)
2883
+ run: (output) => mock(openAPI, output, config.basePath, {
2884
+ ...config.mock,
2885
+ ...config.readonly !== void 0 ? { readonly: config.readonly } : {}
2886
+ })
2916
2887
  } : void 0,
2917
2888
  config.docs ? {
2918
2889
  name: "docs",
@@ -1,7 +1,7 @@
1
1
  import { parseConfig } from "../config/index.js";
2
2
  import { r as setFormatOptions } from "../emit-CFR63U4L.js";
3
3
  import { f as isRecord } from "../guard-zvkMUVYD.js";
4
- import { n as parseOpenAPI, t as makeJob } from "../shared-DC4zuL9A.js";
4
+ import { n as parseOpenAPI, t as makeJob } from "../shared-n3ZMLfl9.js";
5
5
  import path from "node:path";
6
6
  import fsp from "node:fs/promises";
7
7
  //#region src/vite-plugin/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono-takibi",
3
- "version": "0.9.99993",
3
+ "version": "0.9.99994",
4
4
  "description": "Hono Takibi is a code generator from OpenAPI to @hono/zod-openapi",
5
5
  "keywords": [
6
6
  "hono",