docusaurus-plugin-generate-schema-docs 1.2.0 → 1.3.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.
Files changed (81) hide show
  1. package/README.md +42 -6
  2. package/__tests__/ExampleDataLayer.test.js +78 -155
  3. package/__tests__/__fixtures__/static/schemas/add-to-cart-event.json +4 -15
  4. package/__tests__/__fixtures__/static/schemas/choice-event.json +72 -0
  5. package/__tests__/__fixtures__/static/schemas/components/dataLayer.json +52 -54
  6. package/__tests__/__fixtures__/static/schemas/components/product.json +124 -210
  7. package/__tests__/__fixtures__/static/schemas/nested/child-event.json +10 -0
  8. package/__tests__/__fixtures__/static/schemas/nested/grandchild-a.json +9 -0
  9. package/__tests__/__fixtures__/static/schemas/nested/grandchild-b.json +9 -0
  10. package/__tests__/__fixtures__/static/schemas/nested/parent-event.json +7 -0
  11. package/__tests__/__fixtures__/static/schemas/root-any-of-event.json +34 -0
  12. package/__tests__/__fixtures__/static/schemas/root-choice-event.json +36 -0
  13. package/__tests__/__fixtures__/validateSchemas/circular-schema.json +6 -6
  14. package/__tests__/__fixtures__/validateSchemas/components/referenced.json +9 -7
  15. package/__tests__/__fixtures__/validateSchemas/invalid-example-schema.json +7 -7
  16. package/__tests__/__fixtures__/validateSchemas/main-schema-with-missing-ref.json +7 -7
  17. package/__tests__/__fixtures__/validateSchemas/main-schema-with-ref.json +7 -7
  18. package/__tests__/__fixtures__/validateSchemas/no-example-schema.json +11 -11
  19. package/__tests__/__fixtures__/validateSchemas/schema-A.json +5 -5
  20. package/__tests__/__fixtures__/validateSchemas/schema-B.json +5 -5
  21. package/__tests__/__fixtures__/validateSchemas/valid-schema.json +7 -7
  22. package/__tests__/__fixtures_versioned__/static/schemas/1.1.1/add-to-cart-event.json +44 -0
  23. package/__tests__/__fixtures_versioned__/static/schemas/1.1.1/components/dataLayer.json +56 -0
  24. package/__tests__/__fixtures_versioned__/static/schemas/1.1.1/components/product.json +125 -0
  25. package/__tests__/__fixtures_versioned__/static/schemas/next/add-to-cart-event.json +44 -0
  26. package/__tests__/__fixtures_versioned__/static/schemas/next/components/dataLayer.json +56 -0
  27. package/__tests__/__fixtures_versioned__/static/schemas/next/components/product.json +125 -0
  28. package/__tests__/__fixtures_versioned__/versions.json +1 -0
  29. package/__tests__/__snapshots__/ExampleDataLayer.test.js.snap +117 -0
  30. package/__tests__/__snapshots__/generateEventDocs.nested.test.js.snap +92 -0
  31. package/__tests__/__snapshots__/generateEventDocs.test.js.snap +113 -15
  32. package/__tests__/__snapshots__/generateEventDocs.versioned.test.js.snap +53 -0
  33. package/__tests__/components/FoldableRows.test.js +330 -0
  34. package/__tests__/components/PropertiesTable.test.js +31 -14
  35. package/__tests__/components/PropertyRow.test.js +471 -51
  36. package/__tests__/components/SchemaJsonViewer.test.js +23 -19
  37. package/__tests__/components/SchemaRows.test.js +96 -66
  38. package/__tests__/components/SchemaViewer.test.js +34 -17
  39. package/__tests__/components/TableHeader.test.js +12 -12
  40. package/__tests__/generateEventDocs.nested.test.js +80 -0
  41. package/__tests__/generateEventDocs.test.js +77 -71
  42. package/__tests__/generateEventDocs.versioned.test.js +69 -0
  43. package/__tests__/helpers/buildExampleFromSchema.test.js +160 -160
  44. package/__tests__/helpers/file-system.test.js +44 -0
  45. package/__tests__/helpers/getConstraints.test.js +48 -48
  46. package/__tests__/helpers/loadSchema.test.js +11 -5
  47. package/__tests__/helpers/path-helpers.test.js +34 -0
  48. package/__tests__/helpers/processSchema.test.js +42 -22
  49. package/__tests__/helpers/schema-processing.test.js +82 -0
  50. package/__tests__/helpers/schemaToExamples.test.js +56 -0
  51. package/__tests__/helpers/schemaToTableData.filtering.test.js +65 -0
  52. package/__tests__/helpers/schemaToTableData.hierarchicalLines.test.js +539 -0
  53. package/__tests__/helpers/schemaToTableData.test.js +222 -0
  54. package/__tests__/helpers/update-schema-ids.test.js +107 -0
  55. package/__tests__/update-schema-ids.test.js +39 -0
  56. package/__tests__/validateSchemas.test.js +125 -88
  57. package/components/ExampleDataLayer.js +59 -28
  58. package/components/FoldableRows.js +164 -0
  59. package/components/PropertiesTable.js +10 -7
  60. package/components/PropertyRow.js +169 -60
  61. package/components/SchemaJsonViewer.js +6 -6
  62. package/components/SchemaRows.css +236 -14
  63. package/components/SchemaRows.js +24 -41
  64. package/components/SchemaViewer.js +19 -13
  65. package/components/TableHeader.js +12 -12
  66. package/generateEventDocs.js +141 -61
  67. package/helpers/buildExampleFromSchema.js +58 -72
  68. package/helpers/choice-index-template.js +22 -0
  69. package/helpers/file-system.js +32 -0
  70. package/helpers/getConstraints.js +43 -44
  71. package/helpers/loadSchema.js +2 -2
  72. package/helpers/path-helpers.js +22 -0
  73. package/helpers/processSchema.js +19 -19
  74. package/helpers/{mdx-template.js → schema-doc-template.js} +12 -12
  75. package/helpers/schema-processing.js +75 -0
  76. package/helpers/schemaToExamples.js +99 -0
  77. package/helpers/schemaToTableData.js +311 -0
  78. package/helpers/update-schema-ids.js +47 -0
  79. package/index.js +143 -54
  80. package/package.json +1 -1
  81. package/validateSchemas.js +54 -71
