honojs-middleware/packages/swagger-ui/src/index.ts

90 lines
2.7 KiB
TypeScript
Raw Normal View History

import type { Env, MiddlewareHandler } from 'hono'
import { html } from 'hono/html'
import type { DistSwaggerUIOptions } from './swagger/renderer'
import { renderSwaggerUIOptions } from './swagger/renderer'
import type { AssetURLs } from './swagger/resource'
import { remoteAssets } from './swagger/resource'
type OriginalSwaggerUIOptions = {
version?: string
/**
* manuallySwaggerUIHtml is a string that is used to render SwaggerUI.
* If this is set, all other options will be ignored except version.
* The string will be inserted into the body of the HTML.
* This is useful when you want to fully customize the UI.
*
* @example
* ```ts
* const swaggerUI = SwaggerUI({
* manuallySwaggerUIHtml: (asset) => `
* <div>
* <div id="swagger-ui"></div>
* ${asset.css.map((url) => `<link rel="stylesheet" href="${url}" />`)}
* ${asset.js.map((url) => `<script src="${url}" crossorigin="anonymous"></script>`)}
* <script>
* window.onload = () => {
* window.ui = SwaggerUIBundle({
* dom_id: '#swagger-ui',
* url: 'https://petstore.swagger.io/v2/swagger.json',
* })
* }
* </script>
* </div>
* `,
* })
* ```
*/
manuallySwaggerUIHtml?: (asset: AssetURLs) => string
title?: string
}
type SwaggerUIOptions = OriginalSwaggerUIOptions & DistSwaggerUIOptions
const SwaggerUI = (options: SwaggerUIOptions): string => {
const asset = remoteAssets({ version: options?.version })
delete options.version
if (options.manuallySwaggerUIHtml) {
return options.manuallySwaggerUIHtml(asset)
}
const optionsStrings = renderSwaggerUIOptions(options)
return `
<div>
<div id="swagger-ui"></div>
${asset.css.map((url) => html`<link rel="stylesheet" href="${url}" />`)}
${asset.js.map((url) => html`<script src="${url}" crossorigin="anonymous"></script>`)}
<script>
window.onload = () => {
window.ui = SwaggerUIBundle({
dom_id: '#swagger-ui',${optionsStrings},
})
}
</script>
</div>
`
}
const middleware =
<E extends Env>(options: SwaggerUIOptions): MiddlewareHandler<E> =>
async (c) => {
const title = options?.title ?? 'SwaggerUI'
return c.html(/* html */ `
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="SwaggerUI" />
<title>${title}</title>
</head>
<body>
${SwaggerUI(options)}
</body>
</html>
`)
}
export { middleware as swaggerUI, SwaggerUI }
export { SwaggerUIOptions }