Skip to content

Commit 24775bd

Browse files
committed
OpenAPI: optimize
1 parent 12019fb commit 24775bd

File tree

14 files changed

+118
-75
lines changed

14 files changed

+118
-75
lines changed

packages/openapi/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@
6161
"@radix-ui/react-dialog": "^1.1.15",
6262
"@radix-ui/react-select": "^2.2.6",
6363
"@radix-ui/react-slot": "^1.2.3",
64-
"@scalar/json-magic": "^0.7.0",
65-
"@scalar/openapi-parser": "0.23.0",
64+
"@scalar/json-magic": "^0.6.1",
65+
"@scalar/openapi-parser": "0.22.3",
6666
"ajv": "^8.17.1",
6767
"class-variance-authority": "^0.7.1",
6868
"fumadocs-core": "workspace:*",
@@ -80,7 +80,7 @@
8080
"xml-js": "^1.6.11"
8181
},
8282
"devDependencies": {
83-
"@scalar/api-client-react": "^1.3.47",
83+
"@scalar/api-client-react": "^1.3.46",
8484
"@types/js-yaml": "^4.0.9",
8585
"@types/node": "24.10.0",
8686
"@types/openapi-sampler": "^1.0.3",

packages/openapi/src/playground/client.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,14 +194,14 @@ export default function PlaygroundClient({
194194
const defaultValues: FormValues = useMemo(() => {
195195
const requestData = examples.find(
196196
(example) => example.id === exampleId,
197-
)!.data;
197+
)?.data;
198198

199199
return {
200-
path: requestData.path,
201-
query: requestData.query,
202-
header: requestData.header,
203-
body: requestData.body,
204-
cookie: requestData.cookie,
200+
path: requestData?.path ?? {},
201+
query: requestData?.query ?? {},
202+
header: requestData?.header ?? {},
203+
body: requestData?.body ?? {},
204+
cookie: requestData?.cookie ?? {},
205205
};
206206
}, [examples, exampleId]);
207207

packages/openapi/src/playground/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ export type SecurityEntry = SecuritySchemeObject & {
3737
};
3838

3939
export async function APIPlayground({ path, method, ctx }: APIPlaygroundProps) {
40+
if (ctx.playground?.render) {
41+
return ctx.playground.render({ path, method, ctx });
42+
}
43+
4044
let currentId = 0;
4145
const bodyContent = method.requestBody?.content;
4246
const mediaType = bodyContent ? getPreferredType(bodyContent) : undefined;

packages/openapi/src/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type { MediaAdapter } from '@/requests/media/adapter';
66
import type { OpenAPIOptions } from '@/server';
77
import type { CreateAPIPageOptions } from './ui/api-page';
88
import type { CodeUsageGenerator } from './ui/operation/api-example';
9+
import type { ReactNode } from 'react';
910

1011
export type Document = V3_1.Document;
1112
export type OperationObject = V3_1.OperationObject;
@@ -38,4 +39,6 @@ export interface RenderContext
3839
schema: ProcessedDocument;
3940

4041
mediaAdapters: Record<string, MediaAdapter>;
42+
43+
renderHeading: (depth: number, text: string) => ReactNode;
4144
}

packages/openapi/src/ui/api-page.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type { APIPageClientOptions } from './client';
1515
import { cn } from 'fumadocs-ui/utils/cn';
1616
import type { CodeUsageGenerator, ResponseTab } from './operation/api-example';
1717
import { ApiProvider } from './contexts/api';
18+
import { Heading } from 'fumadocs-ui/components/heading';
1819

1920
type Awaitable<T> = T | Promise<T>;
2021

@@ -160,19 +161,26 @@ export function createAPIPage(
160161
? dereferenced.servers
161162
: [{ url: '/' }];
162163

164+
const slugger = new Slugger();
163165
const ctx: RenderContext = {
164166
schema: processed,
165167
proxyUrl: server.options.proxyUrl,
166-
showResponseSchema: options.showResponseSchema,
167-
shikiOptions: options.shikiOptions,
168-
generateTypeScriptSchema: options.generateTypeScriptSchema,
169-
generateCodeSamples: options.generateCodeSamples,
168+
...options,
170169
servers,
171170
mediaAdapters: {
172171
...defaultAdapters,
173172
...options.mediaAdapters,
174173
},
175-
slugger: new Slugger(),
174+
slugger,
175+
renderHeading(depth, text) {
176+
const id = slugger.slug(text);
177+
178+
return (
179+
<Heading id={id} key={id} as={`h${depth}` as `h1`}>
180+
{text}
181+
</Heading>
182+
);
183+
},
176184
};
177185

178186
return <APIPage {...props} ctx={ctx} />;

packages/openapi/src/ui/components/server/heading.tsx

Lines changed: 0 additions & 18 deletions
This file was deleted.

packages/openapi/src/ui/components/server/markdown.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {
44
rehypeCode,
55
type RehypeCodeOptions,
66
remarkGfm,
7-
remarkImage,
87
} from 'fumadocs-core/mdx-plugins';
98
import defaultMdxComponents from 'fumadocs-ui/mdx';
109
import { remark } from 'remark';
@@ -14,7 +13,6 @@ import * as JsxRuntime from 'react/jsx-runtime';
1413

1514
const processor = remark()
1615
.use(remarkGfm)
17-
.use(remarkImage, { useImport: false })
1816
.use(remarkRehype)
1917
.use(rehypeCode, {
2018
langs: [],

packages/openapi/src/ui/contexts/api.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,12 @@ function ServerSelectProvider({
173173
function getDefaultValues(
174174
server: NoReference<ServerObject>,
175175
): Record<string, string> {
176-
return Object.fromEntries(
177-
Object.entries(server.variables ?? {}).map(([k, v]) => [k, v.default]),
178-
);
176+
const out: Record<string, string> = {};
177+
if (!server.variables) return out;
178+
179+
for (const [k, v] of Object.entries(server.variables)) {
180+
out[k] = v.default;
181+
}
182+
183+
return out;
179184
}

packages/openapi/src/ui/contexts/operation.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export type ExampleUpdateListener = (
1818
const OperationContext = createContext<{
1919
route: string;
2020
examples: APIExampleItem[];
21-
example: string;
21+
example: string | undefined;
2222
setExample: (id: string) => void;
2323
setExampleData: (data: RawRequestData, encoded: RequestData) => void;
2424

@@ -38,7 +38,7 @@ export function OperationProvider({
3838
children: ReactNode;
3939
}) {
4040
const [example, setExample] = useState(
41-
() => defaultExampleId ?? examples[0].id,
41+
() => defaultExampleId ?? examples.at(0)?.id,
4242
);
4343
const listeners = useRef<ExampleUpdateListener[]>([]);
4444

packages/openapi/src/ui/operation/api-example.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -182,16 +182,18 @@ export async function APIExample({
182182

183183
if (method['x-codeSamples']) {
184184
for (const sample of method['x-codeSamples']) {
185-
generators.push({
186-
...sample,
187-
id: 'id' in sample ? (sample.id as string) : sample.lang,
188-
});
185+
generators.push(
186+
'id' in sample && typeof sample.id === 'string'
187+
? (sample as CodeUsageGenerator)
188+
: {
189+
id: sample.lang,
190+
...sample,
191+
},
192+
);
189193
}
190194
}
191195

192-
generators = dedupe(
193-
generators.filter((generator) => generator.source !== false),
194-
);
196+
generators = dedupe(generators);
195197

196198
return renderAPIExampleLayout(
197199
{
@@ -214,7 +216,7 @@ function dedupe(samples: CodeUsageGenerator[]): CodeUsageGenerator[] {
214216
const item = samples[i];
215217
if (set.has(item.id)) continue;
216218
set.add(item.id);
217-
out.unshift(item);
219+
if (item.source !== false) out.unshift(item);
218220
}
219221

220222
return out;

0 commit comments

Comments
 (0)