@@ -1,40 +1,71 @@
1
1
  import React from 'react';
2
2
  import CodeBlock from '@theme/CodeBlock';
3
- import buildExampleFromSchema from '../helpers/buildExampleFromSchema';
3
+ import Tabs from '@theme/Tabs';
4
+ import TabItem from '@theme/TabItem';
5
+ import Heading from '@theme/Heading';
6
+ import { schemaToExamples } from '../helpers/schemaToExamples';
4
7
 
5
- export default function ExampleDataLayer({ schema }) {
6
- // 1. Identify properties that need to be reset (cleared) first
7
- const clearableProperties = findClearableProperties(schema || {});
8
+ const generateCodeSnippet = (example, schema) => {
9
+ const clearableProperties = findClearableProperties(schema || {});
10
+ let codeSnippet = '';
11
+ const propertiesToClear = clearableProperties.filter(
12
+ (prop) => prop in example,
13
+ );
8
14
 
9
- // 2. Build the main example data
10
- const example = buildExampleFromSchema(schema || {});
15
+ if (propertiesToClear.length > 0) {
16
+ const resetObject = {};
17
+ propertiesToClear.forEach((prop) => {
18
+ resetObject[prop] = null;
19
+ });
20
+ codeSnippet += `window.dataLayer.push(${JSON.stringify(resetObject, null, 2)});\n`;
21
+ }
11
22
 
12
- // 3. Construct the code snippet
13
- let codeSnippet = '';
23
+ codeSnippet += `window.dataLayer.push(${JSON.stringify(example, null, 2)});`;
24
+ return codeSnippet;
25
+ };
14
26
 
15
- // Filter properties to reset to only those present in the example
16
- const propertiesToClear = clearableProperties.filter(prop => prop in example);
27
+ export default function ExampleDataLayer({ schema }) {
28
+ const exampleGroups = schemaToExamples(schema);
17
29
 
18
- // If there are properties to reset, push them as null first
19
- if (propertiesToClear.length > 0)
20
- {
21
- const resetObject = {};
22
- propertiesToClear.forEach(prop => {
23
- resetObject[prop] = null;
24
- });
25
- codeSnippet += `window.dataLayer.push(${JSON.stringify(resetObject, null, 2)});\n`;
26
- }
30
+ if (!exampleGroups || exampleGroups.length === 0) {
31
+ return null;
32
+ }
27
33
 
28
- // Append the main data payload
29
- codeSnippet += `window.dataLayer.push(${JSON.stringify(example, null, 2)});`;
34
+ // Handle the simple case of a single default example with no choices
35
+ if (exampleGroups.length === 1 && exampleGroups[0].property === 'default') {
36
+ const codeSnippet = generateCodeSnippet(
37
+ exampleGroups[0].options[0].example,
38
+ schema,
39
+ );
40
+ return <CodeBlock language="javascript">{codeSnippet}</CodeBlock>;
41
+ }
30
42
 
31
- return <CodeBlock language="javascript">{codeSnippet}</CodeBlock>
32
- };
43
+ return (
44
+ <>
45
+ {exampleGroups.map((group) => (
46
+ <div key={group.property} style={{ marginTop: '20px' }}>
47
+ <Heading as="h4">
48
+ <code>{group.property}</code> options:
49
+ </Heading>
50
+ <Tabs>
51
+ {group.options.map(({ title, example }, index) => (
52
+ <TabItem value={index} label={title} key={index}>
53
+ <CodeBlock language="javascript">
54
+ {generateCodeSnippet(example, schema)}
55
+ </CodeBlock>
56
+ </TabItem>
57
+ ))}
58
+ </Tabs>
59
+ </div>
60
+ ))}
61
+ </>
62
+ );
63
+ }
33
64
 
