Skip to content

Commit b1f692e

Browse files
committed
feat(scalar): support functions options
1 parent 070919e commit b1f692e

File tree

3 files changed

+76
-19
lines changed

3 files changed

+76
-19
lines changed

example/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ import { openapi, withHeaders } from '../src/index'
77
const app = new Elysia()
88
.use(
99
openapi({
10-
embedSchema: true,
1110
mapJsonSchema: {
1211
zod: z.toJSONSchema
12+
},
13+
scalar: {
14+
onBeforeRequest: ({ request }) => {
15+
console.info('onBeforeRequest', request.method, request.url)
16+
}
1317
}
1418
})
1519
)

src/scalar/index.ts

Lines changed: 70 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { OpenAPIV3 } from 'openapi-types'
2-
import type { ApiReferenceConfiguration } from '@scalar/types'
32
import { ElysiaOpenAPIConfig } from '../types'
43

54
const elysiaCSS = `.light-mode {
@@ -123,10 +122,75 @@ const elysiaCSS = `.light-mode {
123122
filter: opacity(4%) saturate(200%);
124123
}`
125124

125+
const serializeArrayWithFunctions = (arr: unknown[]): string => {
126+
return `[${arr.map((item) => (typeof item === 'function' ? item.toString() : JSON.stringify(item))).join(', ')}]`
127+
}
128+
129+
/**
130+
* Generates the complete HTML script block required for Scalar setup, based on the provided configuration.
131+
*
132+
* This includes:
133+
* 1. The Scalar bundle script.
134+
* 2. An inline script that initializes the Scalar reference with user-provided configuration data.
135+
*
136+
* This function is adapted from the Scalar Core implementation.
137+
* @see https://github.com/scalar/scalar/blob/main/packages/core/src/libs/html-rendering/html-rendering.ts#L93
138+
*
139+
* @param config - The Scalar configuration object.
140+
* @returns A string containing all required <script> tags for embedding Scalar.
141+
*/
142+
export function getScriptTags({
143+
cdn,
144+
...configuration
145+
}: NonNullable<ElysiaOpenAPIConfig['scalar']>) {
146+
const restConfig = { ...configuration }
147+
148+
const functionProps: string[] = []
149+
150+
for (const [key, value] of Object.entries(configuration) as [
151+
keyof typeof configuration,
152+
unknown
153+
][]) {
154+
if (typeof value === 'function') {
155+
functionProps.push(`"${key}": ${value.toString()}`)
156+
delete restConfig[key]
157+
} else if (
158+
Array.isArray(value) &&
159+
value.some((item) => typeof item === 'function')
160+
) {
161+
// Handle arrays that contain functions (like plugins)
162+
functionProps.push(
163+
`"${key}": ${serializeArrayWithFunctions(value)}`
164+
)
165+
delete restConfig[key]
166+
}
167+
}
168+
169+
// Stringify the rest of the configuration
170+
const configString = JSON.stringify(restConfig, null, 2)
171+
.split('\n')
172+
.map((line, index) => (index === 0 ? line : ' ' + line))
173+
.join('\n')
174+
.replace(/\s*}$/, '') // Remove the closing brace and any whitespace before it
175+
176+
const functionPropsString = functionProps.length
177+
? `,\n ${functionProps.join(',\n ')}\n }`
178+
: '}'
179+
180+
return `
181+
<!-- Scalar script -->
182+
<script src="${cdn ?? 'https://cdn.jsdelivr.net/npm/@scalar/api-reference'}"></script>
183+
184+
<!-- Initialize the Scalar API Reference using provided config -->
185+
<script type="text/javascript">
186+
Scalar.createApiReference('#app', ${configString}${functionPropsString})
187+
</script>`
188+
}
189+
126190
export const ScalarRender = (
127-
info: OpenAPIV3.InfoObject,
128-
config: NonNullable<ElysiaOpenAPIConfig['scalar']>,
129-
embedSpec?: string
191+
info: OpenAPIV3.InfoObject,
192+
config: NonNullable<ElysiaOpenAPIConfig['scalar']>,
193+
embedSpec?: string
130194
) => `<!doctype html>
131195
<html>
132196
<head>
@@ -153,18 +217,7 @@ export const ScalarRender = (
153217
</style>
154218
</head>
155219
<body>
156-
<script
157-
id="api-reference"
158-
data-configuration='${JSON.stringify(
159-
Object.assign(
160-
config,
161-
{
162-
content: embedSpec
163-
}
164-
)
165-
)}'
166-
>
167-
</script>
168-
<script src="${config.cdn}" crossorigin></script>
220+
<div id="app"></div>
221+
${getScriptTags(Object.assign(config, { content: embedSpec }) )}
169222
</body>
170223
</html>`

src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export interface ElysiaOpenAPIConfig<
131131
*'
132132
* @see https://github.com/scalar/scalar/blob/main/documentation/configuration.md
133133
*/
134-
scalar?: ApiReferenceConfiguration & {
134+
scalar?: Partial<ApiReferenceConfiguration> & {
135135
/**
136136
* Version to use for Scalar cdn bundle
137137
*

0 commit comments

Comments
 (0)