docusaurus-theme-openapi-docs 0.0.0-1154 → 0.0.0-1156

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.
@@ -121,14 +121,22 @@ function getQualifierMessage(schema) {
121
121
  let lengthQualifier = "";
122
122
  let minLength;
123
123
  let maxLength;
124
+ const charactersMessage = (0, Translate_1.translate)({
125
+ id: translationIds_1.OPENAPI_SCHEMA_ITEM.CHARACTERS,
126
+ message: "characters",
127
+ });
128
+ const nonEmptyMessage = (0, Translate_1.translate)({
129
+ id: translationIds_1.OPENAPI_SCHEMA_ITEM.NON_EMPTY,
130
+ message: "non-empty",
131
+ });
124
132
  if (schema.minLength && schema.minLength > 1) {
125
- minLength = `\`>= ${schema.minLength} characters\``;
133
+ minLength = `\`>= ${schema.minLength} ${charactersMessage}\``;
126
134
  }
127
135
  if (schema.minLength && schema.minLength === 1) {
128
- minLength = `\`non-empty\``;
136
+ minLength = `\`${nonEmptyMessage}\``;
129
137
  }
130
138
  if (schema.maxLength) {
131
- maxLength = `\`<= ${schema.maxLength} characters\``;
139
+ maxLength = `\`<= ${schema.maxLength} ${charactersMessage}\``;
132
140
  }
133
141
  if (minLength && !maxLength) {
134
142
  lengthQualifier += minLength;
@@ -178,7 +186,11 @@ function getQualifierMessage(schema) {
178
186
  qualifierGroups.push(minmaxQualifier);
179
187
  }
180
188
  if (schema.pattern) {
181
- qualifierGroups.push(`Value must match regular expression \`${schema.pattern}\``);
189
+ const expressionMessage = (0, Translate_1.translate)({
190
+ id: translationIds_1.OPENAPI_SCHEMA_ITEM.EXPRESSION,
191
+ message: "Value must match regular expression",
192
+ });
193
+ qualifierGroups.push(`${expressionMessage} \`${schema.pattern}\``);
182
194
  }
183
195
  // Check if discriminator mapping
184
196
  const discriminator = schema;
@@ -13,6 +13,9 @@ var __importDefault =
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
14
  const react_1 = __importDefault(require("react"));
15
15
  const BrowserOnly_1 = __importDefault(require("@docusaurus/BrowserOnly"));
16
+ const ExecutionEnvironment_1 = __importDefault(
17
+ require("@docusaurus/ExecutionEnvironment")
18
+ );
16
19
  const hooks_1 = require("@theme/ApiItem/hooks");
17
20
  function colorForMethod(method) {
18
21
  switch (method.toLowerCase()) {
@@ -35,6 +38,31 @@ function colorForMethod(method) {
35
38
  }
36
39
  }
37
40
  function MethodEndpoint({ method, path, context }) {
41
+ // During SSR, render without Redux store access to avoid "Cannot read properties
42
+ // of null (reading 'store')" errors caused by useSelector running outside a Provider.
43
+ if (!ExecutionEnvironment_1.default.canUseDOM) {
44
+ return react_1.default.createElement(
45
+ react_1.default.Fragment,
46
+ null,
47
+ react_1.default.createElement(
48
+ "pre",
49
+ { className: "openapi__method-endpoint" },
50
+ react_1.default.createElement(
51
+ "span",
52
+ { className: "badge badge--" + colorForMethod(method) },
53
+ method === "event" ? "Webhook" : method.toUpperCase()
54
+ ),
55
+ " ",
56
+ method !== "event" &&
57
+ react_1.default.createElement(
58
+ "h2",
59
+ { className: "openapi__method-endpoint-path" },
60
+ `${path.replace(/{([a-z0-9-_]+)}/gi, ":$1")}`
61
+ )
62
+ ),
63
+ react_1.default.createElement("div", { className: "openapi__divider" })
64
+ );
65
+ }
38
66
  let serverValue = (0, hooks_1.useTypedSelector)(
39
67
  (state) => state.server.value
40
68
  );
@@ -27,7 +27,6 @@ const ResponseHeaders = ({ responseHeaders }) => {
27
27
  name: name,
28
28
  collapsible: false,
29
29
  schemaName: (0, schema_1.getSchemaName)(schema),
30
- qualifierMessage: (0, schema_1.getQualifierMessage)(schema),
31
30
  schema: schema,
32
31
  discriminator: false,
33
32
  children: null,
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import type { SchemaObject } from "docusaurus-plugin-openapi-docs/src/openapi/types";
2
+ import type { SchemaObject } from "../../types.d";
3
3
  interface SchemaProps {
4
4
  schema: SchemaObject;
5
5
  schemaType: "request" | "response";
@@ -84,8 +84,8 @@ const translationIds_1 = require("@theme/translationIds");
84
84
  // eslint-disable-next-line import/no-extraneous-dependencies
85
85
  const allof_merge_1 = require("allof-merge");
86
86
  const clsx_1 = __importDefault(require("clsx"));
87
- const schema_1 = require("docusaurus-plugin-openapi-docs/lib/markdown/schema");
88
87
  const isEmpty_1 = __importDefault(require("lodash/isEmpty"));
88
+ const schema_1 = require("../../markdown/schema");
89
89
  // eslint-disable-next-line import/no-extraneous-dependencies
90
90
  // const jsonSchemaMergeAllOf = require("json-schema-merge-allof");
91
91
  const mergeAllOf = (allOf) => {
@@ -226,6 +226,12 @@ const Summary = ({ name, schemaName, schema, required }) => {
226
226
  };
227
227
  const AnyOneOf = ({ schema, schemaType, schemaPath }) => {
228
228
  const key = schema.oneOf ? "oneOf" : "anyOf";
229
+ const schemaArray = schema[key];
230
+ // Empty oneOf/anyOf arrays are valid in OpenAPI specs but would cause the
231
+ // Tabs component to throw "requires at least one TabItem". Return null instead.
232
+ if (!schemaArray || !Array.isArray(schemaArray) || schemaArray.length === 0) {
233
+ return null;
234
+ }
229
235
  const type = schema.oneOf
230
236
  ? (0, Translate_1.translate)({
231
237
  id: translationIds_1.OPENAPI_SCHEMA_ITEM.ONE_OF,
@@ -305,9 +311,6 @@ const AnyOneOf = ({ schema, schemaType, schemaPath }) => {
305
311
  collapsible: false,
306
312
  name: undefined,
307
313
  schemaName: computedSchemaName,
308
- qualifierMessage: (0, schema_1.getQualifierMessage)(
309
- anyOneSchema
310
- ),
311
314
  schema: anyOneSchema,
312
315
  discriminator: false,
313
316
  children: null,
@@ -321,9 +324,6 @@ const AnyOneOf = ({ schema, schemaType, schemaPath }) => {
321
324
  collapsible: false,
322
325
  name: undefined,
323
326
  schemaName: computedSchemaName,
324
- qualifierMessage: (0, schema_1.getQualifierMessage)(
325
- anyOneSchema
326
- ),
327
327
  schema: anyOneSchema,
328
328
  discriminator: false,
329
329
  children: null,
@@ -392,7 +392,6 @@ const Properties = ({ schema, schemaType, schemaPath }) => {
392
392
  name: "",
393
393
  required: false,
394
394
  schemaName: "object",
395
- qualifierMessage: undefined,
396
395
  schema: {},
397
396
  });
398
397
  }
@@ -588,7 +587,6 @@ const AdditionalProperties = ({ schema, schemaType }) => {
588
587
  name: "property name*",
589
588
  required: false,
590
589
  schemaName: "any",
591
- qualifierMessage: (0, schema_1.getQualifierMessage)(schema),
592
590
  schema: schema,
593
591
  collapsible: false,
594
592
  discriminator: false,
@@ -629,7 +627,6 @@ const AdditionalProperties = ({ schema, schemaType }) => {
629
627
  name: "property name*",
630
628
  required: false,
631
629
  schemaName: schemaName,
632
- qualifierMessage: (0, schema_1.getQualifierMessage)(schema),
633
630
  schema: additionalProperties,
634
631
  collapsible: false,
635
632
  discriminator: false,
@@ -734,7 +731,6 @@ const Items = ({ schema, schemaType, schemaPath }) => {
734
731
  collapsible: false,
735
732
  name: "", // No name for array items
736
733
  schemaName: (0, schema_1.getSchemaName)(itemsSchema),
737
- qualifierMessage: (0, schema_1.getQualifierMessage)(itemsSchema),
738
734
  schema: itemsSchema,
739
735
  discriminator: false,
740
736
  children: null,
@@ -855,7 +851,6 @@ const SchemaEdge = ({
855
851
  name: name,
856
852
  required: Array.isArray(required) ? required.includes(name) : required,
857
853
  schemaName: schema.allOf[0],
858
- qualifierMessage: undefined,
859
854
  schema: schema.allOf[0],
860
855
  discriminator: false,
861
856
  children: null,
@@ -907,7 +902,6 @@ const SchemaEdge = ({
907
902
  name: name,
908
903
  required: Array.isArray(required) ? required.includes(name) : required,
909
904
  schemaName: mergedSchemaName,
910
- qualifierMessage: (0, schema_1.getQualifierMessage)(mergedSchemas),
911
905
  schema: mergedSchemas,
912
906
  discriminator: false,
913
907
  children: null,
@@ -918,7 +912,6 @@ const SchemaEdge = ({
918
912
  name: name,
919
913
  required: Array.isArray(required) ? required.includes(name) : required,
920
914
  schemaName: schemaName,
921
- qualifierMessage: (0, schema_1.getQualifierMessage)(schema),
922
915
  schema: schema,
923
916
  discriminator: false,
924
917
  children: null,
@@ -1086,7 +1079,6 @@ const SchemaNode = ({ schema, schemaType, schemaPath }) => {
1086
1079
  name: schema.type,
1087
1080
  required: Boolean(schema.required),
1088
1081
  schemaName: schemaName,
1089
- qualifierMessage: (0, schema_1.getQualifierMessage)(schema),
1090
1082
  schema: schema,
1091
1083
  discriminator: false,
1092
1084
  children: null,
@@ -18,6 +18,7 @@ const Example_1 = require("@theme/Example");
18
18
  const Markdown_1 = __importDefault(require("@theme/Markdown"));
19
19
  const translationIds_1 = require("@theme/translationIds");
20
20
  const clsx_1 = __importDefault(require("clsx"));
21
+ const schema_1 = require("../../markdown/schema");
21
22
  const utils_1 = require("../../markdown/utils");
22
23
  const transformEnumDescriptions = (enumDescriptions) => {
23
24
  if (enumDescriptions) {
@@ -127,8 +128,12 @@ function SchemaItem(props) {
127
128
  react_1.default.createElement(Markdown_1.default, null, description)
128
129
  )
129
130
  );
131
+ // Generate qualifierMessage from schema if not provided
132
+ const effectiveQualifierMessage =
133
+ qualifierMessage ??
134
+ (schema ? (0, schema_1.getQualifierMessage)(schema) : undefined);
130
135
  const renderQualifierMessage = (0, utils_1.guard)(
131
- qualifierMessage,
136
+ effectiveQualifierMessage,
132
137
  (message) =>
133
138
  react_1.default.createElement(
134
139
  react_1.default.Fragment,
@@ -7,4 +7,4 @@ export interface SchemaTabsProps extends TabProps {
7
7
  */
8
8
  onChange?: (index: number) => void;
9
9
  }
10
- export default function SchemaTabs(props: SchemaTabsProps): React.JSX.Element;
10
+ export default function SchemaTabs(props: SchemaTabsProps): React.JSX.Element | null;
@@ -252,6 +252,26 @@ function TabsComponent(props) {
252
252
  }
253
253
  function SchemaTabs(props) {
254
254
  const isBrowser = (0, useIsBrowser_1.default)();
255
+ const children = Array.isArray(props.children)
256
+ ? props.children.filter(Boolean)
257
+ : props.children
258
+ ? [props.children]
259
+ : [];
260
+ if (children.length === 0) {
261
+ return null;
262
+ }
263
+ let sanitizedChildren;
264
+ try {
265
+ sanitizedChildren = (0, internal_1.sanitizeTabsChildren)(children);
266
+ } catch {
267
+ return null;
268
+ }
269
+ if (
270
+ !sanitizedChildren ||
271
+ (Array.isArray(sanitizedChildren) && sanitizedChildren.length === 0)
272
+ ) {
273
+ return null;
274
+ }
255
275
  return react_1.default.createElement(
256
276
  TabsComponent,
257
277
  // Remount tabs after hydration
@@ -262,6 +282,6 @@ function SchemaTabs(props) {
262
282
  key: String(isBrowser),
263
283
  ...props,
264
284
  },
265
- (0, internal_1.sanitizeTabsChildren)(props.children)
285
+ sanitizedChildren
266
286
  );
267
287
  }
@@ -60,6 +60,8 @@ export declare const OPENAPI_SCHEMA: {
60
60
  NO_SCHEMA: string;
61
61
  };
62
62
  export declare const OPENAPI_SCHEMA_ITEM: {
63
+ CHARACTERS: string;
64
+ NON_EMPTY: string;
63
65
  REQUIRED: string;
64
66
  DEPRECATED: string;
65
67
  NULLABLE: string;
@@ -71,6 +73,7 @@ export declare const OPENAPI_SCHEMA_ITEM: {
71
73
  ENUM_VALUE: string;
72
74
  ENUM_DESCRIPTION: string;
73
75
  POSSIBLE_VALUES: string;
76
+ EXPRESSION: string;
74
77
  ONE_OF: string;
75
78
  ANY_OF: string;
76
79
  };
@@ -84,6 +84,8 @@ exports.OPENAPI_SCHEMA = {
84
84
  NO_SCHEMA: "theme.openapi.schema.noSchema",
85
85
  };
86
86
  exports.OPENAPI_SCHEMA_ITEM = {
87
+ CHARACTERS: "theme.openapi.schemaItem.characters",
88
+ NON_EMPTY: "theme.openapi.schemaItem.nonEmpty",
87
89
  REQUIRED: "theme.openapi.schemaItem.required",
88
90
  DEPRECATED: "theme.openapi.schemaItem.deprecated",
89
91
  NULLABLE: "theme.openapi.schemaItem.nullable",
@@ -95,6 +97,7 @@ exports.OPENAPI_SCHEMA_ITEM = {
95
97
  ENUM_VALUE: "theme.openapi.schemaItem.enumValue",
96
98
  ENUM_DESCRIPTION: "theme.openapi.schemaItem.enumDescription",
97
99
  POSSIBLE_VALUES: "theme.openapi.schemaItem.possibleValues",
100
+ EXPRESSION: "theme.openapi.schemaItem.expression",
98
101
  ONE_OF: "theme.openapi.schemaItem.oneOf",
99
102
  ANY_OF: "theme.openapi.schemaItem.anyOf",
100
103
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "docusaurus-theme-openapi-docs",
3
3
  "description": "OpenAPI theme for Docusaurus.",
4
- "version": "0.0.0-1154",
4
+ "version": "0.0.0-1156",
5
5
  "license": "MIT",
6
6
  "keywords": [
7
7
  "openapi",
@@ -38,7 +38,7 @@
38
38
  "@types/postman-collection": "^3.5.11",
39
39
  "@types/react-modal": "^3.16.3",
40
40
  "concurrently": "^9.2.0",
41
- "docusaurus-plugin-openapi-docs": "0.0.0-1154",
41
+ "docusaurus-plugin-openapi-docs": "0.0.0-1156",
42
42
  "docusaurus-plugin-sass": "^0.2.6",
43
43
  "eslint-plugin-prettier": "^5.5.1"
44
44
  },
@@ -82,5 +82,5 @@
82
82
  "engines": {
83
83
  "node": ">=14"
84
84
  },
85
- "gitHead": "0debbc67d743f553056175f125d0df187f4e4939"
85
+ "gitHead": "15f538e349ea6e12482cb5a53dea9c349fd9157e"
86
86
  }
@@ -140,9 +140,7 @@ export function getQualifierMessage(schema?: SchemaObject): string | undefined {
140
140
  if (schema.items) {
141
141
  const itemsEnum = getEnumFromSchema(schema.items as SchemaObject);
142
142
  if (itemsEnum) {
143
- qualifierGroups.push(
144
- `[${itemsEnum.map((e) => `\`${e}\``).join(", ")}]`
145
- );
143
+ qualifierGroups.push(`[${itemsEnum.map((e) => `\`${e}\``).join(", ")}]`);
146
144
  }
147
145
  }
148
146
 
@@ -150,14 +148,22 @@ export function getQualifierMessage(schema?: SchemaObject): string | undefined {
150
148
  let lengthQualifier = "";
151
149
  let minLength;
152
150
  let maxLength;
151
+ const charactersMessage = translate({
152
+ id: OPENAPI_SCHEMA_ITEM.CHARACTERS,
153
+ message: "characters",
154
+ });
155
+ const nonEmptyMessage = translate({
156
+ id: OPENAPI_SCHEMA_ITEM.NON_EMPTY,
157
+ message: "non-empty",
158
+ });
153
159
  if (schema.minLength && schema.minLength > 1) {
154
- minLength = `\`>= ${schema.minLength} characters\``;
160
+ minLength = `\`>= ${schema.minLength} ${charactersMessage}\``;
155
161
  }
156
162
  if (schema.minLength && schema.minLength === 1) {
157
- minLength = `\`non-empty\``;
163
+ minLength = `\`${nonEmptyMessage}\``;
158
164
  }
159
165
  if (schema.maxLength) {
160
- maxLength = `\`<= ${schema.maxLength} characters\``;
166
+ maxLength = `\`<= ${schema.maxLength} ${charactersMessage}\``;
161
167
  }
162
168
 
163
169
  if (minLength && !maxLength) {
@@ -211,9 +217,11 @@ export function getQualifierMessage(schema?: SchemaObject): string | undefined {
211
217
  }
212
218
 
213
219
  if (schema.pattern) {
214
- qualifierGroups.push(
215
- `Value must match regular expression \`${schema.pattern}\``
216
- );
220
+ const expressionMessage = translate({
221
+ id: OPENAPI_SCHEMA_ITEM.EXPRESSION,
222
+ message: "Value must match regular expression",
223
+ });
224
+ qualifierGroups.push(`${expressionMessage} \`${schema.pattern}\``);
217
225
  }
218
226
 
219
227
  // Check if discriminator mapping
@@ -8,6 +8,7 @@
8
8
  import React from "react";
9
9
 
10
10
  import BrowserOnly from "@docusaurus/BrowserOnly";
11
+ import ExecutionEnvironment from "@docusaurus/ExecutionEnvironment";
11
12
  import { useTypedSelector } from "@theme/ApiItem/hooks";
12
13
 
13
14
  function colorForMethod(method: string) {
@@ -38,6 +39,26 @@ export interface Props {
38
39
  }
39
40
 
40
41
  function MethodEndpoint({ method, path, context }: Props) {
42
+ // During SSR, render without Redux store access to avoid "Cannot read properties
43
+ // of null (reading 'store')" errors caused by useSelector running outside a Provider.
44
+ if (!ExecutionEnvironment.canUseDOM) {
45
+ return (
46
+ <>
47
+ <pre className="openapi__method-endpoint">
48
+ <span className={"badge badge--" + colorForMethod(method)}>
49
+ {method === "event" ? "Webhook" : method.toUpperCase()}
50
+ </span>{" "}
51
+ {method !== "event" && (
52
+ <h2 className="openapi__method-endpoint-path">
53
+ {`${path.replace(/{([a-z0-9-_]+)}/gi, ":$1")}`}
54
+ </h2>
55
+ )}
56
+ </pre>
57
+ <div className="openapi__divider" />
58
+ </>
59
+ );
60
+ }
61
+
41
62
  let serverValue = useTypedSelector((state: any) => state.server.value);
42
63
  let serverUrlWithVariables = "";
43
64
 
@@ -9,7 +9,7 @@ import React from "react";
9
9
 
10
10
  import SchemaItem from "@theme/SchemaItem";
11
11
 
12
- import { getQualifierMessage, getSchemaName } from "../../markdown/schema";
12
+ import { getSchemaName } from "../../markdown/schema";
13
13
 
14
14
  interface ResponseHeadersProps {
15
15
  description?: string;
@@ -35,7 +35,6 @@ export const ResponseHeaders: React.FC<{
35
35
  name={name}
36
36
  collapsible={false}
37
37
  schemaName={getSchemaName(schema)}
38
- qualifierMessage={getQualifierMessage(schema)}
39
38
  schema={schema}
40
39
  discriminator={false}
41
40
  children={null}
@@ -21,16 +21,11 @@ import { OPENAPI_SCHEMA_ITEM } from "@theme/translationIds";
21
21
  // eslint-disable-next-line import/no-extraneous-dependencies
22
22
  import { merge } from "allof-merge";
23
23
  import clsx from "clsx";
24
- import {
25
- getQualifierMessage,
26
- getSchemaName,
27
- } from "docusaurus-plugin-openapi-docs/lib/markdown/schema";
28
- import type {
29
- SchemaObject,
30
- SchemaType,
31
- } from "docusaurus-plugin-openapi-docs/src/openapi/types";
32
24
  import isEmpty from "lodash/isEmpty";
33
25
 
26
+ import { getQualifierMessage, getSchemaName } from "../../markdown/schema";
27
+ import type { SchemaObject } from "../../types.d";
28
+
34
29
  // eslint-disable-next-line import/no-extraneous-dependencies
35
30
  // const jsonSchemaMergeAllOf = require("json-schema-merge-allof");
36
31
 
@@ -214,6 +209,14 @@ const AnyOneOf: React.FC<SchemaProps> = ({
214
209
  schemaPath,
215
210
  }) => {
216
211
  const key = schema.oneOf ? "oneOf" : "anyOf";
212
+ const schemaArray = schema[key];
213
+
214
+ // Empty oneOf/anyOf arrays are valid in OpenAPI specs but would cause the
215
+ // Tabs component to throw "requires at least one TabItem". Return null instead.
216
+ if (!schemaArray || !Array.isArray(schemaArray) || schemaArray.length === 0) {
217
+ return null;
218
+ }
219
+
217
220
  const type = schema.oneOf
218
221
  ? translate({ id: OPENAPI_SCHEMA_ITEM.ONE_OF, message: "oneOf" })
219
222
  : translate({ id: OPENAPI_SCHEMA_ITEM.ANY_OF, message: "anyOf" });
@@ -296,7 +299,6 @@ const AnyOneOf: React.FC<SchemaProps> = ({
296
299
  collapsible={false}
297
300
  name={undefined}
298
301
  schemaName={computedSchemaName}
299
- qualifierMessage={getQualifierMessage(anyOneSchema)}
300
302
  schema={anyOneSchema}
301
303
  discriminator={false}
302
304
  children={null}
@@ -313,7 +315,6 @@ const AnyOneOf: React.FC<SchemaProps> = ({
313
315
  collapsible={false}
314
316
  name={undefined}
315
317
  schemaName={computedSchemaName}
316
- qualifierMessage={getQualifierMessage(anyOneSchema)}
317
318
  schema={anyOneSchema}
318
319
  discriminator={false}
319
320
  children={null}
@@ -398,7 +399,6 @@ const Properties: React.FC<SchemaProps> = ({
398
399
  name=""
399
400
  required={false}
400
401
  schemaName="object"
401
- qualifierMessage={undefined}
402
402
  schema={{}}
403
403
  />
404
404
  );
@@ -611,7 +611,6 @@ const AdditionalProperties: React.FC<SchemaProps> = ({
611
611
  name="property name*"
612
612
  required={false}
613
613
  schemaName="any"
614
- qualifierMessage={getQualifierMessage(schema)}
615
614
  schema={schema}
616
615
  collapsible={false}
617
616
  discriminator={false}
@@ -657,7 +656,6 @@ const AdditionalProperties: React.FC<SchemaProps> = ({
657
656
  name="property name*"
658
657
  required={false}
659
658
  schemaName={schemaName}
660
- qualifierMessage={getQualifierMessage(schema)}
661
659
  schema={additionalProperties}
662
660
  collapsible={false}
663
661
  discriminator={false}
@@ -767,7 +765,6 @@ const Items: React.FC<{
767
765
  collapsible={false}
768
766
  name="" // No name for array items
769
767
  schemaName={getSchemaName(itemsSchema)}
770
- qualifierMessage={getQualifierMessage(itemsSchema)}
771
768
  schema={itemsSchema}
772
769
  discriminator={false}
773
770
  children={null}
@@ -927,7 +924,6 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
927
924
  Array.isArray(required) ? required.includes(name) : required
928
925
  }
929
926
  schemaName={schema.allOf[0]}
930
- qualifierMessage={undefined}
931
927
  schema={schema.allOf[0]}
932
928
  discriminator={false}
933
929
  children={null}
@@ -999,7 +995,6 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
999
995
  name={name}
1000
996
  required={Array.isArray(required) ? required.includes(name) : required}
1001
997
  schemaName={mergedSchemaName}
1002
- qualifierMessage={getQualifierMessage(mergedSchemas)}
1003
998
  schema={mergedSchemas}
1004
999
  discriminator={false}
1005
1000
  children={null}
@@ -1013,7 +1008,6 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
1013
1008
  name={name}
1014
1009
  required={Array.isArray(required) ? required.includes(name) : required}
1015
1010
  schemaName={schemaName}
1016
- qualifierMessage={getQualifierMessage(schema)}
1017
1011
  schema={schema}
1018
1012
  discriminator={false}
1019
1013
  children={null}
@@ -1217,7 +1211,6 @@ const SchemaNode: React.FC<SchemaProps> = ({
1217
1211
  name={schema.type}
1218
1212
  required={Boolean(schema.required)}
1219
1213
  schemaName={schemaName}
1220
- qualifierMessage={getQualifierMessage(schema)}
1221
1214
  schema={schema}
1222
1215
  discriminator={false}
1223
1216
  children={null}
@@ -1230,7 +1223,9 @@ const SchemaNode: React.FC<SchemaProps> = ({
1230
1223
 
1231
1224
  export default SchemaNode;
1232
1225
 
1233
- type PrimitiveSchemaType = Exclude<SchemaType, "object" | "array">;
1226
+ type PrimitiveSchemaType =
1227
+ | Exclude<NonNullable<SchemaObject["type"]>, "object" | "array">
1228
+ | "null";
1234
1229
 
1235
1230
  const PRIMITIVE_TYPES: Record<PrimitiveSchemaType, true> = {
1236
1231
  string: true,
@@ -13,6 +13,7 @@ import Markdown from "@theme/Markdown";
13
13
  import { OPENAPI_SCHEMA_ITEM } from "@theme/translationIds";
14
14
  import clsx from "clsx";
15
15
 
16
+ import { getQualifierMessage } from "../../markdown/schema";
16
17
  import { guard } from "../../markdown/utils";
17
18
 
18
19
  export interface Props {
@@ -130,7 +131,11 @@ export default function SchemaItem(props: Props) {
130
131
  </>
131
132
  ));
132
133
 
133
- const renderQualifierMessage = guard(qualifierMessage, (message) => (
134
+ // Generate qualifierMessage from schema if not provided
135
+ const effectiveQualifierMessage =
136
+ qualifierMessage ?? (schema ? getQualifierMessage(schema) : undefined);
137
+
138
+ const renderQualifierMessage = guard(effectiveQualifierMessage, (message) => (
134
139
  <>
135
140
  <Markdown>{message}</Markdown>
136
141
  </>
@@ -223,8 +223,35 @@ function TabsComponent(props: SchemaTabsProps): React.JSX.Element {
223
223
  </div>
224
224
  );
225
225
  }
226
- export default function SchemaTabs(props: SchemaTabsProps): React.JSX.Element {
226
+ export default function SchemaTabs(
227
+ props: SchemaTabsProps
228
+ ): React.JSX.Element | null {
227
229
  const isBrowser = useIsBrowser();
230
+
231
+ const children = Array.isArray(props.children)
232
+ ? props.children.filter(Boolean)
233
+ : props.children
234
+ ? [props.children]
235
+ : [];
236
+
237
+ if (children.length === 0) {
238
+ return null;
239
+ }
240
+
241
+ let sanitizedChildren;
242
+ try {
243
+ sanitizedChildren = sanitizeTabsChildren(children);
244
+ } catch {
245
+ return null;
246
+ }
247
+
248
+ if (
249
+ !sanitizedChildren ||
250
+ (Array.isArray(sanitizedChildren) && sanitizedChildren.length === 0)
251
+ ) {
252
+ return null;
253
+ }
254
+
228
255
  return (
229
256
  <TabsComponent
230
257
  // Remount tabs after hydration
@@ -232,7 +259,7 @@ export default function SchemaTabs(props: SchemaTabsProps): React.JSX.Element {
232
259
  key={String(isBrowser)}
233
260
  {...props}
234
261
  >
235
- {sanitizeTabsChildren(props.children)}
262
+ {sanitizedChildren}
236
263
  </TabsComponent>
237
264
  );
238
265
  }
@@ -79,6 +79,8 @@ export const OPENAPI_SCHEMA = {
79
79
  };
80
80
 
81
81
  export const OPENAPI_SCHEMA_ITEM = {
82
+ CHARACTERS: "theme.openapi.schemaItem.characters",
83
+ NON_EMPTY: "theme.openapi.schemaItem.nonEmpty",
82
84
  REQUIRED: "theme.openapi.schemaItem.required",
83
85
  DEPRECATED: "theme.openapi.schemaItem.deprecated",
84
86
  NULLABLE: "theme.openapi.schemaItem.nullable",
@@ -90,6 +92,7 @@ export const OPENAPI_SCHEMA_ITEM = {
90
92
  ENUM_VALUE: "theme.openapi.schemaItem.enumValue",
91
93
  ENUM_DESCRIPTION: "theme.openapi.schemaItem.enumDescription",
92
94
  POSSIBLE_VALUES: "theme.openapi.schemaItem.possibleValues",
95
+ EXPRESSION: "theme.openapi.schemaItem.expression",
93
96
  ONE_OF: "theme.openapi.schemaItem.oneOf",
94
97
  ANY_OF: "theme.openapi.schemaItem.anyOf",
95
98
  };