34
65
  export const findClearableProperties = (schema) => {
35
- if (!schema || !schema.properties) return [];
66
+ if (!schema || !schema.properties) return [];
36
67
 
37
- return Object.entries(schema.properties)
38
- .filter(([key, definition]) => definition["x-gtm-clear"] === true)
39
- .map(([key]) => key);
40
- }
68
+ return Object.entries(schema.properties)
69
+ .filter(([, definition]) => definition['x-gtm-clear'] === true)
70
+ .map(([key]) => key);
71
+ };
@@ -0,0 +1,164 @@
1
+ import React, { useState } from 'react';
2
+ import SchemaRows from './SchemaRows';
3
+ import Heading from '@theme/Heading';
4
+ import clsx from 'clsx';
5
+
6
+ /**
7
+ * Generates inline styles for continuing hierarchical lines through a row.
8
+ * @param {number[]} continuingLevels - Array of ancestor levels that need lines
9
+ * @param {number} level - Current level of the choice
10
+ * @returns {object} Style object with background gradients
11
+ */
12
+ const getContinuingLinesStyle = (continuingLevels = [], level = 0) => {
13
+ const getLevelPosition = (lvl) => lvl * 1.25 + 0.5;
14
+
15
+ const allGradients = [];
16
+ const allSizes = [];
17
+ const allPositions = [];
18
+
19
+ // Draw continuing lines for all ancestor levels
20
+ continuingLevels.forEach((lvl) => {
21
+ const pos = getLevelPosition(lvl);
22
+ allGradients.push(
23
+ 'linear-gradient(var(--ifm-table-border-color), var(--ifm-table-border-color))',
24
+ );
25
+ allSizes.push('1px 100%');
26
+ allPositions.push(`${pos}rem top`);
27
+ });
28
+
29
+ // Also draw the line for the immediate parent level (level - 1) if level > 0
30
+ // This connects the choice rows to their parent property
31
+ if (level > 0) {
32
+ const parentPos = getLevelPosition(level - 1);
33
+ // Check if this position is not already in continuing levels
34
+ if (!continuingLevels.includes(level - 1)) {
35
+ allGradients.push(
36
+ 'linear-gradient(var(--ifm-table-border-color), var(--ifm-table-border-color))',
37
+ );
38
+ allSizes.push('1px 100%');
39
+ allPositions.push(`${parentPos}rem top`);
40
+ }
41
+ }
42
+
43
+ // Calculate indentation based on level
44
+ const paddingLeft = `${level * 1.25 + 0.5}rem`;
45
+
46
+ if (allGradients.length === 0) {
47
+ return { paddingLeft };
48
+ }
49
+
50
+ return {
51
+ paddingLeft,
52
+ backgroundImage: allGradients.join(', '),
53
+ backgroundSize: allSizes.join(', '),
54
+ backgroundPosition: allPositions.join(', '),
55
+ backgroundRepeat: 'no-repeat',
56
+ };
57
+ };
58
+
59
+ // A clickable row that acts as a header/summary for a foldable choice
60
+ const ChoiceRow = ({
61
+ title,
62
+ description,
63
+ onToggle,
64
+ isActive,
65
+ isRadio,
66
+ name,
67
+ continuingLinesStyle,
68
+ }) => (
69
+ <tr className="choice-row">
70
+ <td colSpan={5} style={continuingLinesStyle}>
71
+ <label className="choice-row-header">
72
+ <input
73
+ type={isRadio ? 'radio' : 'checkbox'}
74
+ name={name}
75
+ checked={isActive}
76
+ onChange={onToggle}
77
+ />
78
+ <span
79
+ className={clsx('choice-row-toggle', isRadio ? 'radio' : 'checkbox')}
80
+ />
81
+ <strong>{title}</strong>
82
+ </label>
83
+ {description && <p className="choice-row-description">{description}</p>}
84
+ </td>
85
+ </tr>
86
+ );
87
+
88
+ /**
89
+ * Renders 'oneOf' and 'anyOf' choices as a set of foldable `<tr>` elements
90
+ * that integrate directly into the main table body.
91
+ */
92
+ export default function FoldableRows({ row }) {
93
+ const {
94
+ choiceType,
95
+ options,
96
+ description,
97
+ name,
98
+ required,
99
+ level = 0,
100
+ continuingLevels = [],
101
+ } = row;
102
+ const [openOneOf, setOpenOneOf] = useState(0); // For oneOf, track the single open index
103
+ const [openAnyOf, setOpenAnyOf] = useState({}); // For anyOf, track each option's state
104
+
105
+ const handleAnyOfToggle = (index) => {
106
+ setOpenAnyOf((prev) => ({ ...prev, [index]: !prev[index] }));
107
+ };
108
+
109
+ const selectTitle = `Select ${
110
+ choiceType === 'oneOf' ? 'one' : 'any'
111
+ } of the following options:`;
112
+ const header = name ? (
113
+ <>
114
+ <strong>{name}</strong>
115
+ {required && <span className="required-badge">required</span>}
116
+ {' - '}
117
+ {selectTitle}
118
+ </>
119
+ ) : (
120
+ selectTitle
121
+ );
122
+
123
+ // Calculate continuing lines style for choice rows
124
+ const continuingLinesStyle = getContinuingLinesStyle(continuingLevels, level);
125
+
126
+ return (
127
+ <>
128
+ {/* A header row for the entire choice block */}
129
+ <tr>
130
+ <td colSpan={5} style={continuingLinesStyle}>
131
+ <Heading as="h4" className="choice-row-header-headline">
132
+ {header}
133
+ </Heading>
134
+ <p className="choice-row-header-description">{description}</p>
135
+ </td>
136
+ </tr>
137
+
138
+ {/* Render the options */}
139
+ {options.map((option, index) => {
140
+ const isActive =
141
+ choiceType === 'oneOf' ? openOneOf === index : !!openAnyOf[index];
142
+ return (
143
+ <React.Fragment key={option.title}>
144
+ <ChoiceRow
145
+ title={option.title}
146
+ description={option.description}
147
+ onToggle={() =>
148
+ choiceType === 'oneOf'
149
+ ? setOpenOneOf(index)
150
+ : handleAnyOfToggle(index)
151
+ }
152
+ isActive={isActive}
153
+ isRadio={choiceType === 'oneOf'}
154
+ name={choiceType === 'oneOf' ? row.title : option.title}
155
+ continuingLinesStyle={continuingLinesStyle}
156
+ />
157
+ {/* If the option is active, render its rows directly into the table body */}
158
+ {isActive && <SchemaRows tableData={option.rows} />}
159
+ </React.Fragment>
160
+ );
161
+ })}
162
+ </>
163
+ );
164
+ }
@@ -1,14 +1,17 @@
1
1
  import React from 'react';
