fumadocs-openapi 8.1.11 → 9.0.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.
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useState, } from 'react';
3
+ import { useMemo, useState, } from 'react';
4
4
  import { Plus, Trash2 } from '../icons.js';
5
5
  import { Controller, useController, useFieldArray, useFormContext, } from 'react-hook-form';
6
6
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../ui/components/select.js';
@@ -11,11 +11,17 @@ import { buttonVariants } from 'fumadocs-ui/components/ui/button';
11
11
  import { combineSchema } from '../utils/combine-schema.js';
12
12
  import { schemaToString } from '../utils/schema-to-string.js';
13
13
  import { anyFields, useFieldInfo, useResolvedSchema, } from '../playground/schema.js';
14
- function FieldHeader({ name, required = false, type, ...props }) {
15
- return (_jsxs("label", { ...props, className: cn('w-full inline-flex items-center gap-1', props.className), children: [_jsxs("span", { className: cn(labelVariants()), children: [name, required ? _jsx("span", { className: "text-red-400/80 mx-1", children: "*" }) : null] }), _jsx("div", { className: "flex-1" }), type ? (_jsx("code", { "data-type": true, className: "text-xs text-fd-muted-foreground", children: type })) : null, props.children] }));
14
+ function FieldHeader({ name, required = false, ...props }) {
15
+ return (_jsxs("label", { ...props, className: cn('w-full inline-flex items-center gap-1', props.className), children: [_jsxs("span", { className: cn(labelVariants(), 'me-auto'), children: [name, required ? _jsx("span", { className: "text-red-400/80 mx-1", children: "*" }) : null] }), props.children] }));
16
+ }
17
+ function FieldHeaderCode(props) {
18
+ return (_jsx("code", { ...props, className: cn('text-xs text-fd-muted-foreground', props.className), children: props.children }));
16
19
  }
17
20
  export function ObjectInput({ field: _field, fieldName, ...props }) {
18
- const field = useResolvedSchema(combineSchema([_field, ...(_field.allOf ?? []), ...(_field.anyOf ?? [])]));
21
+ const resolved = useResolvedSchema(_field);
22
+ const field = useMemo(() => combineSchema([resolved]), [resolved]);
23
+ if (typeof field === 'boolean')
24
+ return;
19
25
  return (_jsxs("div", { ...props, className: cn('flex flex-col gap-6', props.className), children: [Object.entries(field.properties ?? {}).map(([key, child]) => (_jsx(FieldSet, { name: key, field: child, fieldName: `${fieldName}.${key}`, isRequired: field.required?.includes(key) }, key))), (field.additionalProperties || field.patternProperties) && (_jsx(DynamicProperties, { fieldName: fieldName, filterKey: (v) => !field.properties || !Object.keys(field.properties).includes(v), getType: (key) => {
20
26
  for (const pattern in field.patternProperties) {
21
27
  if (key.match(RegExp(pattern))) {
@@ -64,27 +70,25 @@ function DynamicProperties({ fieldName, filterKey = () => true, getType = () =>
64
70
  return [...p, name];
65
71
  });
66
72
  };
67
- return (_jsxs(_Fragment, { children: [properties.map((item) => (_jsx(FieldSet, { name: item, field: getType(item), fieldName: `${fieldName}.${item}`, toolbar: _jsx("button", { type: "button", "aria-label": "Remove Item", className: cn(buttonVariants({
68
- color: 'ghost',
69
- className: 'p-1',
70
- })), onClick: () => {
71
- setProperties((p) => p.filter((prop) => prop !== item));
72
- control.unregister(`${fieldName}.${item}`);
73
- }, children: _jsx(Trash2, { className: "size-4" }) }) }, item))), _jsxs("div", { className: "flex gap-2", children: [_jsx(Input, { value: nextName, placeholder: "Enter Property Name", onChange: (e) => setNextName(e.target.value), onKeyDown: (e) => {
73
+ return (_jsxs(_Fragment, { children: [properties.map((item) => {
74
+ const type = getType(item);
75
+ return (_jsx(FieldSet, { name: item, field: type, fieldName: `${fieldName}.${item}`, toolbar: _jsx("button", { type: "button", "aria-label": "Remove Item", className: cn(buttonVariants({
76
+ color: 'ghost',
77
+ size: 'icon-sm',
78
+ className: 'p-1',
79
+ })), onClick: () => {
80
+ setProperties((p) => p.filter((prop) => prop !== item));
81
+ control.unregister(`${fieldName}.${item}`);
82
+ }, children: _jsx(Trash2, {}) }) }, item));
83
+ }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Input, { value: nextName, placeholder: "Enter Property Name", onChange: (e) => setNextName(e.target.value), onKeyDown: (e) => {
74
84
  if (e.key === 'Enter') {
75
85
  onAppend();
76
86
  e.preventDefault();
77
87
  }
78
88
  } }), _jsx("button", { type: "button", className: cn(buttonVariants({ color: 'secondary', size: 'sm' }), 'px-4'), onClick: onAppend, children: "New" })] })] }));
79
89
  }
80
- export function FieldInput({ field, fieldName, isRequired, ...props }) {
90
+ function FieldInput({ field, fieldName, isRequired, ...props }) {
81
91
  const { control, register } = useFormContext();
82
- if (field.type === 'object') {
83
- return (_jsx(ObjectInput, { field: field, fieldName: fieldName, ...props, className: cn('rounded-lg border border-fd-primary/20 bg-fd-background/50 p-3 shadow-sm', props.className) }));
84
- }
85
- if (field.type === 'array') {
86
- return (_jsx(ArrayInput, { fieldName: fieldName, items: field.items ?? anyFields, ...props, className: cn('rounded-lg border border-fd-primary/20 bg-fd-background/50 p-3 shadow-sm', props.className) }));
87
- }
88
92
  if (field.type === 'string' && field.format === 'binary') {
89
93
  return (_jsx(Controller, { control: control, name: fieldName, render: ({ field: { value: _, onChange, ...restField } }) => (_jsx("input", { id: fieldName, type: "file", multiple: false, onChange: (e) => {
90
94
  if (!e.target.files)
@@ -95,39 +99,53 @@ export function FieldInput({ field, fieldName, isRequired, ...props }) {
95
99
  if (field.type === 'boolean') {
96
100
  return (_jsx(Controller, { control: control, name: fieldName, render: ({ field: { value, onChange, ...restField } }) => (_jsxs(Select, { value: String(value), onValueChange: (value) => onChange(value === 'null' ? null : value === 'true'), disabled: restField.disabled, children: [_jsx(SelectTrigger, { id: fieldName, className: props.className, ...restField, children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "true", children: "True" }), _jsx(SelectItem, { value: "false", children: "False" }), !isRequired && _jsx(SelectItem, { value: "null", children: "Null" })] })] })) }));
97
101
  }
102
+ if (field.type === 'null')
103
+ return;
98
104
  return (_jsx(Input, { id: fieldName, placeholder: "Enter value", type: field.type === 'string' ? 'text' : 'number', ...register(fieldName, {
99
105
  valueAsNumber: field.type === 'number' || field.type === 'integer',
100
106
  }), ...props }));
101
107
  }
102
- export function FieldSet({ field: _field, fieldName, toolbar, name, isRequired, depth = 0, ...props }) {
108
+ export function FieldSet({ field: _field, fieldName, toolbar, name, isRequired, depth = 0, slotType, ...props }) {
103
109
  const field = useResolvedSchema(_field);
104
- const [show, setShow] = useState(() => typeof _field !== 'object' ||
105
- !_field.$ref ||
106
- (field.type !== 'object' && !field.allOf && !field.oneOf && !field.anyOf));
110
+ const [show, setShow] = useState(false);
107
111
  const { info, updateInfo } = useFieldInfo(fieldName, field, depth);
108
112
  if (_field === false)
109
113
  return null;
110
- if (!show) {
111
- return (_jsxs(FieldHeader, { ...props, name: name, required: isRequired, children: [toolbar, _jsx("button", { type: "button", className: cn(buttonVariants({ size: 'sm' })), onClick: () => setShow(true), children: "Show" })] }));
114
+ const recursive = typeof _field !== 'boolean' &&
115
+ _field.$ref &&
116
+ (field.oneOf || field.type === 'object' || field.allOf || field.anyOf);
117
+ if (recursive && !show) {
118
+ return (_jsxs(FieldHeader, { ...props, name: name, required: isRequired, children: [slotType ?? _jsx(FieldHeaderCode, { children: schemaToString(field) }), toolbar, _jsx("button", { type: "button", className: cn(buttonVariants({
119
+ size: 'sm',
120
+ color: 'secondary',
121
+ })), onClick: () => setShow(true), children: "Open" })] }));
112
122
  }
113
123
  if (field.oneOf) {
114
- return (_jsx(FieldSet, { ...props, className: cn(props.className, '[&>label>[data-type]]:hidden'), name: name, fieldName: fieldName, isRequired: isRequired, field: field.oneOf[info.oneOf], depth: depth + 1, toolbar: _jsxs(_Fragment, { children: [_jsx("select", { className: "text-xs font-mono", value: info.oneOf, onChange: (e) => {
124
+ const showSelect = field.oneOf.length > 1;
125
+ return (_jsx(FieldSet, { ...props, name: name, fieldName: fieldName, isRequired: isRequired, field: field.oneOf[info.oneOf], depth: depth + 1, slotType: showSelect ? false : slotType, toolbar: _jsxs(_Fragment, { children: [showSelect && (_jsx("select", { className: "text-xs font-mono", value: info.oneOf, onChange: (e) => {
115
126
  updateInfo({
116
127
  oneOf: Number(e.target.value),
117
128
  });
118
- }, children: field.oneOf.map((item, i) => (_jsx("option", { value: i, children: schemaToString(item) }, i))) }), toolbar] }) }));
129
+ }, children: field.oneOf.map((item, i) => (_jsx("option", { value: i, children: schemaToString(item) }, i))) })), toolbar] }) }));
119
130
  }
120
131
  if (Array.isArray(field.type)) {
121
- return (_jsxs("fieldset", { ...props, className: cn('flex flex-col gap-1.5', props.className), children: [_jsxs(FieldHeader, { name: name, htmlFor: fieldName, required: isRequired, children: [_jsx("select", { className: "text-xs font-mono", value: info.selectedType, onChange: (e) => {
122
- updateInfo({
123
- selectedType: e.target.value,
124
- });
125
- }, children: field.type.map((item) => (_jsx("option", { value: item, children: item }, item))) }), toolbar] }), _jsx("p", { className: "text-xs text-fd-muted-foreground", children: field.description }), _jsx(FieldInput, { isRequired: isRequired, field: {
126
- ...field,
127
- type: info.selectedType,
128
- }, fieldName: fieldName })] }));
132
+ const showSelect = field.type.length > 1;
133
+ return (_jsx(FieldSet, { ...props, name: name, fieldName: fieldName, isRequired: isRequired, field: {
134
+ ...field,
135
+ type: info.selectedType,
136
+ }, depth: depth + 1, slotType: showSelect ? false : slotType, toolbar: _jsxs(_Fragment, { children: [showSelect && (_jsx("select", { className: "text-xs font-mono", value: info.selectedType, onChange: (e) => {
137
+ updateInfo({
138
+ selectedType: e.target.value,
139
+ });
140
+ }, children: field.type.map((item) => (_jsx("option", { value: item, children: item }, item))) })), toolbar] }) }));
141
+ }
142
+ if (field.type === 'object' || field.anyOf || field.allOf) {
143
+ return (_jsxs("fieldset", { ...props, className: cn('flex flex-col gap-1.5', props.className), children: [_jsxs(FieldHeader, { htmlFor: fieldName, name: name, required: isRequired, children: [slotType ?? (_jsx(FieldHeaderCode, { children: schemaToString(field) })), toolbar] }), _jsx(ObjectInput, { field: field, fieldName: fieldName, ...props, className: cn('rounded-lg border border-fd-primary/20 bg-fd-background/50 p-3 shadow-sm', props.className) })] }));
144
+ }
145
+ if (field.type === 'array') {
146
+ return (_jsxs("fieldset", { ...props, className: cn('flex flex-col gap-1.5', props.className), children: [_jsxs(FieldHeader, { htmlFor: fieldName, name: name, required: isRequired, children: [slotType ?? (_jsx(FieldHeaderCode, { children: schemaToString(field) })), toolbar] }), _jsx(ArrayInput, { fieldName: fieldName, items: field.items ?? anyFields, ...props, className: cn('rounded-lg border border-fd-primary/20 bg-fd-background/50 p-3 shadow-sm', props.className) })] }));
129
147
  }
130
- return (_jsxs("fieldset", { ...props, className: cn('flex flex-col gap-1.5', props.className), children: [_jsx(FieldHeader, { htmlFor: fieldName, name: name, required: isRequired, type: field.oneOf ? undefined : schemaToString(field), children: toolbar }), show ? (_jsx(FieldInput, { field: field, fieldName: fieldName, isRequired: isRequired })) : (_jsx("div", { children: _jsx("button", { onClick: () => setShow((prev) => !prev), children: "Show" }) }))] }));
148
+ return (_jsxs("fieldset", { ...props, className: cn('flex flex-col gap-1.5', props.className), children: [_jsxs(FieldHeader, { htmlFor: fieldName, name: name, required: isRequired, children: [slotType ?? _jsx(FieldHeaderCode, { children: schemaToString(field) }), toolbar] }), _jsx(FieldInput, { field: field, fieldName: fieldName, isRequired: isRequired })] }));
131
149
  }
132
150
  function ArrayInput({ fieldName, items, ...props }) {
133
151
  const name = fieldName.split('.').at(-1) ?? '';
@@ -136,9 +154,10 @@ function ArrayInput({ fieldName, items, ...props }) {
136
154
  });
137
155
  return (_jsxs("div", { ...props, className: cn('flex flex-col gap-2', props.className), children: [fields.map((item, index) => (_jsx(FieldSet, { name: _jsxs("span", { className: "text-fd-muted-foreground", children: [name, "[", index, "]"] }), field: items, fieldName: `${fieldName}.${index}`, toolbar: _jsx("button", { type: "button", "aria-label": "Remove Item", className: cn(buttonVariants({
138
156
  color: 'ghost',
157
+ size: 'icon-sm',
139
158
  className: 'p-1',
140
- })), onClick: () => remove(index), children: _jsx(Trash2, { className: "size-4" }) }) }, item.id))), _jsxs("button", { type: "button", className: cn(buttonVariants({
141
- color: 'outline',
159
+ })), onClick: () => remove(index), children: _jsx(Trash2, {}) }) }, item.id))), _jsxs("button", { type: "button", className: cn(buttonVariants({
160
+ color: 'secondary',
142
161
  className: 'gap-1.5 py-2',
143
162
  size: 'sm',
144
163
  })), onClick: () => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/render/operation/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,YAAY,EAAkB,MAAM,OAAO,CAAC;AACpE,OAAO,KAAK,EAEV,iBAAiB,EAEjB,aAAa,EAEd,MAAM,SAAS,CAAC;AAmBjB,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAK1D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,KAAK,CAAC;CAC3C;AASD,wBAAgB,SAAS,CAAC,EACxB,IAAkB,EAClB,IAAI,EACJ,MAAM,EACN,GAAG,EACH,OAAO,EACP,YAAgB,GACjB,EAAE;IACD,IAAI,CAAC,EAAE,SAAS,GAAG,WAAW,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,iBAAiB,CAAC;IAC1B,GAAG,EAAE,aAAa,CAAC;IAEnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,YAAY,CA2Kf"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/render/operation/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,YAAY,EAAkB,MAAM,OAAO,CAAC;AACpE,OAAO,KAAK,EAEV,iBAAiB,EAEjB,aAAa,EAEd,MAAM,SAAS,CAAC;AAmBjB,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAK1D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,KAAK,CAAC;CAC3C;AASD,wBAAgB,SAAS,CAAC,EACxB,IAAkB,EAClB,IAAI,EACJ,MAAM,EACN,GAAG,EACH,OAAO,EACP,YAAgB,GACjB,EAAE;IACD,IAAI,CAAC,EAAE,SAAS,GAAG,WAAW,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,iBAAiB,CAAC;IAC1B,GAAG,EAAE,aAAa,CAAC;IAEnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,YAAY,CA6Kf"}
@@ -9,7 +9,7 @@ import { Schema } from '../schema.js';
9
9
  import { createMethod } from '../../server/create-method.js';
10
10
  import { methodKeys } from '../../build-routes.js';
11
11
  import { APIExample, APIExampleProvider, getAPIExamples, } from '../../render/operation/api-example.js';
12
- import { MethodLabel } from '../../ui/components/method-label.js';
12
+ import { Badge, MethodLabel } from '../../ui/components/method-label.js';
13
13
  import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
14
14
  import { getTypescriptSchema } from '../../utils/get-typescript-schema.js';
15
15
  import { CopyResponseTypeScript } from '../../ui/client.js';
@@ -35,11 +35,7 @@ export function Operation({ type = 'operation', path, method, ctx, hasHead, head
35
35
  const type = getPreferredType(body.content);
36
36
  if (!type || !(type in ctx.mediaAdapters))
37
37
  throw new Error(`No supported media type for body content: ${path}, received: ${type}`);
38
- bodyNode = (_jsxs(_Fragment, { children: [heading(headingLevel, 'Request Body', ctx), _jsxs("div", { className: "mb-4 p-3 bg-fd-card rounded-xl border flex flex-row items-center justify-between gap-2", children: [_jsx("code", { children: type }), _jsx("span", { className: "text-xs", children: body.required ? 'Required' : 'Optional' })] }), body.description ? _jsx(Markdown, { text: body.description }) : null, _jsx(Schema, { name: "body", schema: (body.content[type].schema ?? {}), required: body.required, ctx: {
39
- readOnly: method.method === 'GET',
40
- writeOnly: method.method !== 'GET',
41
- render: ctx,
42
- } })] }));
38
+ bodyNode = (_jsxs(_Fragment, { children: [heading(headingLevel, 'Request Body', ctx), _jsxs("div", { className: "flex justify-between items-center gap-2 mb-4", children: [_jsx("code", { children: type }), body.required ? (_jsx(Badge, { color: "red", className: "text-xs", children: "Required" })) : (_jsx(Badge, { color: "yellow", className: "text-xs", children: "Optional" }))] }), body.description ? _jsx(Markdown, { text: body.description }) : null, _jsx(Schema, { name: "body", as: "body", schema: (body.content[type].schema ?? {}), required: body.required, readOnly: method.method === 'GET', writeOnly: method.method !== 'GET', ctx: ctx })] }));
43
39
  }
44
40
  if (method.responses && ctx.showResponseSchema !== false) {
45
41
  const statuses = Object.keys(method.responses);
@@ -54,11 +50,7 @@ export function Operation({ type = 'operation', path, method, ctx, hasHead, head
54
50
  description: param.description ?? param.schema?.description,
55
51
  deprecated: (param.deprecated ?? false) ||
56
52
  (param.schema?.deprecated ?? false),
57
- }, parseObject: false, required: param.required, ctx: {
58
- readOnly: method.method === 'GET',
59
- writeOnly: method.method !== 'GET',
60
- render: ctx,
61
- } }, param.name))) })] }, type));
53
+ }, required: param.required, readOnly: method.method === 'GET', writeOnly: method.method !== 'GET', ctx: ctx }, param.name))) })] }, type));
62
54
  });
63
55
  if (method.callbacks) {
64
56
  callbacksNode = (_jsxs(_Fragment, { children: [heading(headingLevel, 'Webhooks', ctx), Object.entries(method.callbacks).map(([name, callback]) => (_jsx(WebhookCallback, { callback: callback, ctx: ctx, headingLevel: headingLevel }, name)))] }));
@@ -90,11 +82,7 @@ async function ResponseTab({ status, operation, ctx, }) {
90
82
  else if (generateTypeScriptSchema === undefined && responseOfType?.schema) {
91
83
  ts = await getTypescriptSchema(responseOfType?.schema, schema.dereferenceMap);
92
84
  }
93
- return (_jsxs(Tab, { value: status, children: [_jsx(Markdown, { text: description }), ts && _jsx(CopyResponseTypeScript, { code: ts }), responseOfType?.schema && (_jsx(Schema, { name: "response", schema: responseOfType.schema, required: true, ctx: {
94
- render: ctx,
95
- writeOnly: false,
96
- readOnly: true,
97
- } }))] }));
85
+ return (_jsxs(Tab, { value: status, children: [_jsx(Markdown, { text: description }), ts && _jsx(CopyResponseTypeScript, { code: ts }), responseOfType?.schema && (_jsx(Schema, { name: "response", schema: responseOfType.schema, as: "body", readOnly: true, ctx: ctx }))] }));
98
86
  }
99
87
  function WebhookCallback({ callback, ctx, headingLevel, }) {
100
88
  return Object.entries(callback).map(([path, pathItem]) => {
@@ -21,6 +21,7 @@ export interface PropertyProps {
21
21
  required?: boolean;
22
22
  deprecated?: boolean;
23
23
  children?: ReactNode;
24
+ nested?: boolean;
24
25
  }
25
26
  export interface ObjectCollapsibleProps {
26
27
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/render/renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAWtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGtE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IAEd,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IAEb,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,SAAS,CAAC;QACxB,KAAK,EAAE,MAAM,CAAC;KACf,EAAE,CAAC;CACL;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,aAAa,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IAC/B,GAAG,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAC5C,OAAO,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACrC,UAAU,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAEnD,SAAS,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC;IACzC,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IACvC,mBAAmB,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACjD,QAAQ,EAAE,aAAa,CAAC;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAClE,OAAO,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACrC,aAAa,EAAE,aAAa,CAAC;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAC7E,YAAY,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;IAE/C;;OAEG;IACH,iBAAiB,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAC;IACzD,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IACvC,aAAa,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;CAClD;AAED,wBAAgB,aAAa,IAAI,QAAQ,CAqCxC"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/render/renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAWtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGtE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IAEd,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IAEb,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,SAAS,CAAC;QACxB,KAAK,EAAE,MAAM,CAAC;KACf,EAAE,CAAC;CACL;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,aAAa,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IAC/B,GAAG,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAC5C,OAAO,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACrC,UAAU,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAEnD,SAAS,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC;IACzC,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IACvC,mBAAmB,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACjD,QAAQ,EAAE,aAAa,CAAC;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAClE,OAAO,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACrC,aAAa,EAAE,aAAa,CAAC;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAC7E,YAAY,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;IAE/C;;OAEG;IACH,iBAAiB,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAC;IACzD,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IACvC,aAAa,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;CAClD;AAED,wBAAgB,aAAa,IAAI,QAAQ,CAqCxC"}
@@ -1,23 +1,13 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import type { ResolvedSchema } from '../utils/schema.js';
3
3
  import type { RenderContext } from '../types.js';
4
- interface Context {
5
- readOnly: boolean;
6
- writeOnly: boolean;
7
- stack?: ResolvedSchema[];
8
- render: RenderContext;
9
- }
10
- export declare function Schema({ name, schema, required, parseObject, ctx, }: {
4
+ export declare function Schema({ name, schema, required, readOnly, writeOnly, as, ctx: { renderer }, }: {
11
5
  name: string;
12
6
  required?: boolean;
13
7
  schema: ResolvedSchema;
14
- /**
15
- * Render the full object
16
- *
17
- * @defaultValue true
18
- * */
19
- parseObject?: boolean;
20
- ctx: Context;
8
+ as?: 'property' | 'body';
9
+ readOnly?: boolean;
10
+ writeOnly?: boolean;
11
+ ctx: RenderContext;
21
12
  }): ReactNode;
22
- export {};
23
13
  //# sourceMappingURL=schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/render/schema.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAiB7C,UAAU,OAAO;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IAEzB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED,wBAAgB,MAAM,CAAC,EACrB,IAAI,EACJ,MAAM,EACN,QAAgB,EAChB,WAAkB,EAClB,GAAG,GACJ,EAAE;IACD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,cAAc,CAAC;IAEvB;;;;SAIK;IACL,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,GAAG,EAAE,OAAO,CAAC;CACd,GAAG,SAAS,CAgNZ"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/render/schema.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAwB7C,wBAAgB,MAAM,CAAC,EACrB,IAAI,EACJ,MAAM,EACN,QAAgB,EAChB,QAAgB,EAChB,SAAiB,EACjB,EAAe,EACf,GAAG,EAAE,EAAE,QAAQ,EAAE,GAClB,EAAE;IACD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,cAAc,CAAC;IACvB,EAAE,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IAEzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,GAAG,EAAE,aAAa,CAAC;CACpB,GAAG,SAAS,CAoSZ"}
@@ -1,115 +1,174 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Fragment } from 'react';
2
3
  import { combineSchema } from '../utils/combine-schema.js';
3
4
  import { Markdown } from './markdown.js';
4
5
  import { schemaToString } from '../utils/schema-to-string.js';
6
+ import { Tabs, TabsContent, TabsList, TabsTrigger, } from 'fumadocs-ui/components/tabs';
5
7
  const keys = {
6
8
  default: 'Default',
7
- minimum: 'Minimum',
8
- maximum: 'Maximum',
9
- minLength: 'Minimum length',
10
- maxLength: 'Maximum length',
11
9
  pattern: 'Pattern',
12
10
  format: 'Format',
11
+ multipleOf: 'Multiple of',
13
12
  };
14
- export function Schema({ name, schema, required = false, parseObject = true, ctx, }) {
15
- const { render: { renderer }, stack = [], } = ctx;
16
- if (schema === true) {
17
- return _jsx(renderer.Property, { name: name, type: "any" });
18
- }
19
- else if (schema === false) {
20
- return _jsx(renderer.Property, { name: name, type: "never" });
21
- }
22
- if ((schema.readOnly === true && !ctx.readOnly) ||
23
- (schema.writeOnly === true && !ctx.writeOnly))
24
- return null;
25
- if (Array.isArray(schema.type) && schema.type.length === 1) {
26
- return (_jsx(Schema, { name: name, required: required, parseObject: parseObject, schema: {
27
- ...schema,
28
- type: schema.type[0],
29
- }, ctx: {
30
- ...ctx,
31
- stack: [schema, ...stack],
32
- } }));
33
- }
34
- if (schema.allOf || schema.anyOf) {
35
- return (_jsx(Schema, { name: name, parseObject: parseObject, required: required, schema: combineSchema([
36
- ...(schema.allOf ?? []),
37
- ...(schema.anyOf ?? []),
38
- ]), ctx: {
39
- ...ctx,
40
- stack: [schema, ...stack],
41
- } }));
42
- }
43
- // object type
44
- if (schema.type === 'object' && parseObject) {
45
- const { additionalProperties, patternProperties, properties } = schema;
46
- return (_jsxs("div", { className: "flex flex-col gap-4", children: [properties &&
47
- Object.entries(properties).map(([key, value]) => {
48
- return (_jsx(Schema, { name: key, schema: value, parseObject: false, required: schema.required?.includes(key) ?? false, ctx: {
49
- ...ctx,
50
- stack: [schema, ...stack],
51
- } }, key));
52
- }), patternProperties &&
53
- Object.entries(patternProperties).map(([key, value]) => {
54
- return (_jsx(Schema, { name: key, schema: value, parseObject: false, ctx: {
55
- ...ctx,
56
- stack: [schema, ...stack],
57
- } }, key));
58
- }), additionalProperties && (_jsx(Schema, { name: "[key: string]", schema: additionalProperties, parseObject: false, ctx: {
59
- ...ctx,
60
- stack: [schema, ...stack],
61
- } }))] }));
13
+ export function Schema({ name, schema, required = false, readOnly = false, writeOnly = false, as = 'property', ctx: { renderer }, }) {
14
+ function propertyBody(schema, renderPrimitive, ctx) {
15
+ if (Array.isArray(schema.type)) {
16
+ const items = schema.type.flatMap((type) => {
17
+ const composed = {
18
+ ...schema,
19
+ type,
20
+ };
21
+ if (!isComplexType(composed))
22
+ return [];
23
+ return composed;
24
+ });
25
+ if (items.length === 0)
26
+ return;
27
+ if (items.length === 1)
28
+ return propertyBody(items[0], renderPrimitive, ctx);
29
+ return (_jsxs(Tabs, { defaultValue: items[0].type, children: [_jsx(TabsList, { children: items.map((item) => (_jsx(TabsTrigger, { value: item.type, children: schemaToString(item) }, item.type))) }), items.map((item) => (_jsxs(TabsContent, { value: item.type, children: [item.description && _jsx(Markdown, { text: item.description }), propertyInfo(item), renderPrimitive(item, ctx)] }, item.type)))] }));
30
+ }
31
+ if (schema.oneOf) {
32
+ const oneOf = schema.oneOf.filter((item) => isComplexType(item));
33
+ if (oneOf.length === 0)
34
+ return;
35
+ if (oneOf.length === 1) {
36
+ return propertyBody(oneOf[0], renderPrimitive, ctx);
37
+ }
38
+ return (_jsxs(Tabs, { defaultValue: "0", children: [_jsx(TabsList, { children: oneOf.map((item, i) => (_jsx(TabsTrigger, { value: i.toString(), children: schemaToString(item) }, i))) }), oneOf.map((item, i) => (_jsxs(TabsContent, { value: i.toString(), children: [item.description && _jsx(Markdown, { text: item.description }), propertyInfo(item), propertyBody(item, (child, ctx) => primitiveBody(child, ctx, false, true), ctx)] }, i)))] }));
39
+ }
40
+ const of = schema.allOf ?? schema.anyOf;
41
+ if (of) {
42
+ const arr = of.filter((item) => !ctx.stack.has(item));
43
+ if (arr.length === 0)
44
+ return;
45
+ const combined = combineSchema(arr);
46
+ if (typeof combined === 'boolean')
47
+ return;
48
+ return renderPrimitive(combined, ctx);
49
+ }
50
+ return renderPrimitive(schema, ctx);
62
51
  }
63
- let footer;
64
- const fields = [];
65
- for (const [key, value] of Object.entries(keys)) {
66
- if (key in schema) {
52
+ function propertyInfo(schema) {
53
+ const fields = [];
54
+ for (const key in keys) {
55
+ if (key in schema) {
56
+ fields.push({
57
+ key: keys[key],
58
+ value: JSON.stringify(schema[key]),
59
+ });
60
+ }
61
+ }
62
+ let range = getRange('value', schema.minimum, schema.exclusiveMinimum, schema.maximum, schema.exclusiveMaximum);
63
+ if (range)
64
+ fields.push({
65
+ key: 'Range',
66
+ value: range,
67
+ });
68
+ range = getRange('length', schema.minLength, undefined, schema.maxLength, undefined);
69
+ if (range)
70
+ fields.push({
71
+ key: 'Length',
72
+ value: range,
73
+ });
74
+ range = getRange('properties', schema.minProperties, undefined, schema.maxProperties, undefined);
75
+ if (range)
76
+ fields.push({
77
+ key: 'Properties',
78
+ value: range,
79
+ });
80
+ if (schema.enum) {
67
81
  fields.push({
68
- key: value,
69
- value: JSON.stringify(schema[key]),
82
+ key: 'Value in',
83
+ value: schema.enum.map((value) => JSON.stringify(value)).join(' | '),
70
84
  });
71
85
  }
86
+ if (fields.length === 0)
87
+ return;
88
+ return (_jsx("div", { className: "flex flex-col border divide-y divide-fd-border bg-fd-muted rounded-lg not-prose", children: fields.map((field) => (_jsxs("div", { className: "flex items-center text-[13px] px-3 py-2.5 justify-between gap-2", children: [_jsx("span", { className: "font-medium", children: field.key }), _jsx("code", { className: "texxt-xs text-fd-muted-foreground", children: field.value })] }, field.key))) }));
72
89
  }
73
- if (schema.enum) {
74
- fields.push({
75
- key: 'Value in',
76
- value: schema.enum.map((value) => JSON.stringify(value)).join(' | '),
77
- });
78
- }
79
- if (schema.type === 'object' && !parseObject && !stack.includes(schema)) {
80
- footer = (_jsx(renderer.ObjectCollapsible, { name: "Show Attributes", children: _jsx(Schema, { name: name, schema: schema, ctx: {
81
- ...ctx,
82
- stack: [schema, ...stack],
83
- } }) }));
90
+ function primitiveBody(schema, ctx, collapsible, nested) {
91
+ if (schema.type === 'object') {
92
+ if (ctx.stack.has(schema))
93
+ return _jsx("p", { children: "Recursive" });
94
+ const props = Object.entries(schema.properties ?? {});
95
+ const patternProps = Object.entries(schema.patternProperties ?? {});
96
+ const next = {
97
+ ...ctx,
98
+ stack: ctx.stack.next(schema),
99
+ };
100
+ if (props.length === 0 && patternProps.length === 0)
101
+ return _jsx("p", { children: "Empty Object" });
102
+ const children = (_jsxs("div", { className: "flex flex-col gap-4", children: [props.map(([key, value]) => (_jsx(Fragment, { children: property(key, value, next, {
103
+ required: schema.required?.includes(key) ?? false,
104
+ nested,
105
+ }) }, key))), patternProps.map(([key, value]) => (_jsx(Fragment, { children: property(key, value, next, { nested }) }, key))), schema.additionalProperties &&
106
+ property('[key: string]', schema.additionalProperties, next, {
107
+ nested,
108
+ })] }));
109
+ if (!collapsible)
110
+ return children;
111
+ return (_jsx(renderer.ObjectCollapsible, { name: "Show Attributes", children: children }));
112
+ }
113
+ if (schema.type === 'array') {
114
+ const items = schema.items;
115
+ if (!items || !isComplexType(items) || ctx.stack.has(items))
116
+ return;
117
+ const children = (_jsxs("div", { className: "flex flex-col gap-4", children: [items.description && _jsx(Markdown, { text: items.description }), propertyBody(items, (child, ctx) => primitiveBody(child, ctx, false, true), {
118
+ ...ctx,
119
+ stack: ctx.stack.next(schema),
120
+ })] }));
121
+ return (_jsx(renderer.ObjectCollapsible, { name: "Array Item", children: children }));
122
+ }
84
123
  }
85
- else {
86
- let mentionedObjectTypes = [];
87
- if (Array.isArray(schema.type)) {
88
- mentionedObjectTypes.push(...schema.type.map((type) => ({
89
- ...schema,
90
- type,
91
- })));
124
+ function property(key, schema, ctx, props) {
125
+ if (schema === true) {
126
+ return _jsx(renderer.Property, { name: key, type: "any", ...props });
127
+ }
128
+ else if (schema === false) {
129
+ return _jsx(renderer.Property, { name: key, type: "never", ...props });
92
130
  }
93
- if (schema.oneOf)
94
- mentionedObjectTypes.push(...schema.oneOf);
95
- if (schema.not)
96
- mentionedObjectTypes.push(schema.not);
97
- if (schema.type === 'array' && schema.items)
98
- mentionedObjectTypes.push(schema.items);
99
- mentionedObjectTypes = mentionedObjectTypes.filter((s) => isComplexType(s) && !stack.includes(s));
100
- if (mentionedObjectTypes.length > 0)
101
- footer = (_jsx("div", { className: "flex flex-col gap-2", children: mentionedObjectTypes.map((s, idx) => {
102
- let title = typeof s === 'object' ? s.title : null;
103
- title ?? (title = mentionedObjectTypes.length === 1
104
- ? 'Show Attributes'
105
- : `Object ${idx + 1}`);
106
- return (_jsx(renderer.ObjectCollapsible, { name: title, children: _jsx(Schema, { name: "element", schema: s, ctx: {
107
- ...ctx,
108
- stack: [schema, ...stack],
109
- } }) }, idx));
110
- }) }));
131
+ if ((schema.readOnly && !readOnly) || (schema.writeOnly && !writeOnly))
132
+ return;
133
+ return (_jsxs(renderer.Property, { name: key, type: schemaToString(schema), deprecated: schema.deprecated, ...props, children: [schema.description && _jsx(Markdown, { text: schema.description }), propertyInfo(schema), propertyBody(schema, (child, ctx) => primitiveBody(child, ctx, true, true), ctx)] }));
111
134
  }
112
- return (_jsxs(renderer.Property, { name: name, type: schemaToString(schema), required: required, deprecated: schema.deprecated, children: [schema.description ? _jsx(Markdown, { text: schema.description }) : null, fields.length > 0 ? (_jsx("div", { className: "flex flex-col gap-2", children: fields.map((field) => (_jsxs("span", { children: [field.key, ": ", _jsx("code", { children: field.value })] }, field.key))) })) : null, footer] }));
135
+ const context = {
136
+ stack: schemaStack(),
137
+ };
138
+ if (typeof schema === 'boolean' ||
139
+ as === 'property' ||
140
+ !isComplexType(schema))
141
+ return property(name, schema, context, { required });
142
+ return propertyBody(schema, (child, ctx) => primitiveBody(child, ctx, false, false), context);
143
+ }
144
+ function schemaStack(parent) {
145
+ const titles = new Set();
146
+ const history = new WeakSet();
147
+ return {
148
+ next(...schemas) {
149
+ const child = schemaStack(this);
150
+ for (const item of schemas) {
151
+ child.add(item);
152
+ }
153
+ return child;
154
+ },
155
+ add(schema) {
156
+ if (typeof schema !== 'object')
157
+ return;
158
+ if (schema.title)
159
+ titles.add(schema.title);
160
+ history.add(schema);
161
+ },
162
+ has(schema) {
163
+ if (typeof schema !== 'object')
164
+ return false;
165
+ if (parent && parent.has(schema))
166
+ return true;
167
+ if (schema.title && titles.has(schema.title))
168
+ return true;
169
+ return history.has(schema);
170
+ },
171
+ };
113
172
  }
114
173
  /**
115
174
  * Check if the schema needs another collapsible to explain
@@ -117,7 +176,29 @@ export function Schema({ name, schema, required = false, parseObject = true, ctx
117
176
  function isComplexType(schema) {
118
177
  if (typeof schema === 'boolean')
119
178
  return false;
120
- if (schema.anyOf ?? schema.oneOf ?? schema.allOf)
179
+ const arr = schema.anyOf ?? schema.oneOf ?? schema.allOf;
180
+ if (arr && arr.some(isComplexType))
121
181
  return true;
122
- return schema.type === 'object' || schema.type === 'array';
182
+ return (schema.type === 'object' ||
183
+ (schema.type === 'array' &&
184
+ schema.items != null &&
185
+ isComplexType(schema.items)));
186
+ }
187
+ function getRange(value, min, exclusiveMin, max, exclusiveMax) {
188
+ const out = [];
189
+ if (min) {
190
+ out.push(`${min} <=`);
191
+ }
192
+ else if (exclusiveMin) {
193
+ out.push(`${exclusiveMin} <`);
194
+ }
195
+ out.push(value);
196
+ if (max) {
197
+ out.push(`<= ${max}`);
198
+ }
199
+ else if (exclusiveMax) {
200
+ out.push(`< ${exclusiveMax}`);
201
+ }
202
+ if (out.length > 1)
203
+ return out.join(' ');
123
204
  }
@@ -1,12 +1,6 @@
1
1
  import type { ApiPageProps } from '../render/api-page.js';
2
- import type { DocumentInput } from '../utils/process-document.js';
3
2
  import { createProxy } from '../server/proxy.js';
4
- export interface OpenAPIOptions extends Omit<Partial<ApiPageProps>, 'document'> {
5
- /**
6
- * @deprecated Pass document to `APIPage` instead
7
- */
8
- documentOrPath?: DocumentInput;
9
- }
3
+ export type OpenAPIOptions = Omit<Partial<ApiPageProps>, 'document'>;
10
4
  export interface OpenAPIServer {
11
5
  getAPIPageProps: (from: ApiPageProps) => ApiPageProps;
12
6
  createProxy: typeof createProxy;
@@ -1 +1 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/server/create.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,WAAW,cACf,SAAQ,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,UAAU,CAAC;IAC/C;;OAEG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC;CAChC;AAED,MAAM,WAAW,aAAa;IAC5B,eAAe,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,YAAY,CAAC;IACtD,WAAW,EAAE,OAAO,WAAW,CAAC;CACjC;AAED,wBAAgB,aAAa,CAAC,OAAO,GAAE,cAAmB,GAAG,aAAa,CAUzE"}
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/server/create.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,UAAU,CAAC,CAAC;AAErE,MAAM,WAAW,aAAa;IAC5B,eAAe,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,YAAY,CAAC;IACtD,WAAW,EAAE,OAAO,WAAW,CAAC;CACjC;AAED,wBAAgB,aAAa,CAAC,OAAO,GAAE,cAAmB,GAAG,aAAa,CAUzE"}
@@ -1,8 +1,9 @@
1
- import type { BuildPageTreeOptions } from 'fumadocs-core/source';
1
+ import type { FileSystem } from 'fumadocs-core/source';
2
+ import type { PageTree } from 'fumadocs-core/server';
2
3
  /**
3
4
  * Source API Integration
4
5
  *
5
6
  * Add this to page tree builder options
6
7
  */
7
- export declare const attachFile: BuildPageTreeOptions['attachFile'];
8
+ export declare const attachFile: (node: PageTree.Item, file: FileSystem.PageFile | undefined) => PageTree.Item;
8
9
  //# sourceMappingURL=source-api.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"source-api.d.ts","sourceRoot":"","sources":["../../src/server/source-api.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAGjE;;;;GAIG;AACH,eAAO,MAAM,UAAU,EAAE,oBAAoB,CAAC,YAAY,CAyBzD,CAAC"}
1
+ {"version":3,"file":"source-api.d.ts","sourceRoot":"","sources":["../../src/server/source-api.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD;;;;GAIG;AACH,eAAO,MAAM,UAAU,GACrB,MAAM,QAAQ,CAAC,IAAI,EACnB,MAAM,UAAU,CAAC,QAAQ,GAAG,SAAS,KACpC,QAAQ,CAAC,IAyBX,CAAC"}