feat(swagger-uri): Add Full Configuration Parameters and Update Dependencies (#618)

* chore(swagger-ui): update swagger-ui-dist types

* feat(swagger-ui): add swagger-ui parameters

* chore(swagger-ui): fix typeerror

add url parameter

* chore(swagger-ui): refactor test case

* chore: add versioning doc

* chore(swagger-ui): remove useUnsafeMarkdown

* chore(swagger-ui): add requestSnippetsEnabled

* chore(swagger-ui): syntaxHighlight: boolean

* chore(swagger-ui): fix propertykey

* chore(swagger-ui): format code

* chore(swagger-ui): add string function property commented
pull/629/head
naporitan 2024-07-10 10:20:52 +09:00 committed by GitHub
parent 61cd9b6a57
commit 47be5c6956
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 255 additions and 170 deletions

View File

@ -0,0 +1,5 @@
---
'@hono/swagger-ui': minor
---
Add Full Configuration Parameters and Update Dependencies for Swagger UI

View File

@ -41,7 +41,7 @@
"hono": "*"
},
"devDependencies": {
"@types/swagger-ui-dist": "^3.30.3",
"@types/swagger-ui-dist": "^3.30.5",
"hono": "^3.11.7",
"publint": "^0.2.2",
"tsup": "^7.2.0",

View File

@ -14,17 +14,60 @@ export type DistSwaggerUIOptions = {
layout?: SwaggerConfigs['layout']
docExpansion?: SwaggerConfigs['docExpansion']
maxDisplayedTags?: SwaggerConfigs['maxDisplayedTags']
/**
* accepts function as a string.
*
* @example (a, b) => a.path.localeCompare(b.path)
*/
operationsSorter?: string
/**
* accepts function as a string.
*
* @example (req) => req
*/
requestInterceptor?: string
/**
* accepts function as a string.
*
* @example (res) => res
*/
responseInterceptor?: string
persistAuthorization?: boolean
defaultModelsExpandDepth?: number
defaultModelExpandDepth?: number
defaultModelRendering?: "example" | "model" | undefined
defaultModelRendering?: 'example' | 'model' | undefined
displayRequestDuration?: boolean
filter?: boolean | string
showExtensions?: boolean
showCommonExtensions?: boolean
queryConfigEnabled?: boolean
displayOperationId?: boolean
/**
* accepts function as a string.
* swagger-ui accepts alpha in the tagsSorter, but this middleware does not support it.
*
* @example (a, b) => a.name.localeCompare(b.name)
*/
tagsSorter?: string
/**
* accepts function as a string.
* @example () => { console.log('Swagger UI Loaded'); }
*/
onComplete?: string
syntaxHighlight?: boolean | { activated: boolean; theme: string[] }
tryItOutEnabled?: boolean
requestSnippetsEnabled?: boolean
requestSnippets?: object
oauth2RedirectUrl?: string
showMutabledRequest?: boolean
request?: {
curlOptions?: string[]
}
supportedSubmitMethods?: string[]
validatorUrl?: string
withCredentials?: boolean
modelPropertyMacro?: string
parameterMacro?: string
} & RequireOne<{
url?: SwaggerConfigs['url']
urls?: SwaggerConfigs['urls']
@ -59,6 +102,22 @@ const RENDER_TYPE_MAP = {
filter: RENDER_TYPE.RAW,
showExtensions: RENDER_TYPE.RAW,
showCommonExtensions: RENDER_TYPE.RAW,
queryConfigEnabled: RENDER_TYPE.RAW,
displayOperationId: RENDER_TYPE.RAW,
tagsSorter: RENDER_TYPE.RAW,
onComplete: RENDER_TYPE.RAW,
syntaxHighlight: RENDER_TYPE.JSON_STRING,
tryItOutEnabled: RENDER_TYPE.RAW,
requestSnippetsEnabled: RENDER_TYPE.RAW,
requestSnippets: RENDER_TYPE.JSON_STRING,
oauth2RedirectUrl: RENDER_TYPE.STRING,
showMutabledRequest: RENDER_TYPE.RAW,
request: RENDER_TYPE.JSON_STRING,
supportedSubmitMethods: RENDER_TYPE.JSON_STRING,
validatorUrl: RENDER_TYPE.STRING,
withCredentials: RENDER_TYPE.RAW,
modelPropertyMacro: RENDER_TYPE.RAW,
parameterMacro: RENDER_TYPE.RAW,
} as const satisfies Record<
keyof DistSwaggerUIOptions,
(typeof RENDER_TYPE)[keyof typeof RENDER_TYPE]

View File

@ -1,174 +1,195 @@
/*eslint quotes: ["off", "single"]*/
import type { DistSwaggerUIOptions } from '../src/swagger/renderer'
import { renderSwaggerUIOptions } from '../src/swagger/renderer'
type TestCase = [description: string, config: DistSwaggerUIOptions, expected: string]
describe('SwaggerUIOption Rendering', () => {
it('renders correctly with configUrl', () =>
expect(
renderSwaggerUIOptions({
configUrl: 'https://petstore3.swagger.io/api/v3/openapi.json',
})
).toEqual("configUrl: 'https://petstore3.swagger.io/api/v3/openapi.json'"))
it('renders correctly with presets', () =>
expect(
renderSwaggerUIOptions({
presets: ['SwaggerUIBundle.presets.apis', 'SwaggerUIStandalonePreset'],
})
).toEqual('presets: [SwaggerUIBundle.presets.apis,SwaggerUIStandalonePreset]'))
it('renders correctly with plugins', () =>
expect(
renderSwaggerUIOptions({
plugins: ['SwaggerUIBundle.plugins.DownloadUrl'],
})
).toEqual('plugins: [SwaggerUIBundle.plugins.DownloadUrl]'))
it('renders correctly with deepLinking', () =>
expect(
renderSwaggerUIOptions({
deepLinking: true,
})
).toEqual('deepLinking: true'))
it('renders correctly with spec', () =>
expect(
renderSwaggerUIOptions({
const baseUrl = 'https://petstore3.swagger.io/api/v3/openapi.json'
const commonTests: TestCase[] = [
[
'configUrl',
{ configUrl: baseUrl, url: baseUrl },
`configUrl: '${baseUrl}',url: '${baseUrl}'`,
],
[
'presets',
{ presets: ['SwaggerUIBundle.presets.apis', 'SwaggerUIStandalonePreset'], url: baseUrl },
`presets: [SwaggerUIBundle.presets.apis,SwaggerUIStandalonePreset],url: '${baseUrl}'`,
],
[
'plugins',
{ plugins: ['SwaggerUIBundle.plugins.DownloadUrl'], url: baseUrl },
`plugins: [SwaggerUIBundle.plugins.DownloadUrl],url: '${baseUrl}'`,
],
['deepLinking', { deepLinking: true, url: baseUrl }, `deepLinking: true,url: '${baseUrl}'`],
[
'spec',
{
spec: {
openapi: '3.0.0',
info: {
title: 'Swagger Petstore',
version: '1.0.0',
},
servers: [
{
url: 'https://petstore3.swagger.io/api/v3',
},
],
info: { title: 'Swagger Petstore', version: '1.0.0' },
servers: [{ url: 'https://petstore3.swagger.io/api/v3' }],
},
})
).toEqual(
'spec: {"openapi":"3.0.0","info":{"title":"Swagger Petstore","version":"1.0.0"},"servers":[{"url":"https://petstore3.swagger.io/api/v3"}]}'
))
url: baseUrl,
},
`spec: {"openapi":"3.0.0","info":{"title":"Swagger Petstore","version":"1.0.0"},"servers":[{"url":"https://petstore3.swagger.io/api/v3"}]},url: '${baseUrl}'`,
],
[
'layout',
{ layout: 'StandaloneLayout', url: baseUrl },
`layout: 'StandaloneLayout',url: '${baseUrl}'`,
],
[
'docExpansion',
{ docExpansion: 'list', url: baseUrl },
`docExpansion: 'list',url: '${baseUrl}'`,
],
[
'maxDisplayedTags',
{ maxDisplayedTags: 5, url: baseUrl },
`maxDisplayedTags: 5,url: '${baseUrl}'`,
],
[
'operationsSorter',
{ operationsSorter: '(a, b) => a.path.localeCompare(b.path)', url: baseUrl },
`operationsSorter: (a, b) => a.path.localeCompare(b.path),url: '${baseUrl}'`,
],
[
'requestInterceptor',
{ requestInterceptor: '(req) => req', url: baseUrl },
`requestInterceptor: (req) => req,url: '${baseUrl}'`,
],
[
'responseInterceptor',
{ responseInterceptor: '(res) => res', url: baseUrl },
`responseInterceptor: (res) => res,url: '${baseUrl}'`,
],
[
'persistAuthorization',
{ persistAuthorization: true, url: baseUrl },
`persistAuthorization: true,url: '${baseUrl}'`,
],
[
'defaultModelsExpandDepth',
{ defaultModelsExpandDepth: 1, url: baseUrl },
`defaultModelsExpandDepth: 1,url: '${baseUrl}'`,
],
[
'defaultModelExpandDepth',
{ defaultModelExpandDepth: 2, url: baseUrl },
`defaultModelExpandDepth: 2,url: '${baseUrl}'`,
],
[
'defaultModelRendering',
{ defaultModelRendering: 'model', url: baseUrl },
`defaultModelRendering: 'model',url: '${baseUrl}'`,
],
[
'displayRequestDuration',
{ displayRequestDuration: true, url: baseUrl },
`displayRequestDuration: true,url: '${baseUrl}'`,
],
['filter', { filter: true, url: baseUrl }, `filter: true,url: '${baseUrl}'`],
[
'showExtensions',
{ showExtensions: true, url: baseUrl },
`showExtensions: true,url: '${baseUrl}'`,
],
[
'showCommonExtensions',
{ showCommonExtensions: true, url: baseUrl },
`showCommonExtensions: true,url: '${baseUrl}'`,
],
[
'queryConfigEnabled',
{ queryConfigEnabled: true, url: baseUrl },
`queryConfigEnabled: true,url: '${baseUrl}'`,
],
[
'displayOperationId',
{ displayOperationId: true, url: baseUrl },
`displayOperationId: true,url: '${baseUrl}'`,
],
[
'tagsSorter',
{ tagsSorter: '(a, b) => a.name.localeCompare(b.name)', url: baseUrl },
`tagsSorter: (a, b) => a.name.localeCompare(b.name),url: '${baseUrl}'`,
],
[
'onComplete',
{ onComplete: '() => console.log("Completed")', url: baseUrl },
`onComplete: () => console.log("Completed"),url: '${baseUrl}'`,
],
[
'syntaxHighlight as false',
{ syntaxHighlight: false, url: baseUrl },
`syntaxHighlight: false,url: '${baseUrl}'`,
],
[
'syntaxHighlight as object',
{ syntaxHighlight: { activated: true, theme: ['agate', 'arta'] }, url: baseUrl },
`syntaxHighlight: {"activated":true,"theme":["agate","arta"]},url: '${baseUrl}'`,
],
[
'tryItOutEnabled',
{ tryItOutEnabled: true, url: baseUrl },
`tryItOutEnabled: true,url: '${baseUrl}'`,
],
[
'requestSnippetsEnabled',
{ requestSnippetsEnabled: true, url: baseUrl },
`requestSnippetsEnabled: true,url: '${baseUrl}'`,
],
[
'requestSnippets',
{ requestSnippets: { generators: { curl_bash: { title: 'cURL (bash)' } } }, url: baseUrl },
`requestSnippets: {"generators":{"curl_bash":{"title":"cURL (bash)"}}},url: '${baseUrl}'`,
],
[
'oauth2RedirectUrl',
{ oauth2RedirectUrl: 'https://example.com/oauth2-redirect.html', url: baseUrl },
`oauth2RedirectUrl: 'https://example.com/oauth2-redirect.html',url: '${baseUrl}'`,
],
[
'showMutableRequest',
{ showMutabledRequest: true, url: baseUrl },
`showMutabledRequest: true,url: '${baseUrl}'`,
],
[
'request',
{ request: { curlOptions: ['--insecure'] }, url: baseUrl },
`request: {"curlOptions":["--insecure"]},url: '${baseUrl}'`,
],
[
'supportedSubmitMethods',
{ supportedSubmitMethods: ['get', 'post', 'put'], url: baseUrl },
`supportedSubmitMethods: ["get","post","put"],url: '${baseUrl}'`,
],
[
'validatorUrl',
{ validatorUrl: 'https://validator.swagger.io', url: baseUrl },
`validatorUrl: 'https://validator.swagger.io',url: '${baseUrl}'`,
],
[
'withCredentials',
{ withCredentials: true, url: baseUrl },
`withCredentials: true,url: '${baseUrl}'`,
],
[
'modelPropertyMacro',
{ modelPropertyMacro: '(property) => property', url: baseUrl },
`modelPropertyMacro: (property) => property,url: '${baseUrl}'`,
],
[
'parameterMacro',
{ parameterMacro: '(parameter) => parameter', url: baseUrl },
`parameterMacro: (parameter) => parameter,url: '${baseUrl}'`,
],
]
it('renders correctly with url', () => {
expect(
renderSwaggerUIOptions({
url: 'https://petstore3.swagger.io/api/v3/openapi.json',
})
).toEqual("url: 'https://petstore3.swagger.io/api/v3/openapi.json'")
it.each(commonTests)('renders correctly with %s', (_, input, expected) => {
expect(renderSwaggerUIOptions(input)).toEqual(expected)
})
it('renders correctly with urls', () => {
expect(
renderSwaggerUIOptions({
urls: [
{
name: 'Petstore',
url: 'https://petstore3.swagger.io/api/v3/openapi.json',
},
],
})
).toEqual(
'urls: [{"name":"Petstore","url":"https://petstore3.swagger.io/api/v3/openapi.json"}]'
)
})
it('renders correctly with layout', () =>
expect(
renderSwaggerUIOptions({
layout: 'StandaloneLayout',
})
).toEqual("layout: 'StandaloneLayout'"))
it('renders correctly with docExpansion', () =>
expect(
renderSwaggerUIOptions({
docExpansion: 'list',
})
).toEqual("docExpansion: 'list'"))
it('renders correctly with maxDisplayedTags', () =>
expect(
renderSwaggerUIOptions({
maxDisplayedTags: 5,
})
).toEqual('maxDisplayedTags: 5'))
it('renders correctly with operationsSorter', () =>
expect(
renderSwaggerUIOptions({
operationsSorter: '(a, b) => a.path.localeCompare(b.path)',
})
).toEqual('operationsSorter: (a, b) => a.path.localeCompare(b.path)'))
it('renders correctly with requestInterceptor', () =>
expect(
renderSwaggerUIOptions({
requestInterceptor: '(req) => req',
})
).toEqual('requestInterceptor: (req) => req'))
it('renders correctly with responseInterceptor', () =>
expect(
renderSwaggerUIOptions({
responseInterceptor: '(res) => res',
})
).toEqual('responseInterceptor: (res) => res'))
it('renders correctly with persistAuthorization', () =>
expect(
renderSwaggerUIOptions({
persistAuthorization: true,
})
).toEqual('persistAuthorization: true'))
it('renders correctly with defaultModelsExpandDepth', () =>
expect(
renderSwaggerUIOptions({
defaultModelsExpandDepth: 1,
})
).toEqual('defaultModelsExpandDepth: 1'))
it('renders correctly with defaultModelExpandDepth', () =>
expect(
renderSwaggerUIOptions({
defaultModelExpandDepth: 2,
})
).toEqual('defaultModelExpandDepth: 2'))
it('renders correctly with defaultModelRendering', () =>
expect(
renderSwaggerUIOptions({
defaultModelRendering: 'model',
})
).toEqual("defaultModelRendering: 'model'"))
it('renders correctly with displayRequestDuration', () =>
expect(
renderSwaggerUIOptions({
displayRequestDuration: true,
})
).toEqual('displayRequestDuration: true'))
it('renders correctly with filter', () =>
expect(
renderSwaggerUIOptions({
filter: true,
})
).toEqual('filter: true'))
it('renders correctly with showExtensions', () =>
expect(
renderSwaggerUIOptions({
showExtensions: true,
})
).toEqual('showExtensions: true'))
it('renders correctly with showCommonExtensions', () =>
expect(
renderSwaggerUIOptions({
showCommonExtensions: true,
})
).toEqual('showCommonExtensions: true'))
})

View File

@ -2278,7 +2278,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@hono/swagger-ui@workspace:packages/swagger-ui"
dependencies:
"@types/swagger-ui-dist": "npm:^3.30.3"
"@types/swagger-ui-dist": "npm:^3.30.5"
hono: "npm:^3.11.7"
publint: "npm:^0.2.2"
tsup: "npm:^7.2.0"
@ -4352,10 +4352,10 @@ __metadata:
languageName: node
linkType: hard
"@types/swagger-ui-dist@npm:^3.30.3":
version: 3.30.4
resolution: "@types/swagger-ui-dist@npm:3.30.4"
checksum: 106114fef47a29811a37810e00e52d3fb6f99bafa7ec00b49926827a9c502b27550e2de589af000e472d327c3fc32417f75befa37b2450e8fad81e0a79ad641f
"@types/swagger-ui-dist@npm:^3.30.5":
version: 3.30.5
resolution: "@types/swagger-ui-dist@npm:3.30.5"
checksum: 0e6ea1b6add4fb9cfd82dcdbd8156b3d0921a6bd2d511b92c05fc6d76e94a78d89eab81ffd6bb34c0c52e97b5e4a61eea77fab502698e9cf170aabf5d2c09510
languageName: node
linkType: hard