2
2
  import SchemaRows from './SchemaRows';
3
3
  import TableHeader from './TableHeader';
4
- import { getConstraints } from '../helpers/getConstraints';
4
+ import { schemaToTableData } from '../helpers/schemaToTableData';
5
5
 
6
6
  export default function PropertiesTable({ schema }) {
7
+ const tableData = schemaToTableData(schema);
7
8
 
8
- return <table>
9
- <TableHeader />
10
- <tbody>
11
- <SchemaRows properties={schema.properties} requiredList={schema.required} getConstraints={getConstraints} />
12
- </tbody>
9
+ return (
10
+ <table>
11
+ <TableHeader />
12
+ <tbody>
13
+ <SchemaRows tableData={tableData} />
14
+ </tbody>
13
15
  </table>
14
- }
16
+ );
17
+ }
@@ -1,74 +1,183 @@
1
1
  import React from 'react';
2
2
  import clsx from 'clsx';
3
+ import CodeBlock from '@theme/CodeBlock';
3
4
 
4
- // Helper to format the property type
5
- const getPropertyType = (type) => {
6
- return Array.isArray(type) ? type.join(' | ') : type;
5
+ /**
6
+ * Formats an example value into a string for display in a CodeBlock.
7
+ * - Objects are stringified with indentation.
8
+ * - Arrays are joined by newlines.
9
+ * @param {any} example The example to format.
10
+ * @returns {string}
11
+ */
12
+ const formatExample = (example) => {
13
+ if (typeof example === 'undefined' || example === null) return '';
14
+ if (Array.isArray(example)) {
15
+ return example
16
+ .map((ex) =>
17
+ typeof ex === 'object' ? JSON.stringify(ex, null, 2) : String(ex),
18
+ )
19
+ .join('\n');
20
+ }
21
+ if (typeof example === 'object') {
22
+ return JSON.stringify(example, null, 2);
23
+ }
24
+ return String(example);
7
25
  };
8
26
 
9
- // Helper to format examples
10
- const formatExamples = (examples) => {
11
- if (!examples)
12
- {
13
- return '';
14
- }
15
- return examples
16
- .map((example) =>
17
- typeof example === 'object' ? JSON.stringify(example) : example
18
- )
19
- .join(', ');
27
+ /**
28
+ * Returns the container symbol for a property based on its container type.
29
+ * @param {string|null} containerType - 'object', 'array', or null
30
+ * @returns {string} The symbol to display
31
+ */
32
+ const getContainerSymbol = (containerType) => {
33
+ if (containerType === 'object') return '{}';
34
+ if (containerType === 'array') return '[]';
35
+ return '';
20
36
  };
21
37
 
22
- const PropertyRow = ({ propertyKey, prop, requiredList, getConstraints }) => {
23
- const isReq = requiredList.includes(propertyKey);
24
- const constraints = getConstraints(prop, isReq);
38
+ /**
39
+ * Renders a single property row in the schema table.
40
+ * All data is passed in via the `row` prop, which comes from `tableData`.
41
+ * This component handles multi-row constraints using `rowSpan`.
42
+ */
43
+ export default function PropertyRow({ row, isLastInGroup }) {
44
+ const {
45
+ name,
46
+ level,
47
+ required,
48
+ propertyType,
49
+ description,
50
+ example,
51
+ constraints,
52
+ hasChildren,
53
+ containerType,
54
+ continuingLevels = [],
55
+ } = row;
25
56
 
26
- const childProperties = prop.properties || (prop.items && prop.items.properties);
27
- const hasChildren = childProperties && Object.keys(childProperties).length > 0;
57
+ const indentStyle = {
58
+ paddingLeft: `${level * 1.25 + 0.5}rem`,
59
+ };
28
60
 
29
- const isObject = prop.type === 'object';
30
- const isArrayOfObjects = prop.type === 'array' && prop.items && prop.items.type === 'object';
61
+ const hasConstraints = constraints && constraints.length > 0;
62
+ // Set rowspan to 1 if there are no constraints.
63
+ const rowSpan = hasConstraints ? constraints.length : 1;
64
+ // Gracefully handle case with no constraints
65
+ const [firstConstraint, ...remainingConstraints] = hasConstraints
66
+ ? constraints
67
+ : [null];
68
+ const formattedExample = formatExample(example);
31
69
 
32
- if ((isObject || isArrayOfObjects) && !hasChildren)
33
- {
34
- return null;
35
- }
70
+ // Generate background gradients for:
71
+ // 1. Parent-to-child line (from 50% down) - for elements with children
72
+ // 2. Continuing ancestor lines (full height) - for ancestors that have more siblings below
73
+ //
74
+ // Position mapping: level N's line is at position (N * 1.25 + 0.5)rem
75
+ // This matches the CSS: level-1 at 0.5rem, level-2 at 1.75rem, etc.
76
+ const getLevelPosition = (lvl) => lvl * 1.25 + 0.5;
36
77
 
37
- const numRows = Math.max(1, constraints.length);
38
- const [firstConstraint, ...remainingConstraints] = constraints;
78
+ const allGradients = [];
79
+ const allSizes = [];
80
+ const allPositions = [];
39
81
 
40
- return (
41
- <React.Fragment>
42
- <tr className={clsx(isReq && 'required-row')}>
43
- <td rowSpan={numRows}>
44
- <strong>{propertyKey}</strong>
45
- {hasChildren && <span style={{ fontSize: '0.8em', marginLeft: '5px' }}>⤵</span>}
46
- </td>
47
- <td rowSpan={numRows}><code>{getPropertyType(prop.type)}</code></td>
48
- <td>
49
- {firstConstraint && (
50
- <code className={clsx('constraint-code', firstConstraint === 'required' && 'required')}>
51
- {firstConstraint}
52
- </code>
53
- )}
54
- </td>
55
- <td rowSpan={numRows}>
56
- {formatExamples(prop.examples)}
57
- </td>
58
- <td rowSpan={numRows}>{prop.description || ''}</td>
59
- </tr>
60
-
61
- {remainingConstraints.map((constraint, index) => (
62
- <tr className={clsx(isReq && 'required-row')} key={`${propertyKey}-constraint-${index}`}>
63
- <td>
64
- <code className={clsx('constraint-code', constraint === 'required' && 'required')}>
65
- {constraint}
66
- </code>
67
- </td>
68
- </tr>
69
- ))}
70
- </React.Fragment>
82
+ // Parent-to-child line: draws from 50% (below symbol) to bottom of cell
83
+ // Position is at the child's level, which is (level * 20 + 8)px
84
+ if (hasChildren) {
85
+ const childLevelPos = level * 1.25 + 0.5;
86
+ allGradients.push(
87
+ 'linear-gradient(to bottom, transparent calc(50% + 1em), var(--ifm-table-border-color) calc(50% + 1em))',
71
88
  );
72
- };
89
+ allSizes.push('1px 100%');
90
+ allPositions.push(`${childLevelPos}rem top`);
91
+ }
92
+
93
+ // Continuing ancestor lines: full-height vertical lines for ancestors with more siblings
94
+ // Filter to only include levels less than (level - 1) since ::before handles immediate parent
95
+ continuingLevels
96
+ .filter((lvl) => lvl < level - 1)
97
+ .forEach((lvl) => {
98
+ const pos = getLevelPosition(lvl);
99
+ allGradients.push(
100
+ 'linear-gradient(var(--ifm-table-border-color), var(--ifm-table-border-color))',
101
+ );
102
+ allSizes.push('1px 100%');
103
+ allPositions.push(`${pos}rem top`);
104
+ });
105
+
106
+ const continuingLinesStyle =
107
+ allGradients.length > 0
108
+ ? {
109
+ backgroundImage: allGradients.join(', '),
110
+ backgroundSize: allSizes.join(', '),
111
+ backgroundPosition: allPositions.join(', '),
112
+ backgroundRepeat: 'no-repeat',
113
+ }
114
+ : {};
115
+
116
+ const containerSymbol = getContainerSymbol(containerType);
117
+
118
+ return (
119
+ <>
120
+ <tr className={clsx(required && 'required-row')}>
121
+ <td
122
+ rowSpan={rowSpan}
123
+ style={{ ...indentStyle, ...continuingLinesStyle }}
124
+ className={clsx(
125
+ level > 0 && `level-${level}`,
126
+ isLastInGroup && 'is-last',
127
+ hasChildren && 'has-children',
128
+ containerType && `container-${containerType}`,
129
+ )}
130
+ >
131
+ <span className="property-name">
132
+ {containerSymbol && (
133
+ <span className="container-symbol">{containerSymbol}</span>
134
+ )}
135
+ <strong>{name}</strong>
136
+ </span>
137
+ </td>
138
+ <td rowSpan={rowSpan}>
139
+ <code>{propertyType}</code>
140
+ </td>
141
+
142
+ {/* The first constraint cell */}
143
+ <td>
144
+ {firstConstraint && (
145
+ <code
146
+ className={clsx(
147
+ 'constraint-code',
148
+ firstConstraint === 'required' && 'required',
149
+ )}
150
+ >
151
+ {firstConstraint}
152
+ </code>
153
+ )}
154
+ </td>
155
+
156
+ <td rowSpan={rowSpan}>
157
+ {formattedExample && (
158
+ <CodeBlock language="json" className="schema-examples">
159
+ {formattedExample}
160
+ </CodeBlock>
161
+ )}
162
+ </td>
163
+ <td rowSpan={rowSpan}>{description || ''}</td>
164
+ </tr>
73
165
 
74
- export default PropertyRow;
166
+ {/* Render subsequent constraints in their own rows */}
167
+ {remainingConstraints.map((constraint) => (
168
+ <tr className={clsx(required && 'required-row')} key={constraint}>
169
+ <td>
170
+ <code
171
+ className={clsx(
172
+ 'constraint-code',
173
+ constraint === 'required' && 'required',
174
+ )}
175
+ >
176
+ {constraint}
177
+ </code>
178
+ </td>
179
+ </tr>
180
+ ))}
181
+ </>
182
+ );
183
+ }
@@ -2,10 +2,10 @@ import React from 'react';
2
2
  import CodeBlock from '@theme/CodeBlock';
3
3
 
4
4
  export default function SchemaJsonViewer({ schema }) {
5
-
6
- return (
7
- <details className="schema-json-viewer">
8
- <summary>View Raw JSON Schema</summary>
9
- <CodeBlock language="json">{JSON.stringify(schema, null, 2)}</CodeBlock>
10
- </details>);
5
+ return (
6
+ <details className="schema-json-viewer">
7
+ <summary>View Raw JSON Schema</summary>
8
+ <CodeBlock language="json">{JSON.stringify(schema, null, 2)}</CodeBlock>
9
+ </details>
10
+ );
11
11
  }