hono-openapi 0.4.3 → 0.4.4
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/index.cjs +1 -1
- package/index.js +1 -1
- package/package.json +1 -1
- package/src/index.d.ts +2 -1
- package/src/route.d.ts +5 -1
- package/src/types.d.ts +5 -1
- package/src/utils.d.ts +6 -0
package/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("
|
|
1
|
+
"use strict";var e=require("./utils.cjs"),t=require("hono/http-exception");const n=["GET","PUT","POST","DELETE","OPTIONS","HEAD","PATCH","TRACE"],s=e=>e.charAt(0).toUpperCase()+e.slice(1),o=(e,t)=>{let n=e;if("/"===t)return`${n}Index`;for(const e of t.split("/"))123===e.charCodeAt(0)?n+=`By${s(e.slice(1,-1))}`:n+=s(e);return n};function c({path:e,method:t,data:n,schema:s}){e=(e=>e.split("/").map((e=>{let t=e;return t.startsWith(":")&&(t=t.slice(1,t.length),t.endsWith("?")&&(t=t.slice(0,-1)),t=`{${t}}`),t})).join("/"))(e);const c=t.toLowerCase();s[e]={...s[e]?s[e]:{},[c]:{responses:{},...s[e]?.[c]??{},operationId:o(c,e),...n}}}function a(e,{excludeStaticFile:t=!0,exclude:n=[]}){const s={},o=Array.isArray(n)?n:[n];for(const[n,c]of Object.entries(e))if(!(o.some((e=>"string"==typeof e?n===e:e.test(n)))||n.includes("*")||t&&n.includes("."))){for(const e of Object.keys(c)){const t=c[e];if(n.includes("{")){t.parameters||(t.parameters=[]);const e=n.split("/").filter((e=>e.startsWith("{")&&!t.parameters.find((t=>"path"===t.in&&t.name===e.slice(1,e.length-1)))));for(const n of e){const e=n.slice(1,n.length-1),s=t.parameters.findIndex((t=>"param"===t.in&&t.name===e));-1!==s?t.parameters[s].in="path":t.parameters.push({schema:{type:"string"},in:"path",name:e,required:!0})}}t.responses||(t.responses={200:{}})}s[n]=c}return s}async function i(t,{documentation:s={},excludeStaticFile:o=!0,exclude:i=[],excludeMethods:r=["OPTIONS"],excludeTags:p=[],defaultOptions:l}={documentation:{},excludeStaticFile:!0,exclude:[],excludeMethods:["OPTIONS"],excludeTags:[]},{version:d="3.1.0",components:u={}}={version:"3.1.0",components:{}},m){const h={version:d,components:u},f={};for(const s of t.routes){if(!(e.uniqueSymbol in s.handler))continue;if(r.includes(s.method))continue;if(!1===n.includes(s.method)&&"ALL"!==s.method)continue;const{resolver:t,metadata:o={}}=s.handler[e.uniqueSymbol],a=l?.[s.method],{docs:i,components:p}=await t({...h,...o},a);if(h.components={...h.components,...p??{}},"ALL"===s.method)for(const e of n)c({path:s.path,data:i,method:e,schema:f});else c({method:s.method,path:s.path,data:i,schema:f})}for(const e in f)for(const t in f[e]){const n=f[e][t]?.hide;n&&("boolean"==typeof n?n:m&&n(m))&&delete f[e][t]}return{openapi:h.version,...{...s,tags:s.tags?.filter((e=>!p?.includes(e?.name))),info:{title:"Hono Documentation",description:"Development documentation",version:"0.0.0",...s.info},paths:{...a(f,{excludeStaticFile:o,exclude:i}),...s.paths},components:{...s.components,schemas:{...h.components,...s.components?.schemas}}}}}exports.generateValidatorDocs=e.generateValidatorDocs,exports.uniqueSymbol=e.uniqueSymbol,exports.describeRoute=function(n){const{validateResponse:s,...o}=n;return Object.assign((async(e,o)=>{if(await o(),s&&n.responses){const o=e.res.status,c=e.res.headers.get("content-type");if(o&&c){const a=n.responses[o];if(a&&"content"in a&&a.content){const n=c.split(";")[0],o=a.content[n];if(o?.schema&&"validator"in o.schema)try{let t;const s=e.res.clone();if("application/json"===n?t=await s.json():"text/plain"===n&&(t=await s.text()),!t)throw new Error("No data to validate!");await o.schema.validator(t)}catch(e){let n={status:500,message:"Response validation failed!"};throw"object"==typeof s&&(n={...n,...s}),new t.HTTPException(n.status,{message:n.message,cause:e})}}}}}),{[e.uniqueSymbol]:{resolver:(e,t)=>async function(e,t,n={}){let s={};const o={...n,...t,responses:{...n?.responses,...t.responses}};for(const t of Object.keys(o.responses)){const n=o.responses[t];if(n&&"content"in n)for(const t of Object.keys(n.content??{})){const o=n.content?.[t];if(o&&(o.schema&&"builder"in o.schema)){const t=await o.schema.builder(e);o.schema=t.schema,t.components&&(s={...s,...t.components})}}}return{docs:o,components:s}}(e,o,t)}})},exports.generateSpecs=i,exports.openAPISpecs=function(e,t){const n={version:"3.1.0",components:{}};let s=null;return async o=>(s||(s=await i(e,t,n,o)),o.json(s))};
|
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{u as e}from"./utils.js";export{g as generateValidatorDocs}from"./utils.js";import{HTTPException as t}from"hono/http-exception";const s=["GET","PUT","POST","DELETE","OPTIONS","HEAD","PATCH","TRACE"],n=e=>e.charAt(0).toUpperCase()+e.slice(1),o=(e,t)=>{let s=e;if("/"===t)return`${s}Index`;for(const e of t.split("/"))123===e.charCodeAt(0)?s+=`By${n(e.slice(1,-1))}`:s+=n(e);return s};function a({path:e,method:t,data:s,schema:n}){e=(e=>e.split("/").map((e=>{let t=e;return t.startsWith(":")&&(t=t.slice(1,t.length),t.endsWith("?")&&(t=t.slice(0,-1)),t=`{${t}}`),t})).join("/"))(e);const a=t.toLowerCase();n[e]={...n[e]?n[e]:{},[a]:{responses:{},...n[e]?.[a]??{},operationId:o(a,e),...s}}}function c(e,{excludeStaticFile:t=!0,exclude:s=[]}){const n={},o=Array.isArray(s)?s:[s];for(const[s,a]of Object.entries(e))if(!(o.some((e=>"string"==typeof e?s===e:e.test(s)))||s.includes("*")||t&&s.includes("."))){for(const e of Object.keys(a)){const t=a[e];if(s.includes("{")){t.parameters||(t.parameters=[]);const e=s.split("/").filter((e=>e.startsWith("{")&&!t.parameters.find((t=>"path"===t.in&&t.name===e.slice(1,e.length-1)))));for(const s of e){const e=s.slice(1,s.length-1),n=t.parameters.findIndex((t=>"param"===t.in&&t.name===e));-1!==n?t.parameters[n].in="path":t.parameters.push({schema:{type:"string"},in:"path",name:e,required:!0})}}t.responses||(t.responses={200:{}})}n[s]=a}return n}function i(e,t){const s={version:"3.1.0",components:{}};let n=null;return async o=>(n||(n=await r(e,t,s,o)),o.json(n))}async function r(t,{documentation:n={},excludeStaticFile:o=!0,exclude:i=[],excludeMethods:r=["OPTIONS"],excludeTags:p=[],defaultOptions:l}={documentation:{},excludeStaticFile:!0,exclude:[],excludeMethods:["OPTIONS"],excludeTags:[]},{version:m="3.1.0",components:d={}}={version:"3.1.0",components:{}},h){const u={version:m,components:d},f={};for(const n of t.routes){if(!(e in n.handler))continue;if(r.includes(n.method))continue;if(!1===s.includes(n.method)&&"ALL"!==n.method)continue;const{resolver:t,metadata:o={}}=n.handler[e],c=l?.[n.method],{docs:i,components:p}=await t({...u,...o},c);if(u.components={...u.components,...p??{}},"ALL"===n.method)for(const e of s)a({path:n.path,data:i,method:e,schema:f});else a({method:n.method,path:n.path,data:i,schema:f})}for(const e in f)for(const t in f[e]){const s=f[e][t]?.hide;s&&("boolean"==typeof s?s:h&&s(h))&&delete f[e][t]}return{openapi:u.version,...{...n,tags:n.tags?.filter((e=>!p?.includes(e?.name))),info:{title:"Hono Documentation",description:"Development documentation",version:"0.0.0",...n.info},paths:{...c(f,{excludeStaticFile:o,exclude:i}),...n.paths},components:{...n.components,schemas:{...u.components,...n.components?.schemas}}}}}function p(s){const{validateResponse:n,...o}=s;return Object.assign((async(e,o)=>{if(await o(),n&&s.responses){const o=e.res.status,a=e.res.headers.get("content-type");if(o&&a){const c=s.responses[o];if(c&&"content"in c&&c.content){const s=a.split(";")[0],o=c.content[s];if(o?.schema&&"validator"in o.schema)try{let t;const n=e.res.clone();if("application/json"===s?t=await n.json():"text/plain"===s&&(t=await n.text()),!t)throw new Error("No data to validate!");await o.schema.validator(t)}catch(e){let s={status:500,message:"Response validation failed!"};throw"object"==typeof n&&(s={...s,...n}),new t(s.status,{message:s.message,cause:e})}}}}}),{[e]:{resolver:(e,t)=>async function(e,t,s={}){let n={};const o={...s,...t,responses:{...s?.responses,...t.responses}};for(const t of Object.keys(o.responses)){const s=o.responses[t];if(s&&"content"in s)for(const t of Object.keys(s.content??{})){const o=s.content?.[t];if(o&&(o.schema&&"builder"in o.schema)){const t=await o.schema.builder(e);o.schema=t.schema,t.components&&(n={...n,...t.components})}}}return{docs:o,components:n}}(e,o,t)}})}export{p as describeRoute,r as generateSpecs,i as openAPISpecs,e as uniqueSymbol};
|
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
package/src/route.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { MiddlewareHandler } from "hono/types";
|
|
2
|
+
import type { ClientErrorStatusCode, ServerErrorStatusCode } from "hono/utils/http-status";
|
|
2
3
|
import type { DescribeRouteOptions, OpenAPIRouteHandlerConfig } from "./types.js";
|
|
3
4
|
/**
|
|
4
5
|
* Describe a route with OpenAPI specs.
|
|
@@ -37,7 +38,10 @@ export declare function generateRouteSpecs(config: OpenAPIRouteHandlerConfig, do
|
|
|
37
38
|
security?: import("openapi-types").OpenAPIV3.SecurityRequirementObject[];
|
|
38
39
|
servers?: import("openapi-types").OpenAPIV3.ServerObject[];
|
|
39
40
|
hide?: boolean | (<E extends import("hono").Env = import("hono").Env, P extends string = string, I extends import("hono").Input = import("hono/types").BlankInput>(c: import("hono").Context<E, P, I>) => boolean);
|
|
40
|
-
validateResponse?: boolean
|
|
41
|
+
validateResponse?: boolean | {
|
|
42
|
+
status: ClientErrorStatusCode | ServerErrorStatusCode;
|
|
43
|
+
message?: string;
|
|
44
|
+
};
|
|
41
45
|
};
|
|
42
46
|
components: {};
|
|
43
47
|
}>;
|
package/src/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Context, Env, Input } from "hono";
|
|
2
2
|
import type { BlankInput } from "hono/types";
|
|
3
|
+
import type { ClientErrorStatusCode, ServerErrorStatusCode } from "hono/utils/http-status";
|
|
3
4
|
import type { OpenAPIV3 } from "openapi-types";
|
|
4
5
|
import type { ALLOWED_METHODS } from "./helper.js";
|
|
5
6
|
export type HasUndefined<T> = undefined extends T ? true : false;
|
|
@@ -32,7 +33,10 @@ export type DescribeRouteOptions = Omit<OpenAPIV3.OperationObject, "responses">
|
|
|
32
33
|
/**
|
|
33
34
|
* Validate response of the route
|
|
34
35
|
*/
|
|
35
|
-
validateResponse?: boolean
|
|
36
|
+
validateResponse?: boolean | {
|
|
37
|
+
status: ClientErrorStatusCode | ServerErrorStatusCode;
|
|
38
|
+
message?: string;
|
|
39
|
+
};
|
|
36
40
|
/**
|
|
37
41
|
* Responses of the request
|
|
38
42
|
*/
|
package/src/utils.d.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import type { ValidationTargets } from "hono";
|
|
2
2
|
import type { OpenAPIV3 } from "openapi-types";
|
|
3
3
|
import type { ResolverResult } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* The unique symbol for the middlewares, which makes it easier to identify them. Not meant to be used directly, unless you're creating a custom middleware.
|
|
6
|
+
*/
|
|
4
7
|
export declare const uniqueSymbol: unique symbol;
|
|
8
|
+
/**
|
|
9
|
+
* Generate OpenAPI docs for a validator middleware. Not meant to be used directly, unless you're creating a custom middleware.
|
|
10
|
+
*/
|
|
5
11
|
export declare function generateValidatorDocs<Target extends keyof ValidationTargets>(target: Target, _result: ReturnType<ResolverResult["builder"]>): Promise<{
|
|
6
12
|
docs: Pick<{
|
|
7
13
|
tags?: string[];
|