Spaces:
Paused
Paused
import express from 'express'; | |
import getAbsoluteSwaggerFsPath from "swagger-ui-dist"; | |
const getAbsoluteSwaggerFsPaths = getAbsoluteSwaggerFsPath.getAbsoluteFSPath() | |
var favIconHtml = '<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />' + | |
'<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />'; | |
var swaggerInit = ''; | |
function trimQuery(q) { | |
return q && q.split('?')[0]; | |
} | |
var htmlTplString = ` | |
<!-- HTML for static distribution bundle build --> | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta property="og:type" content="website"> | |
<meta name="apple-mobile-web-app-capable" content="yes"> | |
<% robotsMetaString %> | |
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" > | |
<% favIconString %> | |
<style> | |
html | |
{ | |
box-sizing: border-box; | |
overflow: -moz-scrollbars-vertical; | |
overflow-y: scroll; | |
} | |
*, | |
*:before, | |
*:after | |
{ | |
box-sizing: inherit; | |
} | |
body { | |
margin:0; | |
background: #fafafa; | |
} | |
.swagger-ui section.models h4 span { | |
flex: 1; | |
color: black; | |
} | |
.swagger-ui .model-toggle { | |
cursor: pointer; | |
display: inline-block; | |
font-size: 10px; | |
margin: auto .3em; | |
position: relative; | |
top: 6px; | |
transform: rotate(90deg); | |
transform-origin: 50% 50%; | |
transition: transform .15s ease-in; | |
background-color: white; | |
border-radius: 50%; | |
} | |
.dark-mode body { | |
background-color: #1f1f1f; | |
color: #ffffff; | |
} | |
.dark-mode .swagger-ui { | |
color: #3b4151; | |
background-color: #1f1f1f; | |
} | |
.dark-mode .swagger-ui .topbar { | |
background-color: #131414; | |
} | |
.dark-mode .swagger-ui .info .title { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .opblock-description-wrapper, .swagger-ui .opblock-external-docs-wrapper, .swagger-ui .opblock-title_normal { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .info li, .dark-mode .swagger-ui .info p, .dark-mode .swagger-ui .info table { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .scheme-container { | |
background: #131414; | |
box-shadow: 0 1px 2px 0 rgba(0,0,0,.15); | |
} | |
.dark-mode .swagger-ui .servers-title { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui select { | |
background: #131414 url("data:image/svg+xml;charset=utf-8,<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 20 20\\"><path d=\\"M13.418 7.859a.695.695 0 0 1 .978 0 .68.68 0 0 1 0 .969l-3.908 3.83a.697.697 0 0 1-.979 0l-3.908-3.83a.68.68 0 0 1 0-.969.695.695 0 0 1 .978 0L10 11z\\"/></svg>") right 10px center no-repeat; | |
border: 2px solid #41444e; | |
box-shadow: 0 1px 2px 0 rgba(0,0,0,.25); | |
color: #fff; | |
} | |
.dark-mode .swagger-ui a.nostyle, .dark-mode .swagger-ui a.nostyle:visited { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .opblock-tag small { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .opblock .opblock-summary-description { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .opblock-description-wrapper p, .dark-mode .swagger-ui .opblock-external-docs-wrapper p, .dark-mode .swagger-ui .opblock-title_normal p { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .opblock .opblock-section-header { | |
align-items: center; | |
background: #131414; | |
box-shadow: 0 1px 2px rgba(0,0,0,.1); | |
} | |
.dark-mode .swagger-ui .btn { | |
box-shadow: 0 1px 2px rgba(0,0,0,.1); | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .opblock .opblock-section-header h4 { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .responses-inner h4, .swagger-ui .responses-inner h5 { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui table thead tr td, .dark-mode .swagger-ui table thead tr th { | |
border-bottom: 1px solid rgba(59,65,81,.2); | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .parameter__name { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .parameters-col_description .markdown p, .dark-mode .swagger-ui .parameters-col_description .renderedMarkdown p { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .parameter__type { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .parameter__extension, .dark-mode .swagger-ui .parameter__in { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui input[disabled], .dark-mode .swagger-ui select[disabled], .dark-mode .swagger-ui textarea[disabled] { | |
background-color: #131414; | |
color: #fff; | |
} | |
.dark-mode .swagger-ui input[type="email"], .dark-mode .swagger-ui input[type="file"], .dark-mode .swagger-ui input[type="password"], .dark-mode .swagger-ui input[type="search"], .dark-mode .swagger-ui input[type="text"], .dark-mode .swagger-ui textarea { | |
background: #131414; | |
border: 1px solid #d9d9d9; | |
color: #fff; | |
} | |
.dark-mode .swagger-ui input[type="email"].invalid, .dark-mode .swagger-ui input[type="file"].invalid, .dark-mode .swagger-ui input[type="password"].invalid, .dark-mode .swagger-ui input[type="search"].invalid, .dark-mode .swagger-ui input[type="text"].invalid, .dark-mode .swagger-ui textarea.invalid { | |
background: #400c0c; | |
border-color: #f93e3e; | |
} | |
.dark-mode .swagger-ui .errors-wrapper { | |
background: rgba(249,62,62,.1); | |
border: 2px solid #f93e3e; | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .response-col_status { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .response-col_description .markdown p, .dark-mode .swagger-ui .response-col_description .renderedMarkdown p { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .response-control-examples__title, .dark-mode .swagger-ui .response-control-media-type__title { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .tab li button.tablinks { | |
color: #fff; | |
} | |
.dark-mode .swagger-ui .expand-methods svg, .swagger-ui .expand-operation svg { | |
fill: white; | |
} | |
.dark-mode .swagger-ui svg:not(:root) { | |
fill: white; | |
} | |
.dark-mode .swagger-ui section.models h4 span { | |
color: white; | |
} | |
.dark-mode .swagger-ui .model { | |
color: white; | |
} | |
.dark-mode .swagger-ui .model-title { | |
color: white; | |
} | |
.dark-mode .swagger-ui label { | |
color: white; | |
} | |
.dark-mode .swagger-ui .model-toggle { | |
background-color: white; | |
} | |
.dark-mode .swagger-ui table.model tr.property-row td:first-child { | |
color: white; | |
} | |
.dark-mode .swagger-ui .model-box-control, .swagger-ui .models-control, .swagger-ui .opblock-summary-control { | |
color: white; | |
} | |
.dark-mode .swagger-ui section.models .model-container { | |
background-color: #1a1a1a; | |
} | |
.dark-mode .swagger-ui .info .base-url { | |
color: white; | |
} | |
.dark-mode .swagger-ui .scheme-container .schemes > .schemes-server-container > label { | |
color: white; | |
} | |
</style> | |
</head> | |
<body> | |
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;width:0;height:0"> | |
<defs> | |
<symbol viewBox="0 0 20 20" id="unlocked"> | |
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path> | |
</symbol> | |
<symbol viewBox="0 0 20 20" id="locked"> | |
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z"/> | |
</symbol> | |
<symbol viewBox="0 0 20 20" id="close"> | |
<path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z"/> | |
</symbol> | |
<symbol viewBox="0 0 20 20" id="large-arrow"> | |
<path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z"/> | |
</symbol> | |
<symbol viewBox="0 0 20 20" id="large-arrow-down"> | |
<path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"/> | |
</symbol> | |
<symbol viewBox="0 0 24 24" id="jump-to"> | |
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"/> | |
</symbol> | |
<symbol viewBox="0 0 24 24" id="expand"> | |
<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/> | |
</symbol> | |
</defs> | |
</svg> | |
<div id="swagger-ui"></div> | |
<script src="./swagger-ui-bundle.js"> </script> | |
<script src="./swagger-ui-standalone-preset.js"> </script> | |
<script src="./swagger-ui-init.js"> </script> | |
<% customJs %> | |
<% customJsStr %> | |
<% customCssUrl %> | |
<style> | |
<% customCss %> | |
</style> | |
<script> | |
document.addEventListener('DOMContentLoaded', function() { | |
const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); | |
function updateTheme() { | |
if (darkModeMediaQuery.matches) { | |
document.documentElement.classList.add('dark-mode'); | |
document.documentElement.classList.remove('light-mode'); | |
} else { | |
document.documentElement.classList.remove('dark-mode'); | |
document.documentElement.classList.add('light-mode'); | |
} | |
} | |
darkModeMediaQuery.addListener(updateTheme); | |
updateTheme(); | |
}); | |
</script> | |
</body> | |
</html> | |
` | |
var jsTplString = ` | |
window.onload = function() { | |
// Build a system | |
var url = window.location.search.match(/url=([^&]+)/); | |
if (url && url.length > 1) { | |
url = decodeURIComponent(url[1]); | |
} else { | |
url = window.location.origin; | |
} | |
<% swaggerOptions %> | |
url = options.swaggerUrl || url | |
var urls = options.swaggerUrls | |
var customOptions = options.customOptions | |
var spec1 = options.swaggerDoc | |
var swaggerOptions = { | |
spec: spec1, | |
url: url, | |
urls: urls, | |
dom_id: '#swagger-ui', | |
deepLinking: true, | |
presets: [ | |
SwaggerUIBundle.presets.apis, | |
SwaggerUIStandalonePreset | |
], | |
plugins: [ | |
SwaggerUIBundle.plugins.DownloadUrl | |
], | |
layout: "StandaloneLayout" | |
} | |
for (var attrname in customOptions) { | |
swaggerOptions[attrname] = customOptions[attrname]; | |
} | |
var ui = SwaggerUIBundle(swaggerOptions) | |
if (customOptions.oauth) { | |
ui.initOAuth(customOptions.oauth) | |
} | |
if (customOptions.preauthorizeApiKey) { | |
const key = customOptions.preauthorizeApiKey.authDefinitionKey; | |
const value = customOptions.preauthorizeApiKey.apiKeyValue; | |
if (!!key && !!value) { | |
const pid = setInterval(() => { | |
const authorized = ui.preauthorizeApiKey(key, value); | |
if(!!authorized) clearInterval(pid); | |
}, 500) | |
} | |
} | |
if (customOptions.authAction) { | |
ui.authActions.authorize(customOptions.authAction) | |
} | |
window.ui = ui | |
} | |
` | |
function toExternalScriptTag(url) { | |
return `<script src='${url}'></script>` | |
} | |
function toInlineScriptTag(jsCode) { | |
return `<script>${jsCode}</script>` | |
} | |
function toExternalStylesheetTag(url) { | |
return `<link href='${url}' rel='stylesheet'>` | |
} | |
function toTags(customCode, toScript) { | |
if (typeof customCode === 'string') { | |
return toScript(customCode) | |
} else if (Array.isArray(customCode)) { | |
return customCode.map(toScript).join('\n') | |
} else { | |
return '' | |
} | |
} | |
var generateHTML = function (swaggerDoc, opts, options, customCss, customfavIcon, swaggerUrl, customSiteTitle, _htmlTplString, _jsTplString) { | |
var isExplorer | |
var customJs | |
var customJsStr | |
var swaggerUrls | |
var customCssUrl | |
var customRobots | |
if (opts && typeof opts === 'object') { | |
options = opts.swaggerOptions | |
customCss = opts.customCss | |
customJs = opts.customJs | |
customJsStr = opts.customJsStr | |
customfavIcon = opts.customfavIcon | |
customRobots = opts.customRobots | |
swaggerUrl = opts.swaggerUrl | |
swaggerUrls = opts.swaggerUrls | |
isExplorer = opts.explorer || !!swaggerUrls | |
customSiteTitle = opts.customSiteTitle | |
customCssUrl = opts.customCssUrl | |
} else { | |
//support legacy params based function | |
isExplorer = opts | |
} | |
options = options || {} | |
var explorerString = isExplorer ? '' : '.swagger-ui .topbar .download-url-wrapper { display: none }' | |
customCss = explorerString + ' ' + customCss || explorerString | |
customfavIcon = customfavIcon || false | |
customSiteTitle = customSiteTitle || 'Swagger UI' | |
_htmlTplString = _htmlTplString || htmlTplString | |
_jsTplString = _jsTplString || jsTplString | |
var robotsMetaString = customRobots ? '<meta name="robots" content="' + customRobots + '" />' : '' | |
var favIconString = customfavIcon ? '<link rel="icon" href="' + customfavIcon + '" />' : favIconHtml | |
var htmlWithCustomCss = _htmlTplString.toString().replace('<% customCss %>', customCss) | |
var htmlWithCustomRobots = htmlWithCustomCss.replace('<% robotsMetaString %>', robotsMetaString) | |
var htmlWithFavIcon = htmlWithCustomRobots.replace('<% favIconString %>', favIconString) | |
var htmlWithCustomJsUrl = htmlWithFavIcon.replace('<% customJs %>', toTags(customJs, toExternalScriptTag)) | |
var htmlWithCustomJs = htmlWithCustomJsUrl.replace('<% customJsStr %>', toTags(customJsStr, toInlineScriptTag)) | |
var htmlWithCustomCssUrl = htmlWithCustomJs.replace('<% customCssUrl %>', toTags(customCssUrl, toExternalStylesheetTag)) | |
var initOptions = { | |
swaggerDoc: swaggerDoc || undefined, | |
customOptions: options, | |
swaggerUrl: swaggerUrl || undefined, | |
swaggerUrls: swaggerUrls || undefined | |
} | |
swaggerInit = _jsTplString.toString().replace('<% swaggerOptions %>', stringify(initOptions)) | |
return htmlWithCustomCssUrl.replace('<% title %>', customSiteTitle) | |
} | |
var setup = function (swaggerDoc, opts, options, customCss, customfavIcon, swaggerUrl, customSiteTitle) { | |
var html = generateHTML(swaggerDoc, opts, options, customCss, customfavIcon, swaggerUrl, customSiteTitle, htmlTplString, jsTplString) | |
return function (req, res) { | |
if (req.swaggerDoc) { | |
var reqHtml = generateHTML(req.swaggerDoc, opts, options, customCss, customfavIcon, swaggerUrl, customSiteTitle, htmlTplString, jsTplString) | |
res.send(reqHtml) | |
} else { | |
res.send(html) | |
} | |
} | |
} | |
function swaggerInitFn(req, res, next) { | |
if (trimQuery(req.url).endsWith('/package.json')) { | |
res.sendStatus(404) | |
} else if (trimQuery(req.url).endsWith('/swagger-ui-init.js')) { | |
res.set('Content-Type', 'application/javascript') | |
res.send(swaggerInit) | |
} else { | |
next() | |
} | |
} | |
var swaggerInitFunction = function (swaggerDoc, opts) { | |
var swaggerInitFile = jsTplString.toString().replace('<% swaggerOptions %>', stringify(opts)) | |
return function (req, res, next) { | |
if (trimQuery(req.url).endsWith('/package.json')) { | |
res.sendStatus(404) | |
} else if (trimQuery(req.url).endsWith('/swagger-ui-init.js')) { | |
if (req.swaggerDoc) { | |
opts.swaggerDoc = req.swaggerDoc | |
swaggerInitFile = jsTplString.toString().replace('<% swaggerOptions %>', stringify(opts)) | |
} | |
res.set('Content-Type', 'application/javascript') | |
res.send(swaggerInitFile) | |
} else { | |
next() | |
} | |
} | |
} | |
var swaggerAssetMiddleware = options => { | |
var opts = options || {} | |
opts.index = false | |
return express.static(getAbsoluteSwaggerFsPaths, opts) | |
} | |
var serveFiles = function (swaggerDoc, opts) { | |
opts = opts || {} | |
var initOptions = { | |
swaggerDoc: swaggerDoc || undefined, | |
customOptions: opts.swaggerOptions || {}, | |
swaggerUrl: opts.swaggerUrl || {}, | |
swaggerUrls: opts.swaggerUrls || undefined | |
} | |
var swaggerInitWithOpts = swaggerInitFunction(swaggerDoc, initOptions) | |
return [swaggerInitWithOpts, swaggerAssetMiddleware()] | |
} | |
var serve = [swaggerInitFn, swaggerAssetMiddleware()] | |
var serveWithOptions = options => [swaggerInitFn, swaggerAssetMiddleware(options)] | |
var stringify = function (obj, prop) { | |
var placeholder = '____FUNCTIONPLACEHOLDER____' | |
var fns = [] | |
var json = JSON.stringify(obj, function (key, value) { | |
if (typeof value === 'function') { | |
fns.push(value) | |
return placeholder | |
} | |
return value | |
}, 2) | |
json = json.replace(new RegExp('"' + placeholder + '"', 'g'), function (_) { | |
return fns.shift() | |
}) | |
return 'var options = ' + json + ';' | |
} | |
export { | |
setup, | |
serve, | |
serveWithOptions, | |
generateHTML, | |
serveFiles | |
}; |