hono-openapi 1.1.2 → 1.2.0

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.
Files changed (3) hide show
  1. package/dist/index.cjs +22 -11
  2. package/dist/index.js +22 -11
  3. package/package.json +86 -84
package/dist/index.cjs CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var handler = require('hono/utils/handler');
3
4
  var standardValidator = require('@hono/standard-validator');
4
5
  var standardJson = require('@standard-community/standard-json');
5
6
  var standardOpenapi = require('@standard-community/standard-openapi');
@@ -15,8 +16,8 @@ const ALLOWED_METHODS = [
15
16
  "PATCH",
16
17
  "TRACE"
17
18
  ];
18
- const toOpenAPIPath = (path) => path.split("/").map((x) => {
19
- let tmp = x;
19
+ const toOpenAPIPathSegment = (segment) => {
20
+ let tmp = segment;
20
21
  if (tmp.startsWith(":")) {
21
22
  const match = tmp.match(/^:([^{?]+)(?:{(.+)})?(\?)?$/);
22
23
  if (match) {
@@ -29,16 +30,18 @@ const toOpenAPIPath = (path) => path.split("/").map((x) => {
29
30
  }
30
31
  }
31
32
  return tmp;
32
- }).join("/");
33
- const capitalize = (word) => word.charAt(0).toUpperCase() + word.slice(1);
33
+ };
34
+ const toOpenAPIPath = (path) => path.split("/").map(toOpenAPIPathSegment).join("/");
35
+ const toPascalCase = (text) => text.split(/[\W_]+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
34
36
  const generateOperationId = (route) => {
35
37
  let operationId = route.method.toLowerCase();
36
38
  if (route.path === "/") return `${operationId}Index`;
37
39
  for (const segment of route.path.split("/")) {
38
- if (segment.charCodeAt(0) === 123) {
39
- operationId += `By${capitalize(segment.slice(1, -1))}`;
40
+ const openApiPathSegment = toOpenAPIPathSegment(segment);
41
+ if (openApiPathSegment.charCodeAt(0) === 123) {
42
+ operationId += `By${toPascalCase(openApiPathSegment.slice(1, -1))}`;
40
43
  } else {
41
- operationId += capitalize(segment);
44
+ operationId += toPascalCase(openApiPathSegment);
42
45
  }
43
46
  }
44
47
  return operationId;
@@ -196,7 +199,15 @@ function removeExcludedPaths(paths, ctx) {
196
199
  };
197
200
  }
198
201
  }
199
- newPaths[key] = value;
202
+ const filteredValue = {};
203
+ for (const method of Object.keys(value)) {
204
+ if (value[method] != null) {
205
+ filteredValue[method] = value[method];
206
+ }
207
+ }
208
+ if (Object.keys(filteredValue).length > 0) {
209
+ newPaths[key] = filteredValue;
210
+ }
200
211
  }
201
212
  return newPaths;
202
213
  }
@@ -267,7 +278,7 @@ async function generateSpecs(hono, options = DEFAULT_OPTIONS, c) {
267
278
  async function generatePaths(hono, ctx) {
268
279
  const paths = {};
269
280
  for (const route of hono.routes) {
270
- const middlewareHandler = route.handler[uniqueSymbol];
281
+ const middlewareHandler = handler.findTargetHandler(route.handler)[uniqueSymbol];
271
282
  if (!middlewareHandler) {
272
283
  if (ctx.options.includeEmptyPaths) {
273
284
  registerSchemaPath({
@@ -286,7 +297,7 @@ async function generatePaths(hono, ctx) {
286
297
  continue;
287
298
  }
288
299
  }
289
- const defaultOptionsForThisMethod = ctx.options.defaultOptions?.[routeMethod];
300
+ const defaultOptionsForThisMethod = ctx.options.defaultOptions?.[routeMethod] && { ...ctx.options.defaultOptions[routeMethod] };
290
301
  const { schema: routeSpecs, components = {} } = await getSpec(
291
302
  middlewareHandler,
292
303
  defaultOptionsForThisMethod
@@ -346,7 +357,7 @@ async function getSpec(middlewareHandler, defaultOptions) {
346
357
  return { schema: tmp, components };
347
358
  }
348
359
  const result = await middlewareHandler.toOpenAPISchema();
349
- const docs = defaultOptions ?? {};
360
+ const docs = { ...defaultOptions };
350
361
  if (middlewareHandler.target === "form" || middlewareHandler.target === "json") {
351
362
  const media = middlewareHandler.options?.media ?? middlewareHandler.target === "json" ? "application/json" : "multipart/form-data";
352
363
  if (!docs.requestBody || !("content" in docs.requestBody) || !docs.requestBody.content) {
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { findTargetHandler } from 'hono/utils/handler';
1
2
  import { sValidator } from '@hono/standard-validator';
2
3
  import { loadVendor as loadVendor$1, toJsonSchema } from '@standard-community/standard-json';
3
4
  import { loadVendor as loadVendor$2, toOpenAPISchema } from '@standard-community/standard-openapi';
@@ -13,8 +14,8 @@ const ALLOWED_METHODS = [
13
14
  "PATCH",
14
15
  "TRACE"
15
16
  ];
16
- const toOpenAPIPath = (path) => path.split("/").map((x) => {
17
- let tmp = x;
17
+ const toOpenAPIPathSegment = (segment) => {
18
+ let tmp = segment;
18
19
  if (tmp.startsWith(":")) {
19
20
  const match = tmp.match(/^:([^{?]+)(?:{(.+)})?(\?)?$/);
20
21
  if (match) {
@@ -27,16 +28,18 @@ const toOpenAPIPath = (path) => path.split("/").map((x) => {
27
28
  }
28
29
  }
29
30
  return tmp;
30
- }).join("/");
31
- const capitalize = (word) => word.charAt(0).toUpperCase() + word.slice(1);
31
+ };
32
+ const toOpenAPIPath = (path) => path.split("/").map(toOpenAPIPathSegment).join("/");
33
+ const toPascalCase = (text) => text.split(/[\W_]+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
32
34
  const generateOperationId = (route) => {
33
35
  let operationId = route.method.toLowerCase();
34
36
  if (route.path === "/") return `${operationId}Index`;
35
37
  for (const segment of route.path.split("/")) {
36
- if (segment.charCodeAt(0) === 123) {
37
- operationId += `By${capitalize(segment.slice(1, -1))}`;
38
+ const openApiPathSegment = toOpenAPIPathSegment(segment);
39
+ if (openApiPathSegment.charCodeAt(0) === 123) {
40
+ operationId += `By${toPascalCase(openApiPathSegment.slice(1, -1))}`;
38
41
  } else {
39
- operationId += capitalize(segment);
42
+ operationId += toPascalCase(openApiPathSegment);
40
43
  }
41
44
  }
42
45
  return operationId;
@@ -194,7 +197,15 @@ function removeExcludedPaths(paths, ctx) {
194
197
  };
195
198
  }
196
199
  }
197
- newPaths[key] = value;
200
+ const filteredValue = {};
201
+ for (const method of Object.keys(value)) {
202
+ if (value[method] != null) {
203
+ filteredValue[method] = value[method];
204
+ }
205
+ }
206
+ if (Object.keys(filteredValue).length > 0) {
207
+ newPaths[key] = filteredValue;
208
+ }
198
209
  }
199
210
  return newPaths;
200
211
  }
@@ -265,7 +276,7 @@ async function generateSpecs(hono, options = DEFAULT_OPTIONS, c) {
265
276
  async function generatePaths(hono, ctx) {
266
277
  const paths = {};
267
278
  for (const route of hono.routes) {
268
- const middlewareHandler = route.handler[uniqueSymbol];
279
+ const middlewareHandler = findTargetHandler(route.handler)[uniqueSymbol];
269
280
  if (!middlewareHandler) {
270
281
  if (ctx.options.includeEmptyPaths) {
271
282
  registerSchemaPath({
@@ -284,7 +295,7 @@ async function generatePaths(hono, ctx) {
284
295
  continue;
285
296
  }
286
297
  }
287
- const defaultOptionsForThisMethod = ctx.options.defaultOptions?.[routeMethod];
298
+ const defaultOptionsForThisMethod = ctx.options.defaultOptions?.[routeMethod] && { ...ctx.options.defaultOptions[routeMethod] };
288
299
  const { schema: routeSpecs, components = {} } = await getSpec(
289
300
  middlewareHandler,
290
301
  defaultOptionsForThisMethod
@@ -344,7 +355,7 @@ async function getSpec(middlewareHandler, defaultOptions) {
344
355
  return { schema: tmp, components };
345
356
  }
346
357
  const result = await middlewareHandler.toOpenAPISchema();
347
- const docs = defaultOptions ?? {};
358
+ const docs = { ...defaultOptions };
348
359
  if (middlewareHandler.target === "form" || middlewareHandler.target === "json") {
349
360
  const media = middlewareHandler.options?.media ?? middlewareHandler.target === "json" ? "application/json" : "multipart/form-data";
350
361
  if (!docs.requestBody || !("content" in docs.requestBody) || !docs.requestBody.content) {
package/package.json CHANGED
@@ -1,84 +1,86 @@
1
- {
2
- "name": "hono-openapi",
3
- "description": "OpenAPI schema generator for Hono",
4
- "version": "1.1.2",
5
- "type": "module",
6
- "main": "dist/index.cjs",
7
- "module": "dist/index.js",
8
- "types": "dist/index.d.ts",
9
- "files": [
10
- "dist"
11
- ],
12
- "license": "MIT",
13
- "keywords": [
14
- "hono",
15
- "openapi",
16
- "zod",
17
- "valibot",
18
- "typebox",
19
- "arktype",
20
- "effect"
21
- ],
22
- "homepage": "https://github.com/rhinobase/hono-openapi",
23
- "publishConfig": {
24
- "access": "public"
25
- },
26
- "repository": {
27
- "type": "git",
28
- "url": "git+https://github.com/rhinobase/hono-openapi.git"
29
- },
30
- "bugs": {
31
- "url": "https://github.com/rhinobase/hono-openapi/issues"
32
- },
33
- "exports": {
34
- "import": {
35
- "types": "./dist/index.d.ts",
36
- "default": "./dist/index.js"
37
- },
38
- "require": {
39
- "types": "./dist/index.d.cts",
40
- "default": "./dist/index.cjs"
41
- }
42
- },
43
- "peerDependencies": {
44
- "@hono/standard-validator": "^0.2.0",
45
- "@standard-community/standard-json": "^0.3.5",
46
- "@standard-community/standard-openapi": "^0.2.9",
47
- "@types/json-schema": "^7.0.15",
48
- "hono": "^4.8.3",
49
- "openapi-types": "^12.1.3"
50
- },
51
- "peerDependenciesMeta": {
52
- "@hono/standard-validator": {
53
- "optional": true
54
- },
55
- "hono": {
56
- "optional": true
57
- }
58
- },
59
- "devDependencies": {
60
- "@biomejs/biome": "^2.0.6",
61
- "@standard-schema/spec": "^1.0.0",
62
- "@valibot/to-json-schema": "^1.3.0",
63
- "arktype": "^2.1.22",
64
- "effect": "^3.17.13",
65
- "husky": "^9.1.7",
66
- "is-ci": "^4.1.0",
67
- "nano-staged": "^0.8.0",
68
- "pkg-pr-new": "^0.0.60",
69
- "pkgroll": "^2.13.1",
70
- "typebox": "^1.0.17",
71
- "typescript": "^5.8.3",
72
- "sury": "^10.0.0",
73
- "valibot": "^1.1.0",
74
- "vitest": "^3.2.4",
75
- "zod": "^3.23.8",
76
- "zod-openapi": "^4"
77
- },
78
- "scripts": {
79
- "build": "pkgroll --clean-dist",
80
- "lint": "biome check .",
81
- "format": "biome check --write .",
82
- "test": "vitest"
83
- }
84
- }
1
+ {
2
+ "name": "hono-openapi",
3
+ "description": "OpenAPI schema generator for Hono",
4
+ "version": "1.2.0",
5
+ "type": "module",
6
+ "main": "dist/index.cjs",
7
+ "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "license": "MIT",
13
+ "scripts": {
14
+ "build": "pkgroll --clean-dist",
15
+ "lint": "biome check .",
16
+ "format": "biome check --write .",
17
+ "prepare": "is-ci || husky",
18
+ "test": "vitest"
19
+ },
20
+ "keywords": [
21
+ "hono",
22
+ "openapi",
23
+ "zod",
24
+ "valibot",
25
+ "typebox",
26
+ "arktype",
27
+ "effect"
28
+ ],
29
+ "homepage": "https://github.com/rhinobase/hono-openapi",
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/rhinobase/hono-openapi.git"
36
+ },
37
+ "bugs": {
38
+ "url": "https://github.com/rhinobase/hono-openapi/issues"
39
+ },
40
+ "exports": {
41
+ "import": {
42
+ "types": "./dist/index.d.ts",
43
+ "default": "./dist/index.js"
44
+ },
45
+ "require": {
46
+ "types": "./dist/index.d.cts",
47
+ "default": "./dist/index.cjs"
48
+ }
49
+ },
50
+ "peerDependencies": {
51
+ "@hono/standard-validator": "^0.2.0",
52
+ "@standard-community/standard-json": "^0.3.5",
53
+ "@standard-community/standard-openapi": "^0.2.9",
54
+ "@types/json-schema": "^7.0.15",
55
+ "hono": "^4.8.3",
56
+ "openapi-types": "^12.1.3"
57
+ },
58
+ "peerDependenciesMeta": {
59
+ "@hono/standard-validator": {
60
+ "optional": true
61
+ },
62
+ "hono": {
63
+ "optional": true
64
+ }
65
+ },
66
+ "devDependencies": {
67
+ "@biomejs/biome": "^2.0.6",
68
+ "@standard-schema/spec": "^1.0.0",
69
+ "@valibot/to-json-schema": "^1.3.0",
70
+ "arktype": "^2.1.22",
71
+ "effect": "^3.17.13",
72
+ "husky": "^9.1.7",
73
+ "is-ci": "^4.1.0",
74
+ "nano-staged": "^0.8.0",
75
+ "pkg-pr-new": "^0.0.60",
76
+ "pkgroll": "^2.13.1",
77
+ "typebox": "^1.0.17",
78
+ "typescript": "^5.8.3",
79
+ "sury": "^10.0.0",
80
+ "valibot": "^1.1.0",
81
+ "vitest": "^3.2.4",
82
+ "zod": "^3.23.8",
83
+ "zod-openapi": "^4"
84
+ },
85
+ "packageManager": "pnpm@10.0.0"
86
+ }