OpenAPI: Support serverContext & createCodeSample for custom generateCodeSamples() function

This commit is contained in:
Fuma Nama
2025-08-12 10:52:58 +08:00
parent 9e6a9956d4
commit c07af6fb0b
5 changed files with 28 additions and 10 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'fumadocs-openapi': patch
---
Support `serverContext` & `createCodeSample` for custom `generateCodeSamples()` function
@@ -30,10 +30,21 @@ import {
AccordionTrigger,
} from '@/ui/components/accordion';
export interface CodeSample {
export interface CodeSample<T = unknown> {
lang: string;
label?: string;
source?: string | SampleGenerator | false;
/**
* either:
* - code
* - a function imported from a file with "use client" directive
* - false (disabled)
*/
source?: string | SampleGenerator<T> | false;
/**
* Pass extra context to client-side source generator
*/
serverContext?: T;
}
const ParamTypes = {
+2 -1
View File
@@ -2,11 +2,12 @@ import type { MediaAdapter } from '@/media/adapter';
import type { NoReference } from '@/utils/schema';
import type { ParameterObject } from '@/types';
export type SampleGenerator = (
export type SampleGenerator<ServerContext = unknown> = (
url: string,
data: RequestData,
context: {
mediaAdapters: Record<string, MediaAdapter>;
server: ServerContext;
},
) => string;
+5
View File
@@ -1,5 +1,6 @@
import type { ApiPageProps } from '@/render/api-page';
import { createProxy } from '@/server/proxy';
import type { CodeSample } from '@/render/operation';
export type OpenAPIOptions = Omit<Partial<ApiPageProps>, 'document'>;
@@ -19,3 +20,7 @@ export function createOpenAPI(options: OpenAPIOptions = {}): OpenAPIServer {
},
};
}
export function createCodeSample<T>(options: CodeSample<T>): CodeSample {
return options as CodeSample;
}
@@ -28,7 +28,6 @@ import {
withBase,
} from '@/utils/url';
import type { RawRequestData, RequestData } from '@/requests/_shared';
import { defaultSamples } from '@/requests';
type UpdateListener = (data: RawRequestData, encoded: RequestData) => void;
@@ -126,7 +125,7 @@ export function CodeExampleProvider({
);
}
export function CodeExample(props: CodeSample) {
export function CodeExample(sample: CodeSample) {
const { shikiOptions, mediaAdapters } = useApiContext();
const { examples, key, route, addListener, removeListener } =
useContext(CodeExampleContext)!;
@@ -135,10 +134,6 @@ export function CodeExample(props: CodeSample) {
return examples.find((example) => example.key === key)!.encoded;
});
const sample = props.source
? props
: defaultSamples.find((item) => item.label === props.label);
useEffect(() => {
const listener: UpdateListener = (_, encoded) => setData(encoded);
@@ -149,7 +144,7 @@ export function CodeExample(props: CodeSample) {
}, [addListener, removeListener]);
const code = useMemo(() => {
if (!sample?.source) return;
if (!sample.source) return;
if (typeof sample.source === 'string') return sample.source;
return sample.source(
@@ -164,6 +159,7 @@ export function CodeExample(props: CodeSample) {
),
data,
{
server: sample.serverContext,
mediaAdapters,
},
);