vitepress-openapi
Version:
Generate VitePress API Documentation from OpenAPI Specification.
1,131 lines (962 loc) • 32.4 kB
text/typescript
import type MarkdownIt from 'markdown-it'
import type { Ref, UnwrapNestedRefs } from 'vue'
import type { OARequest } from '../lib/codeSamples/request'
import type { OperationSlot, ParsedOperation } from '../types'
import vitesseDark from '@shikijs/themes/vitesse-dark'
import vitesseLight from '@shikijs/themes/vitesse-light'
import { useDark } from '@vueuse/core'
import { ref } from 'vue'
import { generateCodeSample } from '../lib/codeSamples/generateCodeSample'
import { deepUnref } from '../lib/utils/deepUnref'
import { locales } from '../locales'
function ensureNestedProperty<T, K extends keyof T>(obj: T, key: K): Exclude<NonNullable<T[K]>, false> {
if (!obj[key]) {
obj[key] = {} as T[K]
}
return obj[key] as Exclude<NonNullable<T[K]>, false>
}
function ensureRefProperty<T, K extends keyof T, V>(obj: T, key: K, propName: string, value: V): Ref<V> {
const container = ensureNestedProperty(obj, key) as any
if (!container[propName]) {
container[propName] = ref(value)
} else if (value !== undefined) {
container[propName].value = value
}
return container[propName]
}
function ensureNestedRefProperty<V>(obj: any, path: string[], propName: string, value: V): Ref<V> {
let current = obj
for (const segment of path) {
current = ensureNestedProperty(current, segment)
}
if (!current[propName]) {
current[propName] = ref(value)
} else if (value !== undefined) {
current[propName].value = value
}
return current[propName]
}
export type BodyViewType = 'schema' | 'contentType' | 'autogenerated'
export type JsonRendererType = 'vue-json-pretty' | 'shiki' | string
export type ResponseCodeSelectorType = 'tabs' | 'select'
export type OperationColsType = 1 | 2
export type OperationBadges = 'deprecated' | 'operationId'
export type PlaygroundJsonEditorMode = 'text' | 'tree' | 'table'
export type Languages = 'es' | 'en' | 'ja' | 'pt-BR' | 'zh' | string
export type Messages = Record<Languages, Record<string, string>>
export interface ThemeConfig {
highlighterTheme?: {
light?: any
dark?: any
}
}
export interface PathConfig {
showBaseURL?: Ref<boolean>
}
export interface RequestConfig {
defaultView?: Ref<BodyViewType>
}
export interface JsonViewerConfig {
deep?: Ref<number>
renderer?: Ref<JsonRendererType>
}
export interface SchemaViewerConfig {
deep?: Ref<number>
}
export interface HeadingLevels {
h1?: number
h2?: number
h3?: number
h4?: number
h5?: number
h6?: number
}
export interface ResponseConfig {
responseCodeSelector?: Ref<ResponseCodeSelectorType>
maxTabs?: Ref<number>
body?: {
defaultView?: Ref<BodyViewType>
}
}
export interface PlaygroundConfig {
jsonEditor?: {
mode?: Ref<PlaygroundJsonEditorMode>
mainMenuBar?: Ref<boolean>
navigationBar?: Ref<boolean>
statusBar?: Ref<boolean>
}
}
export interface SecurityConfig {
defaultScheme?: Ref<string | null>
}
export interface OperationConfig {
badges?: Ref<OperationBadges[]>
slots?: Ref<OperationSlot[]>
/** @deprecated Use server.getServers instead */
getServers?: GetServersFunction | null
hiddenSlots?: Ref<OperationSlot[]>
cols?: Ref<OperationColsType>
defaultBaseUrl?: string
}
export interface AvailableLocale {
code: string
label: string
}
export interface I18nConfig {
locale?: Ref<Languages>
fallbackLocale?: Ref<Languages>
messages?: Messages
availableLocales?: AvailableLocale[]
}
export interface SpecConfig {
groupByTags?: Ref<boolean>
collapsePaths?: Ref<boolean>
showPathsSummary?: Ref<boolean>
avoidCirculars?: Ref<boolean>
lazyRendering?: Ref<boolean>
defaultTag?: string
defaultTagDescription?: string
wrapExamples?: boolean
disableDownload?: Ref<boolean>
}
export interface ServerConfig {
allowCustomServer?: boolean
getServers?: GetServersFunction | null
}
export interface OperationLinkConfig {
linkPrefix?: string
transformHref?: (href: string) => string
}
export interface MarkdownConfig {
operationLink?: OperationLinkConfig | false
externalLinksNewTab?: boolean
config?: (md: MarkdownIt) => MarkdownIt | undefined
}
export interface UseThemeConfig {
theme?: Partial<ThemeConfig>
path?: Partial<PathConfig>
requestBody?: Partial<RequestConfig>
jsonViewer?: Partial<JsonViewerConfig>
schemaViewer?: Partial<SchemaViewerConfig>
headingLevels?: Partial<HeadingLevels>
response?: Partial<ResponseConfig>
playground?: Partial<PlaygroundConfig>
security?: Partial<SecurityConfig>
operation?: Partial<OperationConfig>
i18n?: Partial<I18nConfig>
spec?: Partial<SpecConfig>
codeSamples?: Partial<CodeSamplesConfig>
linksPrefixes?: Partial<LinksPrefixesConfig>
server?: Partial<ServerConfig>
markdown?: Partial<MarkdownConfig>
}
export interface CodeSamplesConfig {
langs: string[]
defaultLang: string
availableLanguages: LanguageConfig[]
generator: GeneratorFunction
defaultHeaders: Record<string, string>
}
export interface LinksPrefixesConfig {
tags: string
operations: string
}
interface LanguageConfig {
lang: string
label: string
highlighter: string
icon?: string
}
export type PartialUseThemeConfig = Partial<UnwrapNestedRefs<UseThemeConfig>>
type GeneratorFunction = (lang: string, request: OARequest) => Promise<string>
type GetServersFunction = ({ method, path, operation }: { method: string, path: string, operation: ParsedOperation }) => string[] | null
export const DEFAULT_OPERATION_SLOTS: OperationSlot[] = [
'header',
'path',
'description',
'security',
'parameters',
'request-body',
'responses',
'playground',
'code-samples',
'branding',
'footer',
]
export const DEFAULT_BASE_URL = 'http://localhost'
export const availableLanguages: LanguageConfig[] = [
{
lang: 'curl',
label: 'cURL',
highlighter: 'bash',
icon: 'curl',
},
{
lang: 'javascript',
label: 'JavaScript',
highlighter: 'javascript',
icon: '.js',
},
{
lang: 'php',
label: 'PHP',
highlighter: 'php',
icon: '.php',
},
{
lang: 'python',
label: 'Python',
highlighter: 'python',
icon: '.py',
},
]
const DEFAULT_OPERATIONS_PREFIX = '/operations/'
const defaultValues = {
theme: {
highlighterTheme: {
light: vitesseLight,
dark: vitesseDark,
},
},
path: {
showBaseURL: false,
},
requestBody: {
defaultView: 'contentType' as BodyViewType,
},
jsonViewer: {
deep: Number.POSITIVE_INFINITY,
renderer: 'vue-json-pretty' as JsonRendererType,
},
schemaViewer: {
deep: 1,
},
headingLevels: {
h1: 1,
h2: 2,
h3: 3,
h4: 4,
h5: 5,
h6: 6,
},
response: {
responseCodeSelector: 'tabs' as ResponseCodeSelectorType,
maxTabs: 5,
body: {
defaultView: 'contentType' as BodyViewType,
},
},
playground: {
jsonEditor: {
mode: 'tree' as PlaygroundJsonEditorMode,
mainMenuBar: false,
navigationBar: false,
statusBar: false,
},
},
security: {
defaultScheme: null as string | null,
},
operation: {
badges: ['deprecated'] as OperationBadges[],
slots: DEFAULT_OPERATION_SLOTS,
hiddenSlots: [] as OperationSlot[],
cols: 2 as OperationColsType,
defaultBaseUrl: DEFAULT_BASE_URL,
getServers: null,
},
i18n: {
locale: 'en' as Languages,
fallbackLocale: 'en' as Languages,
messages: locales,
availableLocales: [
{
code: 'en',
label: 'English',
},
{
code: 'es',
label: 'Español',
},
{
code: 'ja',
label: 'Japanese',
},
{
code: 'pt-BR',
label: 'Português (Brasil)',
},
{
code: 'zh',
label: '中文',
},
],
},
spec: {
groupByTags: true,
collapsePaths: false,
showPathsSummary: true,
avoidCirculars: false,
lazyRendering: false,
defaultTag: 'Default',
defaultTagDescription: '',
wrapExamples: true,
disableDownload: false,
},
codeSamples: {
langs: [
'curl',
'javascript',
'php',
'python',
],
defaultLang: 'curl',
availableLanguages,
generator: (lang: string, request: OARequest) => generateCodeSample(lang, request),
defaultHeaders: {},
},
linksPrefixes: {
tags: '/tags/',
operations: DEFAULT_OPERATIONS_PREFIX,
},
server: {
allowCustomServer: false,
getServers: null,
},
markdown: {
operationLink: {
linkPrefix: DEFAULT_OPERATIONS_PREFIX,
},
externalLinksNewTab: false,
config: undefined,
},
}
const themeConfig: UseThemeConfig = {
theme: {
highlighterTheme: {
light: defaultValues.theme.highlighterTheme.light,
dark: defaultValues.theme.highlighterTheme.dark,
},
},
path: {
showBaseURL: ref(defaultValues.path.showBaseURL),
},
requestBody: {
defaultView: ref(defaultValues.requestBody.defaultView),
},
jsonViewer: {
deep: ref(defaultValues.jsonViewer.deep),
renderer: ref(defaultValues.jsonViewer.renderer),
},
schemaViewer: {
deep: ref(defaultValues.schemaViewer.deep),
},
headingLevels: {
...defaultValues.headingLevels,
},
response: {
responseCodeSelector: ref(defaultValues.response.responseCodeSelector),
maxTabs: ref(defaultValues.response.maxTabs),
body: {
defaultView: ref(defaultValues.response.body.defaultView),
},
},
playground: {
jsonEditor: {
mode: ref(defaultValues.playground.jsonEditor.mode),
mainMenuBar: ref(defaultValues.playground.jsonEditor.mainMenuBar),
navigationBar: ref(defaultValues.playground.jsonEditor.navigationBar),
statusBar: ref(defaultValues.playground.jsonEditor.statusBar),
},
},
security: {
defaultScheme: ref(defaultValues.security.defaultScheme),
},
operation: {
badges: ref(defaultValues.operation.badges),
slots: ref(defaultValues.operation.slots),
hiddenSlots: ref(defaultValues.operation.hiddenSlots),
cols: ref(defaultValues.operation.cols),
defaultBaseUrl: defaultValues.operation.defaultBaseUrl,
getServers: defaultValues.operation.getServers,
},
i18n: {
locale: ref(defaultValues.i18n.locale),
fallbackLocale: ref(defaultValues.i18n.fallbackLocale),
messages: defaultValues.i18n.messages,
availableLocales: defaultValues.i18n.availableLocales,
},
spec: {
groupByTags: ref(defaultValues.spec.groupByTags),
collapsePaths: ref(defaultValues.spec.collapsePaths),
showPathsSummary: ref(defaultValues.spec.showPathsSummary),
avoidCirculars: ref(defaultValues.spec.avoidCirculars),
lazyRendering: ref(defaultValues.spec.lazyRendering),
defaultTag: defaultValues.spec.defaultTag,
defaultTagDescription: defaultValues.spec.defaultTagDescription,
wrapExamples: defaultValues.spec.wrapExamples,
disableDownload: ref(defaultValues.spec.disableDownload),
},
codeSamples: {
langs: defaultValues.codeSamples.langs,
defaultLang: defaultValues.codeSamples.defaultLang,
availableLanguages: defaultValues.codeSamples.availableLanguages,
generator: defaultValues.codeSamples.generator,
defaultHeaders: defaultValues.codeSamples.defaultHeaders,
},
linksPrefixes: {
tags: defaultValues.linksPrefixes.tags,
operations: defaultValues.linksPrefixes.operations,
},
server: {
allowCustomServer: defaultValues.server.allowCustomServer,
getServers: defaultValues.server.getServers,
},
markdown: {
operationLink: {
linkPrefix: defaultValues.markdown.operationLink.linkPrefix,
},
externalLinksNewTab: defaultValues.markdown.externalLinksNewTab,
config: defaultValues.markdown.config,
},
}
const isDark = useDark({
storageKey: 'vitepress-theme-appearance',
})
export function useTheme(initialConfig: PartialUseThemeConfig = {}) {
setConfig(initialConfig)
function setConfig(config: PartialUseThemeConfig) {
if (!config || !Object.keys(config).length) {
return
}
// Theme and highlighter
if (config.theme?.highlighterTheme) {
setHighlighterTheme(config.theme.highlighterTheme)
}
// Path
if (config.path?.showBaseURL !== undefined) {
ensureRefProperty(themeConfig, 'path', 'showBaseURL', config.path.showBaseURL)
}
// Request body
if (config.requestBody?.defaultView !== undefined) {
ensureRefProperty(themeConfig, 'requestBody', 'defaultView', config.requestBody.defaultView)
}
// JSON viewer
if (config.jsonViewer?.deep !== undefined) {
ensureRefProperty(themeConfig, 'jsonViewer', 'deep', config.jsonViewer.deep)
}
if (config.jsonViewer?.renderer !== undefined) {
ensureRefProperty(themeConfig, 'jsonViewer', 'renderer', config.jsonViewer.renderer)
}
// Schema viewer
if (config.schemaViewer?.deep !== undefined) {
ensureRefProperty(themeConfig, 'schemaViewer', 'deep', config.schemaViewer.deep)
}
// Heading levels
if (config.headingLevels !== undefined) {
setHeadingLevels(config.headingLevels)
}
// Response
if (config.response?.responseCodeSelector !== undefined) {
ensureRefProperty(themeConfig, 'response', 'responseCodeSelector', config.response.responseCodeSelector)
}
if (config.response?.maxTabs !== undefined) {
ensureRefProperty(themeConfig, 'response', 'maxTabs', config.response.maxTabs)
}
if (config.response?.body?.defaultView !== undefined) {
ensureNestedRefProperty(themeConfig, ['response', 'body'], 'defaultView', config.response.body.defaultView)
}
// Playground
if (config.playground?.jsonEditor?.mode !== undefined) {
ensureNestedRefProperty(themeConfig, ['playground', 'jsonEditor'], 'mode', config.playground.jsonEditor.mode)
}
if (config.playground?.jsonEditor?.mainMenuBar !== undefined) {
ensureNestedRefProperty(themeConfig, ['playground', 'jsonEditor'], 'mainMenuBar', config.playground.jsonEditor.mainMenuBar)
}
if (config.playground?.jsonEditor?.navigationBar !== undefined) {
ensureNestedRefProperty(themeConfig, ['playground', 'jsonEditor'], 'navigationBar', config.playground.jsonEditor.navigationBar)
}
if (config.playground?.jsonEditor?.statusBar !== undefined) {
ensureNestedRefProperty(themeConfig, ['playground', 'jsonEditor'], 'statusBar', config.playground.jsonEditor.statusBar)
}
// Security
if (config.security?.defaultScheme !== undefined) {
ensureRefProperty(themeConfig, 'security', 'defaultScheme', config.security.defaultScheme)
}
// Operation
if (config.operation?.badges !== undefined) {
ensureRefProperty(themeConfig, 'operation', 'badges', config.operation.badges)
}
if (config.operation?.slots !== undefined) {
ensureRefProperty(themeConfig, 'operation', 'slots', config.operation.slots)
}
if (config.operation?.hiddenSlots !== undefined) {
ensureRefProperty(themeConfig, 'operation', 'hiddenSlots', config.operation.hiddenSlots)
}
if (config.operation?.cols !== undefined) {
ensureRefProperty(themeConfig, 'operation', 'cols', config.operation.cols)
}
if (config.operation?.defaultBaseUrl !== undefined) {
setOperationDefaultBaseUrl(config.operation.defaultBaseUrl)
}
if (config.operation?.getServers !== undefined) {
setOperationServers(config.operation.getServers)
}
// i18n
if (config.i18n !== undefined) {
setI18nConfig(config.i18n)
}
// Spec
if (config.spec !== undefined) {
setSpecConfig(config.spec)
}
// Code samples
if (config.codeSamples !== undefined) {
setCodeSamplesConfig(config.codeSamples)
}
// Links prefixes
if (config.linksPrefixes !== undefined) {
setLinksPrefixesConfig(config.linksPrefixes)
}
// Server
if (config.server !== undefined) {
setServerConfig(config.server)
}
// Markdown
if (config.markdown !== undefined) {
setMarkdownConfig(config.markdown)
}
}
function reset() {
setConfig(defaultValues)
}
function getState() {
return deepUnref(themeConfig)
}
function getLocale(): Languages {
return themeConfig?.i18n?.locale?.value || 'en'
}
/**
* @deprecated Use `setI18nConfig({ locale: value })` instead.
*/
function setLocale(value: Languages) {
console.warn('`setLocale` is deprecated. Use `setI18nConfig({ locale: value })` instead.')
// @ts-expect-error: This is a valid expression.
themeConfig.i18n.locale.value = value
}
function getHighlighterTheme() {
return themeConfig?.theme?.highlighterTheme
}
function setHighlighterTheme(value: ThemeConfig['highlighterTheme']) {
// @ts-expect-error: This is a valid expression.
themeConfig.theme.highlighterTheme = {
...themeConfig?.theme?.highlighterTheme,
...value,
}
}
function getRequestBodyDefaultView(): BodyViewType | undefined {
return themeConfig?.requestBody?.defaultView?.value
}
function setRequestBodyDefaultView(value: BodyViewType) {
ensureRefProperty(themeConfig, 'requestBody', 'defaultView', value)
}
function getShowBaseURL(): boolean | undefined {
return themeConfig?.path?.showBaseURL?.value
}
function setShowBaseURL(value: boolean) {
ensureRefProperty(themeConfig, 'path', 'showBaseURL', value)
}
function getJsonViewerDeep(): number | undefined {
return themeConfig?.jsonViewer?.deep?.value
}
function setJsonViewerDeep(value: number) {
ensureRefProperty(themeConfig, 'jsonViewer', 'deep', value)
}
function getJsonViewerRenderer(): JsonRendererType {
return themeConfig?.jsonViewer?.renderer?.value || 'vue-json-pretty'
}
function setJsonViewerRenderer(value: JsonRendererType) {
ensureRefProperty(themeConfig, 'jsonViewer', 'renderer', value)
}
function getSchemaViewerDeep(): number | undefined {
return themeConfig?.schemaViewer?.deep?.value
}
function setSchemaViewerDeep(value: number) {
ensureRefProperty(themeConfig, 'schemaViewer', 'deep', value)
}
function getHeadingLevels() {
return themeConfig.headingLevels
}
function getHeadingLevel(level: keyof HeadingLevels): `h${1 | 2 | 3 | 4 | 5 | 6}` {
if (!themeConfig.headingLevels) {
return `h${level}` as 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
}
const headingLevel = themeConfig.headingLevels[level] as number
if (headingLevel < 1 || headingLevel > 6) {
throw new Error(`Heading level for ${level} must be between 1 and 6.`)
}
return `h${headingLevel}` as 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
}
function setHeadingLevels(levels: Partial<UnwrapNestedRefs<HeadingLevels>>) {
if (!themeConfig.headingLevels) {
themeConfig.headingLevels = { }
}
for (const key of Object.keys(levels)) {
const value = levels[key as keyof HeadingLevels] as number
if (value < 1 || value > 6) {
throw new Error(`Heading level for ${key} must be between 1 and 6.`)
}
}
Object.assign(themeConfig.headingLevels, levels)
}
function getResponseCodeSelector(): ResponseCodeSelectorType | undefined {
return themeConfig?.response?.responseCodeSelector?.value
}
function setResponseCodeSelector(value: ResponseCodeSelectorType) {
ensureRefProperty(themeConfig, 'response', 'responseCodeSelector', value)
}
function getResponseCodeMaxTabs(): number | undefined {
return themeConfig?.response?.maxTabs?.value
}
function setResponseCodeMaxTabs(value: number) {
ensureRefProperty(themeConfig, 'response', 'maxTabs', value)
}
function getResponseBodyDefaultView(): BodyViewType | undefined {
return themeConfig?.response?.body?.defaultView?.value
}
function setResponseBodyDefaultView(value: BodyViewType) {
ensureNestedRefProperty(themeConfig, ['response', 'body'], 'defaultView', value)
}
function getPlaygroundJsonEditorMode(): PlaygroundJsonEditorMode | undefined {
return themeConfig?.playground?.jsonEditor?.mode?.value
}
function setPlaygroundJsonEditorMode(value: PlaygroundJsonEditorMode) {
ensureNestedRefProperty(themeConfig, ['playground', 'jsonEditor'], 'mode', value)
}
function getPlaygroundJsonEditorMainMenuBar(): boolean | undefined {
return themeConfig?.playground?.jsonEditor?.mainMenuBar?.value
}
function setPlaygroundJsonEditorMainMenuBar(value: boolean) {
ensureNestedRefProperty(themeConfig, ['playground', 'jsonEditor'], 'mainMenuBar', value)
}
function getPlaygroundJsonEditorNavigationBar(): boolean | undefined {
return themeConfig?.playground?.jsonEditor?.navigationBar?.value
}
function setPlaygroundJsonEditorNavigationBar(value: boolean) {
ensureNestedRefProperty(themeConfig, ['playground', 'jsonEditor'], 'navigationBar', value)
}
function getPlaygroundJsonEditorStatusBar(): boolean | undefined {
return themeConfig?.playground?.jsonEditor?.statusBar?.value
}
function setPlaygroundJsonEditorStatusBar(value: boolean) {
ensureNestedRefProperty(themeConfig, ['playground', 'jsonEditor'], 'statusBar', value)
}
function getSecurityDefaultScheme(): string | null | undefined {
return themeConfig?.security?.defaultScheme?.value
}
function setSecurityDefaultScheme(value: string | null) {
ensureRefProperty(themeConfig, 'security', 'defaultScheme', value)
}
function getOperationBadges(): OperationBadges[] {
return [...(themeConfig?.operation?.badges?.value || [])]
}
function setOperationBadges(value: OperationBadges[]) {
ensureRefProperty(themeConfig, 'operation', 'badges', value)
}
function getOperationSlots(): OperationSlot[] | undefined {
return themeConfig?.operation?.slots?.value
}
function setOperationSlots(value: OperationSlot[]) {
ensureRefProperty(themeConfig, 'operation', 'slots', value)
}
function getOperationHiddenSlots(): OperationSlot[] | undefined {
return themeConfig?.operation?.hiddenSlots?.value
}
function setOperationHiddenSlots(value: OperationSlot[]) {
ensureRefProperty(themeConfig, 'operation', 'hiddenSlots', value)
}
function getOperationCols(): OperationColsType | undefined {
return themeConfig?.operation?.cols?.value
}
function setOperationCols(value: OperationColsType) {
ensureRefProperty(themeConfig, 'operation', 'cols', value)
}
function getOperationDefaultBaseUrl(): string {
return themeConfig?.operation?.defaultBaseUrl || DEFAULT_BASE_URL
}
function setOperationDefaultBaseUrl(value: string) {
const operation = ensureNestedProperty(themeConfig, 'operation')
operation.defaultBaseUrl = value
}
function getOperationServers(): GetServersFunction | null {
if (themeConfig?.operation?.getServers) {
console.warn('operation.getServers is deprecated. Use server.getServers instead.')
return themeConfig.operation.getServers
}
return themeConfig?.server?.getServers || null
}
function setOperationServers(value: GetServersFunction | null) {
const operation = ensureNestedProperty(themeConfig, 'operation')
operation.getServers = value
}
function getI18nConfig(): I18nConfig {
return themeConfig.i18n as I18nConfig
}
function setI18nConfig(config: Partial<UnwrapNestedRefs<I18nConfig>>) {
const i18n = ensureNestedProperty(themeConfig, 'i18n')
if (config.locale) {
ensureRefProperty(themeConfig, 'i18n', 'locale', config.locale)
}
if (config.fallbackLocale) {
ensureRefProperty(themeConfig, 'i18n', 'fallbackLocale', config.fallbackLocale)
}
if (config.messages) {
i18n.messages = config.messages
}
if (config.availableLocales) {
i18n.availableLocales = config.availableLocales
}
}
function getSpecConfig() {
return themeConfig.spec
}
function getWrapExamples() {
return themeConfig?.spec?.wrapExamples
}
function getSpecDisableDownload(): boolean | undefined {
return themeConfig?.spec?.disableDownload?.value
}
function setSpecConfig(config: Partial<UnwrapNestedRefs<SpecConfig>>) {
const spec = ensureNestedProperty(themeConfig, 'spec')
if (config.groupByTags !== undefined) {
ensureRefProperty(themeConfig, 'spec', 'groupByTags', config.groupByTags)
}
if (config.collapsePaths !== undefined) {
ensureRefProperty(themeConfig, 'spec', 'collapsePaths', config.collapsePaths)
}
if (config.showPathsSummary !== undefined) {
ensureRefProperty(themeConfig, 'spec', 'showPathsSummary', config.showPathsSummary)
}
if (config.avoidCirculars !== undefined) {
ensureRefProperty(themeConfig, 'spec', 'avoidCirculars', config.avoidCirculars)
}
if (config.lazyRendering !== undefined) {
ensureRefProperty(themeConfig, 'spec', 'lazyRendering', config.lazyRendering)
}
if (config.defaultTag !== undefined) {
spec.defaultTag = config.defaultTag
}
if (config.defaultTagDescription !== undefined) {
spec.defaultTagDescription = config.defaultTagDescription
}
if (config.wrapExamples !== undefined) {
spec.wrapExamples = config.wrapExamples
}
if (config.disableDownload !== undefined) {
ensureRefProperty(themeConfig, 'spec', 'disableDownload', config.disableDownload)
}
}
function getCodeSamplesLangs() {
const codeSamples = ensureNestedProperty(themeConfig, 'codeSamples')
if (!codeSamples.langs) {
codeSamples.langs = defaultValues.codeSamples.langs
}
return codeSamples.langs.filter((lang, index, self) => self.indexOf(lang) === index)
}
function getCodeSamplesDefaultLang() {
const availableLangs = getCodeSamplesLangs() || []
const codeSamples = ensureNestedProperty(themeConfig, 'codeSamples')
if (codeSamples.defaultLang && availableLangs.includes(codeSamples.defaultLang)) {
return codeSamples.defaultLang
}
return availableLangs[0]
}
function getCodeSamplesAvailableLanguages() {
const codeSamples = ensureNestedProperty(themeConfig, 'codeSamples')
return codeSamples.availableLanguages
}
function getCodeSamplesGenerator() {
const codeSamples = ensureNestedProperty(themeConfig, 'codeSamples')
if (!codeSamples.generator) {
codeSamples.generator = defaultValues.codeSamples.generator
}
return codeSamples.generator
}
function getCodeSamplesDefaultHeaders() {
const codeSamples = ensureNestedProperty(themeConfig, 'codeSamples')
if (!codeSamples.defaultHeaders) {
codeSamples.defaultHeaders = defaultValues.codeSamples.defaultHeaders
}
return codeSamples.defaultHeaders
}
function setCodeSamplesConfig(config: Partial<UnwrapNestedRefs<CodeSamplesConfig>>) {
const codeSamples = ensureNestedProperty(themeConfig, 'codeSamples')
if (config.langs) {
codeSamples.langs = config.langs.filter((lang, index, self) => self.indexOf(lang) === index)
}
if (config.defaultLang) {
codeSamples.defaultLang = config.defaultLang
}
if (config.availableLanguages) {
setCodeSamplesAvailableLanguages(config.availableLanguages)
}
if (config.generator) {
codeSamples.generator = config.generator
}
if (config.defaultHeaders) {
codeSamples.defaultHeaders = config.defaultHeaders
}
}
function setCodeSamplesAvailableLanguages(languages: LanguageConfig[]) {
const codeSamples = ensureNestedProperty(themeConfig, 'codeSamples')
if (!codeSamples.availableLanguages) {
codeSamples.availableLanguages = defaultValues.codeSamples.availableLanguages
}
const uniqueLanguages = [...new Set(languages.map(({ lang }) => lang))]
codeSamples.availableLanguages = uniqueLanguages.map((lang) => {
const language
= languages.find(l => l.lang === lang)
?? availableLanguages.find(l => l.lang === lang)
return language || { lang, label: lang, highlighter: 'plaintext' }
})
}
function getLinksPrefixesConfig() {
return themeConfig.linksPrefixes
}
function setLinksPrefixesConfig(config: Partial<UnwrapNestedRefs<LinksPrefixesConfig>>) {
const linksPrefixes = ensureNestedProperty(themeConfig, 'linksPrefixes')
if (config.tags) {
linksPrefixes.tags = config.tags
}
if (config.operations) {
linksPrefixes.operations = config.operations
}
}
function getTagsLinkPrefix() {
return themeConfig?.linksPrefixes?.tags
}
function getOperationsLinkPrefix() {
return themeConfig?.linksPrefixes?.operations
}
function getServerConfig(): ServerConfig {
return themeConfig.server as ServerConfig
}
function setServerConfig(config: Partial<UnwrapNestedRefs<ServerConfig>>) {
const server = ensureNestedProperty(themeConfig, 'server')
if (config.allowCustomServer !== undefined) {
server.allowCustomServer = config.allowCustomServer
}
if (config.getServers !== undefined) {
server.getServers = config.getServers
}
}
function getServerAllowCustomServer(): boolean {
return themeConfig.server?.allowCustomServer || false
}
function getMarkdownConfig(): MarkdownConfig {
return themeConfig.markdown as MarkdownConfig
}
function getExternalLinksNewTab(): boolean {
return themeConfig.markdown?.externalLinksNewTab ?? false
}
function setMarkdownConfig(config: Partial<UnwrapNestedRefs<MarkdownConfig>>) {
const markdown = ensureNestedProperty(themeConfig, 'markdown')
if (config.operationLink !== undefined) {
if (config.operationLink === false) {
markdown.operationLink = false
} else {
const operationLink = ensureNestedProperty(markdown, 'operationLink')
if (config.operationLink.linkPrefix !== undefined) {
operationLink.linkPrefix = config.operationLink.linkPrefix
}
if (config.operationLink.transformHref !== undefined) {
operationLink.transformHref = config.operationLink.transformHref
}
}
}
if (config.externalLinksNewTab !== undefined) {
markdown.externalLinksNewTab = config.externalLinksNewTab
}
if (config.config !== undefined) {
markdown.config = config.config
}
}
function getOperationLinkConfig(): OperationLinkConfig | false | undefined {
return themeConfig.markdown?.operationLink
}
return {
isDark,
schemaConfig: themeConfig.requestBody,
reset,
getState,
getLocale,
setLocale,
getHighlighterTheme,
/** @deprecated Use `getRequestBodyDefaultView` instead. */
getSchemaDefaultView: getRequestBodyDefaultView,
getRequestBodyDefaultView,
/** @deprecated Use `setRequestBodyDefaultView` instead. */
setSchemaDefaultView: setRequestBodyDefaultView,
setRequestBodyDefaultView,
getShowBaseURL,
setShowBaseURL,
getJsonViewerDeep,
setJsonViewerDeep,
getJsonViewerRenderer,
setJsonViewerRenderer,
getSchemaViewerDeep,
setSchemaViewerDeep,
getHeadingLevels,
getHeadingLevel,
setHeadingLevels,
getResponseCodeSelector,
setResponseCodeSelector,
getResponseCodeMaxTabs,
setResponseCodeMaxTabs,
getResponseBodyDefaultView,
setResponseBodyDefaultView,
getPlaygroundJsonEditorMode,
setPlaygroundJsonEditorMode,
getPlaygroundJsonEditorMainMenuBar,
setPlaygroundJsonEditorMainMenuBar,
getPlaygroundJsonEditorNavigationBar,
setPlaygroundJsonEditorNavigationBar,
getPlaygroundJsonEditorStatusBar,
setPlaygroundJsonEditorStatusBar,
getSecurityDefaultScheme,
setSecurityDefaultScheme,
getOperationBadges,
setOperationBadges,
getOperationSlots,
setOperationSlots,
getOperationHiddenSlots,
setOperationHiddenSlots,
getOperationCols,
setOperationCols,
getOperationDefaultBaseUrl,
getOperationServers,
getI18nConfig,
setI18nConfig,
getSpecConfig,
getWrapExamples,
getSpecDisableDownload,
setSpecConfig,
getCodeSamplesLangs,
getCodeSamplesDefaultLang,
getCodeSamplesAvailableLanguages,
getCodeSamplesGenerator,
getCodeSamplesDefaultHeaders,
setCodeSamplesConfig,
getLinksPrefixesConfig,
setLinksPrefixesConfig,
getTagsLinkPrefix,
getOperationsLinkPrefix,
getServerConfig,
setServerConfig,
getServerAllowCustomServer,
getMarkdownConfig,
getExternalLinksNewTab,
setMarkdownConfig,
getOperationLinkConfig,
}
}