fumadocs-openapi 5.0.0 → 5.0.1

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.
@@ -180,7 +180,8 @@ interface RenderContext {
180
180
  generateCodeSamples?: (endpoint: EndpointSample) => Awaitable<CodeSample[]>;
181
181
  }
182
182
 
183
- interface ApiPageProps {
183
+ interface ApiPageProps extends Pick<RenderContext, 'generateCodeSamples' | 'generateTypeScriptSchema'> {
184
+ document: OpenAPIV3.Document;
184
185
  /**
185
186
  * An array of operation
186
187
  */
@@ -189,15 +190,14 @@ interface ApiPageProps {
189
190
  method: OpenAPIV3.HttpMethods;
190
191
  }[];
191
192
  hasHead: boolean;
192
- ctx: RenderContext;
193
+ renderer?: Partial<Renderer>;
193
194
  }
194
195
 
195
- interface OpenAPIOptions extends Pick<RenderContext, 'generateCodeSamples' | 'generateTypeScriptSchema'> {
196
+ interface OpenAPIOptions extends Omit<Partial<ApiPageProps>, 'document'> {
196
197
  documentOrPath: string | OpenAPIV3.Document;
197
- renderer?: Partial<Renderer>;
198
198
  }
199
199
  interface OpenAPIServer {
200
- APIPage: FC<Omit<ApiPageProps, 'ctx'>>;
200
+ APIPage: FC<Omit<ApiPageProps, 'document'>>;
201
201
  }
202
202
  declare function createOpenAPI(options: OpenAPIOptions): OpenAPIServer;
203
203
 
@@ -1,4 +1,4 @@
1
- import { jsx, jsxs } from 'react/jsx-runtime';
1
+ import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
2
2
  import Parser from '@apidevtools/json-schema-ref-parser';
3
3
  import Slugger from 'github-slugger';
4
4
  import { createElement, Fragment, useMemo } from 'react';
@@ -436,6 +436,8 @@ function isObject(schema) {
436
436
  }
437
437
  function Schema({ name, schema, ctx }) {
438
438
  if (schema.readOnly === true && !ctx.readOnly || schema.writeOnly === true && !ctx.writeOnly) return null;
439
+ const parseObject = ctx.parseObject ?? true;
440
+ const stack = ctx.stack ?? [];
439
441
  const { renderer } = ctx.render;
440
442
  const child = [];
441
443
  function field(key, value) {
@@ -450,7 +452,7 @@ function Schema({ name, schema, ctx }) {
450
452
  }, key));
451
453
  }
452
454
  // object type
453
- if (isObject(schema) && ctx.parseObject) {
455
+ if (isObject(schema) && parseObject) {
454
456
  const { additionalProperties, properties } = schema;
455
457
  if (additionalProperties === true) {
456
458
  child.push(/*#__PURE__*/ jsx(renderer.Property, {
@@ -496,7 +498,7 @@ function Schema({ name, schema, ctx }) {
496
498
  if (schema.enum) {
497
499
  field('Value in', schema.enum.map((value)=>JSON.stringify(value)).join(' | '));
498
500
  }
499
- if (isObject(schema) && !ctx.parseObject) {
501
+ if (isObject(schema) && !parseObject) {
500
502
  child.push(/*#__PURE__*/ jsx(renderer.ObjectCollapsible, {
501
503
  name: "Attributes",
502
504
  children: /*#__PURE__*/ jsx(Schema, {
@@ -531,8 +533,7 @@ function Schema({ name, schema, ctx }) {
531
533
  ...schema.type === 'array' ? [
532
534
  schema.items
533
535
  ] : []
534
- ].map(noRef).filter((s)=>isComplexType(s) && !ctx.stack.includes(s));
535
- ctx.stack.push(schema);
536
+ ].map(noRef).filter((s)=>isComplexType(s) && !stack.includes(s));
536
537
  const renderedMentionedTypes = mentionedObjectTypes.map((s, idx)=>{
537
538
  return /*#__PURE__*/ jsx(renderer.ObjectCollapsible, {
538
539
  name: s.title ?? `Object ${(idx + 1).toString()}`,
@@ -541,6 +542,10 @@ function Schema({ name, schema, ctx }) {
541
542
  schema: noRef(s),
542
543
  ctx: {
543
544
  ...ctx,
545
+ stack: [
546
+ schema,
547
+ ...stack
548
+ ],
544
549
  parseObject: true,
545
550
  required: false
546
551
  }
@@ -548,7 +553,6 @@ function Schema({ name, schema, ctx }) {
548
553
  }, `mentioned:${idx.toString()}`);
549
554
  });
550
555
  child.push(...renderedMentionedTypes);
551
- ctx.stack.pop();
552
556
  }
553
557
  return /*#__PURE__*/ jsx(renderer.Property, {
554
558
  name: name,
@@ -605,7 +609,7 @@ function getSchemaType(schema, ctx) {
605
609
  if (schema.anyOf) {
606
610
  return `Any properties in ${schema.anyOf.map((one)=>getSchemaType(noRef(one), ctx)).join(', ')}`;
607
611
  }
608
- if (schema.type === 'string' && schema.format === 'binary' && ctx.allowFile) return 'File';
612
+ if (schema.type === 'string' && schema.format === 'binary' && ctx.allowFile) return 'file';
609
613
  if (schema.type) return schema.type;
610
614
  if (isObject(schema)) return 'object';
611
615
  return 'unknown';
@@ -661,13 +665,11 @@ function Operation({ path, method, ctx, hasHead }) {
661
665
  name: "body",
662
666
  schema: noRef(body.content[type].schema ?? {}),
663
667
  ctx: {
664
- parseObject: true,
665
668
  readOnly: method.method === 'GET',
666
669
  writeOnly: method.method !== 'GET',
667
670
  required: body.required ?? false,
668
671
  render: ctx,
669
- allowFile: type === 'multipart/form-data',
670
- stack: []
672
+ allowFile: type === 'multipart/form-data'
671
673
  }
672
674
  })
673
675
  ]
@@ -698,9 +700,7 @@ function Operation({ path, method, ctx, hasHead }) {
698
700
  readOnly: method.method === 'GET',
699
701
  writeOnly: method.method !== 'GET',
700
702
  required: param.required ?? false,
701
- render: ctx,
702
- allowFile: false,
703
- stack: []
703
+ render: ctx
704
704
  }
705
705
  }, param.name));
706
706
  parameterGroups.set(groupName, group);
@@ -922,24 +922,6 @@ function createMethod(method, operation) {
922
922
  };
923
923
  }
924
924
 
925
- function APIPage({ operations, ctx, hasHead = true }) {
926
- const schema = ctx.document;
927
- return /*#__PURE__*/ jsx(ctx.renderer.Root, {
928
- baseUrl: ctx.baseUrl,
929
- children: operations.map((item)=>{
930
- const operation = schema.paths[item.path]?.[item.method];
931
- if (!operation) return null;
932
- const method = createMethod(item.method, operation);
933
- return /*#__PURE__*/ jsx(Operation, {
934
- method: method,
935
- path: item.path,
936
- ctx: ctx,
937
- hasHead: hasHead
938
- }, `${item.path}:${item.method}`);
939
- })
940
- });
941
- }
942
-
943
925
  const highlighter = await createHighlighter({
944
926
  themes: Object.values(bundledThemes),
945
927
  langs: Object.values(bundledLanguages)
@@ -1002,17 +984,23 @@ const defaultRenderer = {
1002
984
  APIPlayground
1003
985
  };
1004
986
 
1005
- function createOpenAPI(options) {
1006
- const document = Parser.dereference(options.documentOrPath);
1007
- return {
1008
- APIPage: async (props)=>{
1009
- const ctx = getContext(await document, options);
1010
- return /*#__PURE__*/ jsx(APIPage, {
987
+ function APIPage(props) {
988
+ const { operations, document, hasHead = true } = props;
989
+ const ctx = getContext(document, props);
990
+ return /*#__PURE__*/ jsx(ctx.renderer.Root, {
991
+ baseUrl: ctx.baseUrl,
992
+ children: operations.map((item)=>{
993
+ const operation = document.paths[item.path]?.[item.method];
994
+ if (!operation) return null;
995
+ const method = createMethod(item.method, operation);
996
+ return /*#__PURE__*/ jsx(Operation, {
997
+ method: method,
998
+ path: item.path,
1011
999
  ctx: ctx,
1012
- ...props
1013
- });
1014
- }
1015
- };
1000
+ hasHead: hasHead
1001
+ }, `${item.path}:${item.method}`);
1002
+ })
1003
+ });
1016
1004
  }
1017
1005
  function getContext(document, options) {
1018
1006
  return {
@@ -1028,6 +1016,18 @@ function getContext(document, options) {
1028
1016
  };
1029
1017
  }
1030
1018
 
1019
+ function createOpenAPI(options) {
1020
+ const document = Parser.dereference(options.documentOrPath);
1021
+ return {
1022
+ APIPage: async (props)=>{
1023
+ return /*#__PURE__*/ jsx(APIPage, {
1024
+ document: await document,
1025
+ ...props
1026
+ });
1027
+ }
1028
+ };
1029
+ }
1030
+
1031
1031
  cva('rounded border px-1.5 py-1 text-xs font-medium leading-[12px]', {
1032
1032
  variants: {
1033
1033
  color: {
@@ -1063,18 +1063,19 @@ function getBadgeColor(method) {
1063
1063
  const data = file.data.data;
1064
1064
  if ('method' in data && typeof data.method === 'string') {
1065
1065
  const color = getBadgeColor(data.method);
1066
- node.name = [
1067
- node.name,
1068
- ' ',
1069
- // eslint-disable-next-line react/jsx-key -- static
1070
- /*#__PURE__*/ jsx("span", {
1071
- className: badgeVariants({
1072
- className: 'ms-auto text-nowrap',
1073
- color
1074
- }),
1075
- children: data.method
1076
- })
1077
- ];
1066
+ node.name = /*#__PURE__*/ jsxs(Fragment$1, {
1067
+ children: [
1068
+ node.name,
1069
+ ' ',
1070
+ /*#__PURE__*/ jsx("span", {
1071
+ className: badgeVariants({
1072
+ className: 'ms-auto text-nowrap',
1073
+ color
1074
+ }),
1075
+ children: data.method
1076
+ })
1077
+ ]
1078
+ });
1078
1079
  }
1079
1080
  return node;
1080
1081
  };
@@ -3,6 +3,7 @@ import { useContext, createContext, useState, useEffect } from 'react';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
  import { Check, Copy } from 'lucide-react';
5
5
  import { cn, useCopyButton, buttonVariants } from 'fumadocs-ui/components/api';
6
+ import dynamic from 'next/dynamic';
6
7
 
7
8
  const ApiContext = /*#__PURE__*/ createContext({
8
9
  baseUrl: undefined,
@@ -57,6 +58,7 @@ function useSchemaContext() {
57
58
  return ctx;
58
59
  }
59
60
 
61
+ const APIPlayground = dynamic(()=>import('./playground-client-Cn3a3hra.js').then((mod)=>mod.APIPlayground));
60
62
  function Root({ children, baseUrl, className, ...props }) {
61
63
  return /*#__PURE__*/ jsx("div", {
62
64
  className: cn('flex flex-col gap-24 text-sm text-fd-muted-foreground', className),
@@ -88,4 +90,4 @@ function CopyRouteButton({ className, route, ...props }) {
88
90
  });
89
91
  }
90
92
 
91
- export { CopyRouteButton as C, Root as R, SchemaContext as S, useApiContext as a, useSchemaContext as u };
93
+ export { APIPlayground as A, CopyRouteButton as C, Root as R, SchemaContext as S, useApiContext as a, useSchemaContext as u };
@@ -2,23 +2,6 @@ import * as react from 'react';
2
2
  import { ReactNode, ReactElement, MutableRefObject, HTMLAttributes } from 'react';
3
3
  import { FieldPath, ControllerRenderProps, ControllerFieldState, UseFormStateReturn } from 'react-hook-form';
4
4
 
5
- interface APIInfoProps {
6
- method: string;
7
- route: string;
8
- children: ReactNode;
9
- }
10
- interface PropertyProps {
11
- name: string;
12
- type: string;
13
- required?: boolean;
14
- deprecated?: boolean;
15
- children?: ReactNode;
16
- }
17
- interface RootProps {
18
- baseUrl?: string;
19
- children: ReactNode;
20
- }
21
-
22
5
  interface BaseRequestField {
23
6
  name: string;
24
7
  description?: string;
@@ -74,6 +57,23 @@ interface APIPlaygroundProps {
74
57
  schemas: Record<string, RequestSchema>;
75
58
  }
76
59
 
60
+ interface APIInfoProps {
61
+ method: string;
62
+ route: string;
63
+ children: ReactNode;
64
+ }
65
+ interface PropertyProps {
66
+ name: string;
67
+ type: string;
68
+ required?: boolean;
69
+ deprecated?: boolean;
70
+ children?: ReactNode;
71
+ }
72
+ interface RootProps {
73
+ baseUrl?: string;
74
+ children: ReactNode;
75
+ }
76
+
77
77
  interface FormValues {
78
78
  authorization: string;
79
79
  path: Record<string, unknown>;
@@ -106,8 +106,6 @@ type DynamicField = {
106
106
  };
107
107
  declare function useSchemaContext(): SchemaContextType;
108
108
 
109
- declare function Root({ children, baseUrl, className, ...props }: RootProps & HTMLAttributes<HTMLDivElement>): React.ReactElement;
110
-
111
109
  declare const APIPlayground: react.ComponentType<APIPlaygroundProps & {
112
110
  fields?: {
113
111
  auth?: CustomField<"authorization", PrimitiveRequestField>;
@@ -117,6 +115,8 @@ declare const APIPlayground: react.ComponentType<APIPlaygroundProps & {
117
115
  body?: CustomField<"body", RequestSchema>;
118
116
  };
119
117
  } & HTMLAttributes<HTMLFormElement>>;
118
+ declare function Root({ children, baseUrl, className, ...props }: RootProps & HTMLAttributes<HTMLDivElement>): React.ReactElement;
119
+
120
120
  declare function APIInfo({ children, className, route, badgeClassname, method, ...props }: APIInfoProps & HTMLAttributes<HTMLDivElement> & {
121
121
  badgeClassname?: string;
122
122
  }): React.ReactElement;
package/dist/ui/index.js CHANGED
@@ -1,11 +1,10 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import dynamic from 'next/dynamic';
3
2
  import { cn } from 'fumadocs-ui/components/api';
4
3
  import { Fragment } from 'react';
5
4
  import { Accordions, Accordion } from 'fumadocs-ui/components/accordion';
6
5
  import { cva } from 'class-variance-authority';
7
- import { C as CopyRouteButton } from './client-client-CbQJObP6.js';
8
- export { R as Root, u as useSchemaContext } from './client-client-CbQJObP6.js';
6
+ import { C as CopyRouteButton } from './client-client-CMzXLiVt.js';
7
+ export { A as APIPlayground, R as Root, u as useSchemaContext } from './client-client-CMzXLiVt.js';
9
8
 
10
9
  const badgeVariants = cva('rounded border px-1.5 py-1 text-xs font-medium leading-[12px]', {
11
10
  variants: {
@@ -33,7 +32,6 @@ function getBadgeColor(method) {
33
32
  }
34
33
  }
35
34
 
36
- const APIPlayground = dynamic(()=>import('./playground-client-W7yhm4ZD.js').then((mod)=>mod.APIPlayground));
37
35
  function Route({ route }) {
38
36
  const segments = route.split('/').filter((part)=>part.length > 0);
39
37
  return /*#__PURE__*/ jsx("div", {
@@ -141,4 +139,4 @@ function ObjectCollapsible(props) {
141
139
  });
142
140
  }
143
141
 
144
- export { API, APIExample, APIInfo, APIPlayground, ObjectCollapsible, Property };
142
+ export { API, APIExample, APIInfo, ObjectCollapsible, Property };
@@ -6,7 +6,7 @@ import { FormProvider, Controller, useFormContext, useFieldArray, useForm, useWa
6
6
  import useSWRImmutable from 'swr/immutable';
7
7
  import { Accordions, Accordion } from 'fumadocs-ui/components/accordion';
8
8
  import { cn, buttonVariants } from 'fumadocs-ui/components/api';
9
- import { u as useSchemaContext, a as useApiContext, S as SchemaContext } from './client-client-CbQJObP6.js';
9
+ import { u as useSchemaContext, a as useApiContext, S as SchemaContext } from './client-client-CMzXLiVt.js';
10
10
  import { Slot } from '@radix-ui/react-slot';
11
11
  import { cva } from 'class-variance-authority';
12
12
  import { CircleCheckIcon, CircleXIcon, ChevronDown, ChevronUp, Check, Trash2, Plus } from 'lucide-react';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumadocs-openapi",
3
- "version": "5.0.0",
3
+ "version": "5.0.1",
4
4
  "description": "Generate MDX docs for your OpenAPI spec",
5
5
  "keywords": [
6
6
  "NextJs",