This commit is contained in:
2024-05-24 15:27:07 +03:00
parent 17df2ce6a9
commit fc1da2c238
643 changed files with 110185 additions and 231 deletions

View File

@ -0,0 +1,13 @@
module.exports.indent = function indent(str, len, fromLine = 0) {
return str
.split("\n")
.map((line, i) => {
if (i + 1 >= fromLine) {
return `${Array(len + 1).join(" ")}${line}`
} else {
return line
}
})
.join("\n")
}

View File

@ -0,0 +1,52 @@
/*
* Replace static code with configured data based on environment-variables.
* This code should be called BEFORE the webserver serve the api-documentation.
*/
const fs = require("fs")
const path = require("path")
const translator = require("./translator")
const oauthBlockBuilder = require("./oauth")
const indent = require("./helpers").indent
const START_MARKER = "//<editor-fold desc=\"Changeable Configuration Block\">"
const END_MARKER = "//</editor-fold>"
const targetPath = path.normalize(process.cwd() + "/" + process.argv[2])
const originalHtmlContent = fs.readFileSync(targetPath, "utf8")
const startMarkerIndex = originalHtmlContent.indexOf(START_MARKER)
const endMarkerIndex = originalHtmlContent.indexOf(END_MARKER)
const beforeStartMarkerContent = originalHtmlContent.slice(0, startMarkerIndex)
const afterEndMarkerContent = originalHtmlContent.slice(
endMarkerIndex + END_MARKER.length
)
if (startMarkerIndex < 0 || endMarkerIndex < 0) {
console.error("ERROR: Swagger UI was unable to inject Docker configuration data!")
console.error("! This can happen when you provide custom HTML/JavaScript to Swagger UI.")
console.error("! ")
console.error(`! In order to solve this, add the "${START_MARKER}"`)
console.error(`! and "${END_MARKER}" markers to your JavaScript.`)
console.error("! See the repository for an example:")
console.error("! https://github.com/swagger-api/swagger-ui/blob/8c946a02e73ef877d73b7635de27924418ba50f3/dist/swagger-initializer.js#L2-L19")
console.error("! ")
console.error("! If you're seeing this message and aren't using custom HTML,")
console.error("! this message may be a bug. Please file an issue:")
console.error("! https://github.com/swagger-api/swagger-ui/issues/new/choose")
process.exit(0)
}
fs.writeFileSync(
targetPath,
`${beforeStartMarkerContent}
${START_MARKER}
window.ui = SwaggerUIBundle({
${indent(translator(process.env, {injectBaseConfig: true}), 8, 2)}
})
${indent(oauthBlockBuilder(process.env), 6, 2)}
${END_MARKER}
${afterEndMarkerContent}`
)

View File

@ -0,0 +1,55 @@
const translator = require("./translator")
const indent = require("./helpers").indent
const oauthBlockSchema = {
OAUTH_CLIENT_ID: {
type: "string",
name: "clientId"
},
OAUTH_CLIENT_SECRET: {
type: "string",
name: "clientSecret",
onFound: () => console.warn("Swagger UI warning: don't use `OAUTH_CLIENT_SECRET` in production!")
},
OAUTH_REALM: {
type: "string",
name: "realm"
},
OAUTH_APP_NAME: {
type: "string",
name: "appName"
},
OAUTH_SCOPE_SEPARATOR: {
type: "string",
name: "scopeSeparator"
},
OAUTH_SCOPES: {
type: "string",
name: "scopes"
},
OAUTH_ADDITIONAL_PARAMS: {
type: "object",
name: "additionalQueryStringParams"
},
OAUTH_USE_BASIC_AUTH: {
type: "boolean",
name: "useBasicAuthenticationWithAccessCodeGrant"
},
OAUTH_USE_PKCE: {
type: "boolean",
name: "usePkceWithAuthorizationCodeGrant"
}
}
module.exports = function oauthBlockBuilder(env) {
const translatorResult = translator(env, { schema: oauthBlockSchema })
if(translatorResult) {
return (
`ui.initOAuth({
${indent(translatorResult, 2)}
})`)
}
return ``
}

View File

