fumadocs-openapi 5.7.4 → 5.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +59 -27
- package/dist/index.js +182 -141
- package/dist/server/index.d.ts +39 -12
- package/dist/server/index.js +321 -172
- package/dist/ui/{client-client-Ddkf37Pm.js → client-client-D9KEBAUd.js} +7 -7
- package/dist/ui/index.d.ts +27 -10
- package/dist/ui/index.js +6 -5
- package/dist/ui/{playground-client-DPxpLHKJ.js → playground-client-C0GkAwm2.js} +2 -2
- package/package.json +11 -10
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OpenAPIV3 } from 'openapi-types';
|
|
1
|
+
import { OpenAPIV3_1, OpenAPIV3 } from 'openapi-types';
|
|
2
2
|
import Slugger from 'github-slugger';
|
|
3
3
|
import { ComponentType, ReactNode } from 'react';
|
|
4
4
|
import { CodeToHastOptionsCommon, CodeOptionsThemes, BuiltinTheme } from 'shiki';
|
|
@@ -72,6 +72,7 @@ interface APIInfoProps {
|
|
|
72
72
|
method: string;
|
|
73
73
|
route: string;
|
|
74
74
|
baseUrls: string[];
|
|
75
|
+
head: ReactNode;
|
|
75
76
|
children: ReactNode;
|
|
76
77
|
}
|
|
77
78
|
interface PropertyProps {
|
|
@@ -127,6 +128,11 @@ interface Renderer {
|
|
|
127
128
|
APIPlayground: ComponentType<APIPlaygroundProps>;
|
|
128
129
|
}
|
|
129
130
|
|
|
131
|
+
type NoReference<T> = T extends (infer I)[] ? NoReference<I>[] : T extends ReferenceObject ? Exclude<T, ReferenceObject> : T extends object ? {
|
|
132
|
+
[K in keyof T]: NoReference<T[K]>;
|
|
133
|
+
} : T;
|
|
134
|
+
type ParsedSchema = OpenAPIV3_1.SchemaObject;
|
|
135
|
+
|
|
130
136
|
/**
|
|
131
137
|
* Sample info of endpoint
|
|
132
138
|
*/
|
|
@@ -137,7 +143,7 @@ interface EndpointSample {
|
|
|
137
143
|
url: string;
|
|
138
144
|
method: string;
|
|
139
145
|
body?: {
|
|
140
|
-
schema:
|
|
146
|
+
schema: ParsedSchema;
|
|
141
147
|
mediaType: string;
|
|
142
148
|
sample: unknown;
|
|
143
149
|
};
|
|
@@ -147,12 +153,12 @@ interface EndpointSample {
|
|
|
147
153
|
interface ResponseSample {
|
|
148
154
|
mediaType: string;
|
|
149
155
|
sample: unknown;
|
|
150
|
-
schema:
|
|
156
|
+
schema: ParsedSchema;
|
|
151
157
|
}
|
|
152
158
|
interface ParameterSample {
|
|
153
159
|
name: string;
|
|
154
160
|
in: string;
|
|
155
|
-
schema:
|
|
161
|
+
schema: ParsedSchema;
|
|
156
162
|
sample: unknown;
|
|
157
163
|
}
|
|
158
164
|
|
|
@@ -162,22 +168,38 @@ interface CodeSample {
|
|
|
162
168
|
source: string | ((endpoint: EndpointSample) => string | undefined) | false;
|
|
163
169
|
}
|
|
164
170
|
|
|
171
|
+
type Document = OpenAPIV3_1.Document;
|
|
172
|
+
type OperationObject = OpenAPIV3_1.OperationObject;
|
|
173
|
+
type ParameterObject = OpenAPIV3_1.ParameterObject;
|
|
174
|
+
type SecurityRequirementObject = OpenAPIV3_1.SecurityRequirementObject;
|
|
175
|
+
type SecuritySchemeObject = OpenAPIV3_1.SecuritySchemeObject;
|
|
176
|
+
type ReferenceObject = OpenAPIV3_1.ReferenceObject;
|
|
177
|
+
type PathItemObject = OpenAPIV3_1.PathItemObject;
|
|
178
|
+
type TagObject = OpenAPIV3_1.TagObject;
|
|
165
179
|
interface RouteInformation {
|
|
166
180
|
path: string;
|
|
167
181
|
summary?: string;
|
|
168
182
|
description?: string;
|
|
169
183
|
methods: MethodInformation[];
|
|
170
184
|
}
|
|
171
|
-
|
|
172
|
-
parameters: OpenAPIV3.ParameterObject[];
|
|
185
|
+
type MethodInformation = NoReference<OperationObject> & {
|
|
173
186
|
method: string;
|
|
174
|
-
}
|
|
187
|
+
};
|
|
175
188
|
type Awaitable<T> = T | Promise<T>;
|
|
189
|
+
/**
|
|
190
|
+
* Dereferenced value and its original `$ref` value
|
|
191
|
+
*/
|
|
192
|
+
type DereferenceMap = Map<unknown, string>;
|
|
176
193
|
interface RenderContext {
|
|
177
194
|
renderer: Renderer;
|
|
178
|
-
|
|
195
|
+
/**
|
|
196
|
+
* dereferenced schema
|
|
197
|
+
*/
|
|
198
|
+
document: NoReference<Document>;
|
|
179
199
|
baseUrl: string;
|
|
200
|
+
baseUrls: string[];
|
|
180
201
|
slugger: Slugger;
|
|
202
|
+
dereferenceMap: DereferenceMap;
|
|
181
203
|
/**
|
|
182
204
|
* Generate TypeScript definitions from response schema.
|
|
183
205
|
*
|
|
@@ -194,24 +216,26 @@ interface RenderContext {
|
|
|
194
216
|
shikiOptions?: Omit<CodeToHastOptionsCommon, 'lang'> & CodeOptionsThemes<BuiltinTheme>;
|
|
195
217
|
}
|
|
196
218
|
|
|
219
|
+
type DocumentInput = string | OpenAPIV3_1.Document | OpenAPIV3.Document;
|
|
220
|
+
|
|
221
|
+
interface WebhookItem {
|
|
222
|
+
name: string;
|
|
223
|
+
method: OpenAPIV3_1.HttpMethods;
|
|
224
|
+
}
|
|
225
|
+
interface OperationItem {
|
|
226
|
+
path: string;
|
|
227
|
+
method: OpenAPIV3_1.HttpMethods;
|
|
228
|
+
}
|
|
229
|
+
|
|
197
230
|
type DocumentContext = {
|
|
198
231
|
type: 'tag';
|
|
199
|
-
tag:
|
|
200
|
-
routes: RouteInformation[];
|
|
232
|
+
tag: TagObject | undefined;
|
|
201
233
|
} | {
|
|
202
234
|
type: 'operation';
|
|
203
|
-
/**
|
|
204
|
-
* information of the route
|
|
205
|
-
*/
|
|
206
|
-
route: RouteInformation;
|
|
207
|
-
/**
|
|
208
|
-
* information of the method (API Endpoint)
|
|
209
|
-
*/
|
|
210
|
-
endpoint: MethodInformation;
|
|
211
235
|
} | {
|
|
212
236
|
type: 'file';
|
|
213
|
-
routes: RouteInformation[];
|
|
214
237
|
};
|
|
238
|
+
|
|
215
239
|
interface GenerateOptions {
|
|
216
240
|
/**
|
|
217
241
|
* Additional imports of your MDX components.
|
|
@@ -238,14 +262,22 @@ interface GenerateTagOutput {
|
|
|
238
262
|
tag: string;
|
|
239
263
|
content: string;
|
|
240
264
|
}
|
|
241
|
-
|
|
265
|
+
type GeneratePageOutput = {
|
|
266
|
+
type: 'operation';
|
|
267
|
+
pathItem: NoReference<PathItemObject>;
|
|
268
|
+
operation: NoReference<OperationObject>;
|
|
269
|
+
item: OperationItem;
|
|
242
270
|
content: string;
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
271
|
+
} | {
|
|
272
|
+
type: 'webhook';
|
|
273
|
+
pathItem: NoReference<PathItemObject>;
|
|
274
|
+
operation: NoReference<OperationObject>;
|
|
275
|
+
item: WebhookItem;
|
|
276
|
+
content: string;
|
|
277
|
+
};
|
|
278
|
+
declare function generateAll(pathOrDocument: DocumentInput, options?: GenerateOptions): Promise<string>;
|
|
279
|
+
declare function generatePages(pathOrDocument: DocumentInput, options?: GenerateOptions): Promise<GeneratePageOutput[]>;
|
|
280
|
+
declare function generateTags(pathOrDocument: DocumentInput, options?: GenerateOptions): Promise<GenerateTagOutput[]>;
|
|
249
281
|
|
|
250
282
|
interface Config extends GenerateOptions {
|
|
251
283
|
/**
|
|
@@ -284,4 +316,4 @@ interface Config extends GenerateOptions {
|
|
|
284
316
|
}
|
|
285
317
|
declare function generateFiles(options: Config): Promise<void>;
|
|
286
318
|
|
|
287
|
-
export { type Config, type
|
|
319
|
+
export { type Config, type DereferenceMap, type Document, type GenerateOptions, type GeneratePageOutput, type GenerateTagOutput, type MethodInformation, type OperationObject, type ParameterObject, type PathItemObject, type ReferenceObject, type RenderContext, type RouteInformation, type SecurityRequirementObject, type SecuritySchemeObject, type TagObject, generateAll, generateFiles, generatePages, generateTags };
|
package/dist/index.js
CHANGED
|
@@ -1,29 +1,11 @@
|
|
|
1
1
|
import { resolve, join, parse, dirname } from 'node:path';
|
|
2
|
-
import Parser from '@apidevtools/json-schema-ref-parser';
|
|
3
2
|
import { dump } from 'js-yaml';
|
|
4
3
|
import Slugger from 'github-slugger';
|
|
4
|
+
import Parser from '@apidevtools/json-schema-ref-parser';
|
|
5
|
+
import { upgrade } from '@scalar/openapi-parser';
|
|
5
6
|
import { mkdir, writeFile } from 'node:fs/promises';
|
|
6
7
|
import fg from 'fast-glob';
|
|
7
8
|
|
|
8
|
-
function noRef(v) {
|
|
9
|
-
return v;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Summarize method endpoint information
|
|
14
|
-
*/ function createMethod(method, path, operation) {
|
|
15
|
-
return {
|
|
16
|
-
description: path.description,
|
|
17
|
-
summary: path.summary,
|
|
18
|
-
...operation,
|
|
19
|
-
parameters: [
|
|
20
|
-
...noRef(operation.parameters ?? []),
|
|
21
|
-
...noRef(path.parameters ?? [])
|
|
22
|
-
],
|
|
23
|
-
method: method.toUpperCase()
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
9
|
const methodKeys = [
|
|
28
10
|
'get',
|
|
29
11
|
'post',
|
|
@@ -32,38 +14,34 @@ const methodKeys = [
|
|
|
32
14
|
'head',
|
|
33
15
|
'put'
|
|
34
16
|
];
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
17
|
+
function getAPIPageItems(document) {
|
|
18
|
+
const result = {
|
|
19
|
+
webhooks: [],
|
|
20
|
+
operations: []
|
|
21
|
+
};
|
|
22
|
+
for (const [path, pathItem] of Object.entries(document.paths ?? {})){
|
|
40
23
|
if (!pathItem) continue;
|
|
41
|
-
const methodMap = new Map();
|
|
42
24
|
for (const methodKey of methodKeys){
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const tags = operation.tags ?? [];
|
|
47
|
-
for (const tag of [
|
|
48
|
-
...tags,
|
|
49
|
-
'all'
|
|
50
|
-
]){
|
|
51
|
-
const list = methodMap.get(tag) ?? [];
|
|
52
|
-
list.push(info);
|
|
53
|
-
methodMap.set(tag, list);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
for (const [tag, methods] of methodMap.entries()){
|
|
57
|
-
const list = map.get(tag) ?? [];
|
|
58
|
-
list.push({
|
|
59
|
-
...pathItem,
|
|
25
|
+
if (!pathItem[methodKey]) continue;
|
|
26
|
+
result.operations.push({
|
|
27
|
+
method: methodKey,
|
|
60
28
|
path,
|
|
61
|
-
|
|
29
|
+
tags: pathItem[methodKey]?.tags
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
for (const [name, pathItem] of Object.entries(document.webhooks ?? {})){
|
|
34
|
+
if (!pathItem) continue;
|
|
35
|
+
for (const methodKey of methodKeys){
|
|
36
|
+
if (!pathItem[methodKey]) continue;
|
|
37
|
+
result.webhooks.push({
|
|
38
|
+
method: methodKey,
|
|
39
|
+
name,
|
|
40
|
+
tags: pathItem[methodKey]?.tags
|
|
62
41
|
});
|
|
63
|
-
map.set(tag, list);
|
|
64
42
|
}
|
|
65
43
|
}
|
|
66
|
-
return
|
|
44
|
+
return result;
|
|
67
45
|
}
|
|
68
46
|
|
|
69
47
|
function idToTitle(id) {
|
|
@@ -83,10 +61,11 @@ function generateDocument(options) {
|
|
|
83
61
|
const out = [];
|
|
84
62
|
const extend = frontmatter?.(options.title, options.description, options.context);
|
|
85
63
|
let meta;
|
|
86
|
-
if (options.
|
|
64
|
+
if (options.page.operations?.length === 1) {
|
|
65
|
+
const operation = options.page.operations[0];
|
|
87
66
|
meta = {
|
|
88
|
-
method:
|
|
89
|
-
route:
|
|
67
|
+
method: operation.method.toUpperCase(),
|
|
68
|
+
route: operation.path
|
|
90
69
|
};
|
|
91
70
|
}
|
|
92
71
|
const data = generateStaticData(options.dereferenced, options.page);
|
|
@@ -117,8 +96,8 @@ function generateStaticData(dereferenced, props) {
|
|
|
117
96
|
headings: [],
|
|
118
97
|
contents: []
|
|
119
98
|
};
|
|
120
|
-
for (const item of props.operations){
|
|
121
|
-
const operation = dereferenced.paths[item.path]?.[item.method];
|
|
99
|
+
for (const item of props.operations ?? []){
|
|
100
|
+
const operation = dereferenced.paths?.[item.path]?.[item.method];
|
|
122
101
|
if (!operation) continue;
|
|
123
102
|
if (props.hasHead && operation.operationId) {
|
|
124
103
|
const title = operation.summary ?? (operation.operationId ? idToTitle(operation.operationId) : item.path);
|
|
@@ -144,107 +123,156 @@ function generateStaticData(dereferenced, props) {
|
|
|
144
123
|
};
|
|
145
124
|
}
|
|
146
125
|
function pageContent(props) {
|
|
147
|
-
|
|
126
|
+
// filter extra properties in props
|
|
127
|
+
const operations = (props.operations ?? []).map((item)=>({
|
|
128
|
+
path: item.path,
|
|
129
|
+
method: item.method
|
|
130
|
+
}));
|
|
131
|
+
const webhooks = (props.webhooks ?? []).map((item)=>({
|
|
132
|
+
name: item.name,
|
|
133
|
+
method: item.method
|
|
134
|
+
}));
|
|
135
|
+
return `<APIPage document={${JSON.stringify(props.document)}} operations={${JSON.stringify(operations)}} webhooks={${JSON.stringify(webhooks)}} hasHead={${JSON.stringify(props.hasHead)}} />`;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const cache = new Map();
|
|
139
|
+
/**
|
|
140
|
+
* process & reference input document to a Fumadocs OpenAPI compatible format
|
|
141
|
+
*/ async function processDocument(document, disableCache = false) {
|
|
142
|
+
const cached = !disableCache && typeof document === 'string' ? cache.get(document) : null;
|
|
143
|
+
if (cached) return cached;
|
|
144
|
+
let bundled = await Parser.bundle(document, {
|
|
145
|
+
mutateInputSchema: false
|
|
146
|
+
});
|
|
147
|
+
bundled = upgrade(bundled).specification;
|
|
148
|
+
const dereferenceMap = new Map();
|
|
149
|
+
const dereferenced = await Parser.dereference(bundled, {
|
|
150
|
+
mutateInputSchema: true,
|
|
151
|
+
dereference: {
|
|
152
|
+
onDereference ($ref, schema) {
|
|
153
|
+
dereferenceMap.set(schema, $ref);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
const processed = {
|
|
158
|
+
document: dereferenced,
|
|
159
|
+
dereferenceMap
|
|
160
|
+
};
|
|
161
|
+
if (!disableCache && typeof document === 'string') {
|
|
162
|
+
cache.set(document, processed);
|
|
163
|
+
}
|
|
164
|
+
return processed;
|
|
148
165
|
}
|
|
149
166
|
|
|
150
167
|
async function dereference(pathOrDocument, options) {
|
|
151
|
-
return await
|
|
152
|
-
typeof pathOrDocument === 'string' && !pathOrDocument.startsWith('http://') && !pathOrDocument.startsWith('https://') ? resolve(options.cwd ?? process.cwd(), pathOrDocument) : pathOrDocument);
|
|
168
|
+
return await processDocument(// resolve paths
|
|
169
|
+
typeof pathOrDocument === 'string' && !pathOrDocument.startsWith('http://') && !pathOrDocument.startsWith('https://') ? resolve(options.cwd ?? process.cwd(), pathOrDocument) : pathOrDocument).then((res)=>res.document);
|
|
153
170
|
}
|
|
154
171
|
async function generateAll(pathOrDocument, options = {}) {
|
|
155
172
|
const document = await dereference(pathOrDocument, options);
|
|
156
|
-
const
|
|
157
|
-
const operations = [];
|
|
158
|
-
for (const route of routes){
|
|
159
|
-
for (const method of route.methods){
|
|
160
|
-
operations.push({
|
|
161
|
-
method: method.method.toLowerCase(),
|
|
162
|
-
path: route.path
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
}
|
|
173
|
+
const items = getAPIPageItems(document);
|
|
166
174
|
return generateDocument({
|
|
167
175
|
...options,
|
|
168
176
|
dereferenced: document,
|
|
169
177
|
title: document.info.title,
|
|
170
178
|
description: document.info.description,
|
|
171
179
|
page: {
|
|
172
|
-
operations,
|
|
180
|
+
operations: items.operations,
|
|
181
|
+
webhooks: items.webhooks,
|
|
173
182
|
hasHead: true,
|
|
174
183
|
document: pathOrDocument
|
|
175
184
|
},
|
|
176
185
|
context: {
|
|
177
|
-
type: 'file'
|
|
178
|
-
routes
|
|
186
|
+
type: 'file'
|
|
179
187
|
}
|
|
180
188
|
});
|
|
181
189
|
}
|
|
182
|
-
async function
|
|
190
|
+
async function generatePages(pathOrDocument, options = {}) {
|
|
183
191
|
const document = await dereference(pathOrDocument, options);
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
192
|
+
const items = getAPIPageItems(document);
|
|
193
|
+
const result = [];
|
|
194
|
+
for (const item of items.operations){
|
|
195
|
+
const pathItem = document.paths?.[item.path];
|
|
196
|
+
if (!pathItem) continue;
|
|
197
|
+
const operation = pathItem[item.method];
|
|
198
|
+
if (!operation) continue;
|
|
199
|
+
result.push({
|
|
200
|
+
type: 'operation',
|
|
201
|
+
pathItem,
|
|
202
|
+
operation,
|
|
203
|
+
item,
|
|
204
|
+
content: generateDocument({
|
|
189
205
|
...options,
|
|
190
206
|
page: {
|
|
191
207
|
operations: [
|
|
192
|
-
|
|
193
|
-
path: route.path,
|
|
194
|
-
method: method.method.toLowerCase()
|
|
195
|
-
}
|
|
208
|
+
item
|
|
196
209
|
],
|
|
197
210
|
hasHead: false,
|
|
198
211
|
document: pathOrDocument
|
|
199
212
|
},
|
|
200
213
|
dereferenced: document,
|
|
201
|
-
title:
|
|
202
|
-
description:
|
|
214
|
+
title: operation.summary ?? pathItem.summary ?? idToTitle(operation.operationId ?? 'unknown'),
|
|
215
|
+
description: operation.description ?? pathItem.description,
|
|
203
216
|
context: {
|
|
204
|
-
type: 'operation'
|
|
205
|
-
endpoint: method,
|
|
206
|
-
route
|
|
217
|
+
type: 'operation'
|
|
207
218
|
}
|
|
208
|
-
})
|
|
209
|
-
return {
|
|
210
|
-
content,
|
|
211
|
-
route,
|
|
212
|
-
method
|
|
213
|
-
};
|
|
219
|
+
})
|
|
214
220
|
});
|
|
215
|
-
}
|
|
221
|
+
}
|
|
222
|
+
for (const item of items.webhooks){
|
|
223
|
+
const pathItem = document.webhooks?.[item.name];
|
|
224
|
+
if (!pathItem) continue;
|
|
225
|
+
const operation = pathItem[item.method];
|
|
226
|
+
if (!operation) continue;
|
|
227
|
+
result.push({
|
|
228
|
+
type: 'webhook',
|
|
229
|
+
pathItem,
|
|
230
|
+
operation,
|
|
231
|
+
item,
|
|
232
|
+
content: generateDocument({
|
|
233
|
+
...options,
|
|
234
|
+
page: {
|
|
235
|
+
webhooks: [
|
|
236
|
+
item
|
|
237
|
+
],
|
|
238
|
+
hasHead: false,
|
|
239
|
+
document: pathOrDocument
|
|
240
|
+
},
|
|
241
|
+
dereferenced: document,
|
|
242
|
+
title: operation.summary ?? pathItem.summary ?? idToTitle(item.name),
|
|
243
|
+
description: operation.description ?? pathItem.description,
|
|
244
|
+
context: {
|
|
245
|
+
type: 'operation'
|
|
246
|
+
}
|
|
247
|
+
})
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
return result;
|
|
216
251
|
}
|
|
217
252
|
async function generateTags(pathOrDocument, options = {}) {
|
|
218
253
|
const document = await dereference(pathOrDocument, options);
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
operations.push({
|
|
226
|
-
method: method.method.toLowerCase(),
|
|
227
|
-
path: route.path
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
const displayName = info && 'x-displayName' in info && typeof info['x-displayName'] === 'string' ? info['x-displayName'] : idToTitle(tag);
|
|
254
|
+
if (!document.tags) return [];
|
|
255
|
+
const items = getAPIPageItems(document);
|
|
256
|
+
return document.tags.map((tag)=>{
|
|
257
|
+
const webhooks = items.webhooks.filter((v)=>v.tags && v.tags.includes(tag.name));
|
|
258
|
+
const operations = items.operations.filter((v)=>v.tags && v.tags.includes(tag.name));
|
|
259
|
+
const displayName = tag && 'x-displayName' in tag && typeof tag['x-displayName'] === 'string' ? tag['x-displayName'] : idToTitle(tag.name);
|
|
232
260
|
return {
|
|
233
|
-
tag,
|
|
261
|
+
tag: tag.name,
|
|
234
262
|
content: generateDocument({
|
|
235
263
|
...options,
|
|
236
264
|
page: {
|
|
237
265
|
document: pathOrDocument,
|
|
238
266
|
operations,
|
|
267
|
+
webhooks,
|
|
239
268
|
hasHead: true
|
|
240
269
|
},
|
|
241
270
|
dereferenced: document,
|
|
242
271
|
title: displayName,
|
|
243
|
-
description:
|
|
272
|
+
description: tag?.description,
|
|
244
273
|
context: {
|
|
245
274
|
type: 'tag',
|
|
246
|
-
tag
|
|
247
|
-
routes
|
|
275
|
+
tag
|
|
248
276
|
}
|
|
249
277
|
})
|
|
250
278
|
};
|
|
@@ -272,7 +300,28 @@ async function generateFiles(options) {
|
|
|
272
300
|
}),
|
|
273
301
|
...urlInputs
|
|
274
302
|
];
|
|
275
|
-
|
|
303
|
+
function getOutputPaths(name, result) {
|
|
304
|
+
const outPaths = [];
|
|
305
|
+
if (groupBy === 'tag') {
|
|
306
|
+
const tags = result.operation.tags;
|
|
307
|
+
if (tags && tags.length > 0) {
|
|
308
|
+
for (const tag of tags){
|
|
309
|
+
outPaths.push(join(outputDir, getFilename(tag), `${getFilename(name)}.mdx`));
|
|
310
|
+
}
|
|
311
|
+
} else {
|
|
312
|
+
outPaths.push(result.type === 'operation' ? join(outputDir, `${getFilename(name)}.mdx`) : join(outputDir, 'webhooks', `${getFilename(name)}.mdx`));
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (groupBy === 'route') {
|
|
316
|
+
const dir = result.pathItem.summary ? getFilename(result.pathItem.summary) : getFilenameFromRoute(result.type === 'operation' ? result.item.path : result.item.name);
|
|
317
|
+
outPaths.push(join(outputDir, dir, `${getFilename(name)}.mdx`));
|
|
318
|
+
}
|
|
319
|
+
if (groupBy === 'none') {
|
|
320
|
+
outPaths.push(join(outputDir, `${getFilename(name)}.mdx`));
|
|
321
|
+
}
|
|
322
|
+
return outPaths;
|
|
323
|
+
}
|
|
324
|
+
async function generateFromDocument(pathOrUrl) {
|
|
276
325
|
if (per === 'file') {
|
|
277
326
|
let filename = isUrl(pathOrUrl) ? 'index' : parse(pathOrUrl).name;
|
|
278
327
|
if (nameFn) filename = nameFn('file', filename);
|
|
@@ -280,49 +329,41 @@ async function generateFiles(options) {
|
|
|
280
329
|
const result = await generateAll(pathOrUrl, options);
|
|
281
330
|
await write(outPath, result);
|
|
282
331
|
console.log(`Generated: ${outPath}`);
|
|
283
|
-
return;
|
|
284
332
|
}
|
|
285
333
|
if (per === 'operation') {
|
|
286
334
|
const metaFiles = new Set();
|
|
287
|
-
const results = await
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
if (!
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
const metaFile = join(dirname(outPath), 'meta.json');
|
|
299
|
-
if (result.route.summary && !metaFiles.has(metaFile)) {
|
|
335
|
+
const results = await generatePages(pathOrUrl, options);
|
|
336
|
+
for (const result of results){
|
|
337
|
+
let name = result.type === 'operation' ? result.operation.operationId : result.item.name;
|
|
338
|
+
if (!name) return;
|
|
339
|
+
name = name.split('.').at(-1) ?? name;
|
|
340
|
+
for (const outPath of getOutputPaths(name, result)){
|
|
341
|
+
await write(outPath, result.content);
|
|
342
|
+
console.log(`Generated: ${outPath}`);
|
|
343
|
+
if (groupBy === 'route') {
|
|
344
|
+
const metaFile = join(dirname(outPath), 'meta.json');
|
|
345
|
+
if (!result.pathItem.summary || metaFiles.has(metaFile)) continue;
|
|
300
346
|
metaFiles.add(metaFile);
|
|
301
347
|
await write(metaFile, JSON.stringify({
|
|
302
|
-
title: result.
|
|
303
|
-
}));
|
|
348
|
+
title: result.pathItem.summary
|
|
349
|
+
}, null, 2));
|
|
304
350
|
console.log(`Generated Meta: ${metaFile}`);
|
|
305
351
|
}
|
|
306
|
-
outPaths.push(outPath);
|
|
307
|
-
} else {
|
|
308
|
-
outPaths.push(join(outputDir, `${getFilename(id)}.mdx`));
|
|
309
|
-
}
|
|
310
|
-
for (const outPath of outPaths){
|
|
311
|
-
await write(outPath, result.content);
|
|
312
|
-
console.log(`Generated: ${outPath}`);
|
|
313
352
|
}
|
|
314
|
-
}
|
|
315
|
-
return;
|
|
353
|
+
}
|
|
316
354
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
355
|
+
if (per === 'tag') {
|
|
356
|
+
const results = await generateTags(pathOrUrl, options);
|
|
357
|
+
for (const result of results){
|
|
358
|
+
let tagName = result.tag;
|
|
359
|
+
tagName = nameFn?.('tag', tagName) ?? getFilename(tagName);
|
|
360
|
+
const outPath = join(outputDir, `${tagName}.mdx`);
|
|
361
|
+
await write(outPath, result.content);
|
|
362
|
+
console.log(`Generated: ${outPath}`);
|
|
363
|
+
}
|
|
324
364
|
}
|
|
325
|
-
}
|
|
365
|
+
}
|
|
366
|
+
await Promise.all(resolvedInputs.map(generateFromDocument));
|
|
326
367
|
}
|
|
327
368
|
function isUrl(input) {
|
|
328
369
|
return input.startsWith('https://') || input.startsWith('http://');
|
|
@@ -340,4 +381,4 @@ async function write(path, content) {
|
|
|
340
381
|
await writeFile(path, content);
|
|
341
382
|
}
|
|
342
383
|
|
|
343
|
-
export { generateAll, generateFiles,
|
|
384
|
+
export { generateAll, generateFiles, generatePages, generateTags };
|