OpenAPI: support watch option

This commit is contained in:
Fuma Nama
2026-03-27 17:43:07 +08:00
parent e21cd05fcc
commit a5186a7102
5 changed files with 44 additions and 5 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'fumadocs-openapi': patch
---
Support `watch` option
+1
View File
@@ -61,6 +61,7 @@
"@scalar/json-magic": "^0.12.4",
"@scalar/openapi-upgrader": "^0.2.2",
"ajv": "^8.18.0",
"chokidar": "^5.0.0",
"class-variance-authority": "^0.7.1",
"github-slugger": "^2.0.0",
"hast-util-to-jsx-runtime": "^2.3.6",
+27 -5
View File
@@ -6,6 +6,7 @@ import type { OpenAPIServer } from '@/server';
import { createGetUrl, getSlugs, PathUtils } from 'fumadocs-core/source';
import { createAutoPreset, type SchemaToPagesOptions } from '@/utils/pages/preset-auto';
import { fromSchema, type OutputGroup, type OutputEntry } from '@/utils/pages/builder';
import type { DistributiveOmit } from './types';
export interface OutputFile {
path: string;
@@ -76,7 +77,15 @@ interface MetaOptions {
groupStyle?: 'folder' | 'separator';
}
export type Config = SchemaToPagesOptions & GenerateFilesConfig;
export type Config = SchemaToPagesOptions &
GenerateFilesConfig & {
/**
* Re-generate when **schema files are changed**, ignores custom input functions & URLs.
*
* Note: it is recommended to configure & use `chokidar` on your own, this is only for simple cases.
*/
watch?: boolean;
};
interface BeforeWriteContext {
readonly generated: Record<string, OutputFile[]>;
@@ -85,12 +94,24 @@ interface BeforeWriteContext {
}
export async function generateFiles(options: Config): Promise<void> {
if (options.watch) {
const { watch } = await import('chokidar');
const subOptions: Config = { ...options, watch: false };
await generateFiles(subOptions);
const targets = options.input._getWatchPaths();
console.log(`[Fumadocs OpenAPI] watching ${targets.join(', ')}`);
watch(targets, {
ignoreInitial: true,
}).on('all', () => generateFiles(subOptions));
return;
}
const files = await generateFilesOnly(options);
const { output } = options;
await Promise.all(
files.map(async (file) => {
const filePath = path.join(output, file.path);
const filePath = path.join(options.output, file.path);
await mkdir(path.dirname(filePath), { recursive: true });
await writeFile(filePath, file.content);
@@ -100,7 +121,7 @@ export async function generateFiles(options: Config): Promise<void> {
}
export async function generateFilesOnly(
options: SchemaToPagesOptions & Omit<GenerateFilesConfig, 'output'>,
options: DistributiveOmit<Config, 'output'>,
): Promise<OutputFile[]> {
const schemas = await options.input.getSchemas();
@@ -115,7 +136,7 @@ export async function generateFilesOnly(
const preset = createAutoPreset(options);
for (const [id, schema] of entries) {
const entries = fromSchema(id, schema, preset);
const schemaFiles = (generated[id] ??= []);
const schemaFiles: OutputFile[] = [];
generatedEntries[id] = entries;
function scan(entry: OutputEntry) {
@@ -131,6 +152,7 @@ export async function generateFilesOnly(
}
for (const entry of entries) scan(entry);
generated[id] = schemaFiles;
files.push(...schemaFiles);
}
+7
View File
@@ -2,6 +2,7 @@ import { createProxy } from '@/server/proxy';
import { processDocument, type ProcessedDocument } from '@/utils/process-document';
import type { Document } from '@/types';
import type { InlineCodeUsageGenerator } from '@/requests/generators';
import fs from 'node:fs';
/**
* schema id -> file path, URL, or downloaded schema object
@@ -30,6 +31,8 @@ export interface OpenAPIServer {
createProxy: typeof createProxy;
getSchemas: () => Promise<ProcessedSchemaMap>;
getSchema: (document: string) => Promise<ProcessedDocument>;
/** @private internal API */
_getWatchPaths: () => string[];
readonly options: OpenAPIOptions;
}
@@ -54,6 +57,10 @@ export function createOpenAPI(options: OpenAPIOptions = {}): OpenAPIServer {
return {
options,
createProxy,
_getWatchPaths() {
const keys = Array.isArray(input) ? input : Object.keys(input);
return keys.filter((key) => !URL.canParse(key) && fs.existsSync(key));
},
async getSchema(document) {
const schemas = await this.getSchemas();
if (document in schemas) return schemas[document];
+4
View File
@@ -2509,6 +2509,9 @@ importers:
ajv:
specifier: ^8.18.0
version: 8.18.0
chokidar:
specifier: ^5.0.0
version: 5.0.0
class-variance-authority:
specifier: ^0.7.1
version: 0.7.1
@@ -7626,6 +7629,7 @@ packages:
[email protected]:
resolution: {integrity: sha512-AvXWYFO6j/ZQ7bhGm4X6eilq2JHsDVC90ZM32k2B7/srhC2gs3Sdki1QTbwrdRCo8o7eT+167vcB1yzOvPdbjA==}
cpu: [arm64, x64]
os: [darwin, linux, win32]
hasBin: true