@ -0,0 +1,111 @@
// Converts an object of environment variables into a Swagger UI config object
const configSchema = require("./variables")
const defaultBaseConfig = {
url: {
value: "https://petstore.swagger.io/v2/swagger.json",
schema: {
type: "string",
base: true
}
},
dom_id: {
value: "#swagger-ui",
schema: {
type: "string",
base: true
}
},
deepLinking: {
value: "true",
schema: {
type: "boolean",
base: true
}
},
presets: {
value: `[\n SwaggerUIBundle.presets.apis,\n SwaggerUIStandalonePreset\n]`,
schema: {
type: "array",
base: true
}
},
plugins: {
value: `[\n SwaggerUIBundle.plugins.DownloadUrl\n]`,
schema: {
type: "array",
base: true
}
},
layout: {
value: "StandaloneLayout",
schema: {
type: "string",
base: true
}
},
queryConfigEnabled: {
value: "false",
schema: {
type: "boolean",
base: true,
}
}
}
function objectToKeyValueString(env, { injectBaseConfig = false, schema = configSchema, baseConfig = defaultBaseConfig } = {}) {
let valueStorage = injectBaseConfig ? Object.assign({}, baseConfig) : {}
const keys = Object.keys(env)
// Compute an intermediate representation that holds candidate values and schemas.
//
// This is useful for deduping between multiple env keys that set the same
// config variable.
keys.forEach(key => {
const varSchema = schema[key]
const value = env[key]
if(!varSchema) return
if(varSchema.onFound) {
varSchema.onFound()
}
const storageContents = valueStorage[varSchema.name]
if(storageContents) {
if (varSchema.legacy === true && !storageContents.schema.base) {
// If we're looking at a legacy var, it should lose out to any already-set value
// except for base values
return
}
delete valueStorage[varSchema.name]
}
valueStorage[varSchema.name] = {
value,
schema: varSchema
}
})
// Compute a key:value string based on valueStorage's contents.
let result = ""
Object.keys(valueStorage).forEach(key => {
const value = valueStorage[key]
const escapedName = /[^a-zA-Z0-9]/.test(key) ? `"${key}"` : key
if (value.schema.type === "string") {
result += `${escapedName}: "${value.value}",\n`
} else {
result += `${escapedName}: ${value.value === "" ? `undefined` : value.value},\n`
}
})
return result.trim()
}
module.exports = objectToKeyValueString

View File

@ -0,0 +1,125 @@
const standardVariables = {
CONFIG_URL: {
type: "string",
name: "configUrl"
},
DOM_ID: {
type: "string",
name: "dom_id"
},
SPEC: {
type: "object",
name: "spec"
},
URL: {
type: "string",
name: "url"
},
URLS: {
type: "array",
name: "urls"
},
URLS_PRIMARY_NAME: {
type: "string",
name: "urls.primaryName"
},
QUERY_CONFIG_ENABLED: {
type: "boolean",
name: "queryConfigEnabled"
},
LAYOUT: {
type: "string",
name: "layout"
},
DEEP_LINKING: {
type: "boolean",
name: "deepLinking"
},
DISPLAY_OPERATION_ID: {
type: "boolean",
name: "displayOperationId"
},
DEFAULT_MODELS_EXPAND_DEPTH: {
type: "number",
name: "defaultModelsExpandDepth"
},
DEFAULT_MODEL_EXPAND_DEPTH: {
type: "number",
name: "defaultModelExpandDepth"
},
DEFAULT_MODEL_RENDERING: {
type: "string",
name: "defaultModelRendering"
},
DISPLAY_REQUEST_DURATION: {
type: "boolean",
name: "displayRequestDuration"
},
DOC_EXPANSION: {
type: "string",
name: "docExpansion"
},
FILTER: {
type: "string",
name: "filter"
},
MAX_DISPLAYED_TAGS: {
type: "number",
name: "maxDisplayedTags"
},
SHOW_EXTENSIONS: {
type: "boolean",
name: "showExtensions"
},
SHOW_COMMON_EXTENSIONS: {
type: "boolean",
name: "showCommonExtensions"
},
USE_UNSAFE_MARKDOWN: {
type: "boolean",
name: "useUnsafeMarkdown"
},
OAUTH2_REDIRECT_URL: {
type: "string",
name: "oauth2RedirectUrl"
},
PERSIST_AUTHORIZATION: {
type: "boolean",
name: "persistAuthorization"
},
SHOW_MUTATED_REQUEST: {
type: "boolean",
name: "showMutatedRequest"
},
SUPPORTED_SUBMIT_METHODS: {
type: "array",
name: "supportedSubmitMethods"
},
TRY_IT_OUT_ENABLED: {
type: "boolean",
name: "tryItOutEnabled"
},
VALIDATOR_URL: {
type: "string",
name: "validatorUrl"
},
WITH_CREDENTIALS: {
type: "boolean",
name: "withCredentials",
}
}
const legacyVariables = {
API_URL: {
type: "string",
name: "url",
legacy: true
},
API_URLS: {
type: "array",
name: "urls",
legacy: true
}
}
module.exports = Object.assign({}, standardVariables, legacyVariables)