Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/swagger-ui-urls-standalone-preset.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hono/swagger-ui': patch
---

Load the standalone preset when `urls` is set so the first definition loads and can be switched from the top bar
3 changes: 0 additions & 3 deletions packages/swagger-ui/eslint-suppressions.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
"src/index.ts": {
"@typescript-eslint/no-base-to-string": {
"count": 2
},
"@typescript-eslint/restrict-template-expressions": {
"count": 2
}
},
"src/swagger/renderer.ts": {
Expand Down
23 changes: 21 additions & 2 deletions packages/swagger-ui/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,37 @@ describe('SwaggerUI Rendering', () => {
<div>
<div id="swagger-ui"></div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist/swagger-ui.css" />
<script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist/swagger-ui-bundle.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist/swagger-ui-bundle.js" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist/swagger-ui-standalone-preset.js" crossorigin="anonymous"></script>
<script>
window.onload = () => {
window.ui = SwaggerUIBundle({
dom_id: '#swagger-ui',urls: [{"name":"Petstore","url":"${url}"}],
dom_id: '#swagger-ui',urls: [{"name":"Petstore","url":"${url}"}],presets: [SwaggerUIBundle.presets.apis,SwaggerUIStandalonePreset],layout: "StandaloneLayout",
})
}
</script>
</div>
`)
})

it('keeps user-provided presets and layout when using urls', () => {
const html = SwaggerUI({
urls: [{ name: 'Petstore', url }],
presets: ['SwaggerUIStandalonePreset'],
layout: 'BaseLayout',
})
expect(html).toContain('swagger-ui-standalone-preset.js')
expect(html).toContain('presets: [SwaggerUIStandalonePreset]')
expect(html).toContain('layout: "BaseLayout"')
expect(html).not.toContain('StandaloneLayout')
})

it('does not load the standalone preset when only url is given', () => {
const html = SwaggerUI({ url })
expect(html).not.toContain('swagger-ui-standalone-preset.js')
expect(html).not.toContain('presets:')
expect(html).not.toContain('layout:')
})

it('renders correctly with custom UI', () => {
expect(
SwaggerUI({
Expand Down
26 changes: 17 additions & 9 deletions packages/swagger-ui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,30 @@ type OriginalSwaggerUIOptions = {
type SwaggerUIOptions = OriginalSwaggerUIOptions & DistSwaggerUIOptions

const SwaggerUI = ({ baseUrl, version, ...options }: SwaggerUIOptions): string => {
const asset = remoteAssets({
baseUrl: baseUrl,
version: version,
})

if (options.manuallySwaggerUIHtml) {
return options.manuallySwaggerUIHtml(asset)
return options.manuallySwaggerUIHtml(remoteAssets({ baseUrl, version }))
}

const optionsStrings = renderSwaggerUIOptions(options)
// Swagger UI only loads a definition from `urls` through the TopBar plugin,
// which ships in the standalone preset, so enable it when `urls` is given.
const useStandalonePreset = options.urls !== undefined
const asset = remoteAssets({ baseUrl, version, standalonePreset: useStandalonePreset })

const optionsStrings = renderSwaggerUIOptions(
useStandalonePreset
? {
...options,
presets: options.presets ?? ['SwaggerUIBundle.presets.apis', 'SwaggerUIStandalonePreset'],
layout: options.layout ?? 'StandaloneLayout',
}
: 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>`)}
${asset.css.map((url) => html`<link rel="stylesheet" href="${url}" />`).join('')}
${asset.js.map((url) => html`<script src="${url}" crossorigin="anonymous"></script>`).join('')}
<script>
window.onload = () => {
window.ui = SwaggerUIBundle({
Expand Down
8 changes: 8 additions & 0 deletions packages/swagger-ui/src/remote-assets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ describe('remoteAssets', () => {
expect(assets.js).toEqual([`${baseUrl}/swagger-ui-dist/swagger-ui-bundle.js`])
})

it('should add the standalone preset script when standalonePreset is true', () => {
const assets = remoteAssets({ version: '5.0.0', standalonePreset: true })
expect(assets.js).toEqual([
'https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.0.0/swagger-ui-bundle.js',
'https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.0.0/swagger-ui-standalone-preset.js',
])
})

it('should support baseUrl with version', () => {
const baseUrl = 'https://unpkg.com'
const version = '5.0.0'
Expand Down
10 changes: 9 additions & 1 deletion packages/swagger-ui/src/swagger/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,26 @@ type ResourceConfig = {
/** CDN base URL, e.g. https://unpkg.com for internal network mirror */
baseUrl?: string
version?: string
/** Also load `swagger-ui-standalone-preset.js`, which provides `SwaggerUIStandalonePreset` */
standalonePreset?: boolean
}

export const remoteAssets = ({
baseUrl = DEFAULT_CDN_BASE,
version,
standalonePreset = false,
}: ResourceConfig): AssetURLs => {
const url = `${baseUrl.replace(/\/$/, '')}/swagger-ui-dist${
version !== undefined ? `@${version}` : ''
}`

const js = [`${url}/swagger-ui-bundle.js`]
if (standalonePreset) {
js.push(`${url}/swagger-ui-standalone-preset.js`)
}

return {
css: [`${url}/swagger-ui.css`],
js: [`${url}/swagger-ui-bundle.js`],
js,
}
}
Loading