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.
- package/README.md +42 -6
- package/__tests__/ExampleDataLayer.test.js +78 -155
- package/__tests__/__fixtures__/static/schemas/add-to-cart-event.json +4 -15
- package/__tests__/__fixtures__/static/schemas/choice-event.json +72 -0
- package/__tests__/__fixtures__/static/schemas/components/dataLayer.json +52 -54
- package/__tests__/__fixtures__/static/schemas/components/product.json +124 -210
- package/__tests__/__fixtures__/static/schemas/nested/child-event.json +10 -0
- package/__tests__/__fixtures__/static/schemas/nested/grandchild-a.json +9 -0
- package/__tests__/__fixtures__/static/schemas/nested/grandchild-b.json +9 -0
- package/__tests__/__fixtures__/static/schemas/nested/parent-event.json +7 -0
- package/__tests__/__fixtures__/static/schemas/root-any-of-event.json +34 -0
- package/__tests__/__fixtures__/static/schemas/root-choice-event.json +36 -0
- package/__tests__/__fixtures__/validateSchemas/circular-schema.json +6 -6
- package/__tests__/__fixtures__/validateSchemas/components/referenced.json +9 -7
- package/__tests__/__fixtures__/validateSchemas/invalid-example-schema.json +7 -7
- package/__tests__/__fixtures__/validateSchemas/main-schema-with-missing-ref.json +7 -7
- package/__tests__/__fixtures__/validateSchemas/main-schema-with-ref.json +7 -7
- package/__tests__/__fixtures__/validateSchemas/no-example-schema.json +11 -11
- package/__tests__/__fixtures__/validateSchemas/schema-A.json +5 -5
- package/__tests__/__fixtures__/validateSchemas/schema-B.json +5 -5
- package/__tests__/__fixtures__/validateSchemas/valid-schema.json +7 -7
- package/__tests__/__fixtures_versioned__/static/schemas/1.1.1/add-to-cart-event.json +44 -0
- package/__tests__/__fixtures_versioned__/static/schemas/1.1.1/components/dataLayer.json +56 -0
- package/__tests__/__fixtures_versioned__/static/schemas/1.1.1/components/product.json +125 -0
- package/__tests__/__fixtures_versioned__/static/schemas/next/add-to-cart-event.json +44 -0
- package/__tests__/__fixtures_versioned__/static/schemas/next/components/dataLayer.json +56 -0
- package/__tests__/__fixtures_versioned__/static/schemas/next/components/product.json +125 -0
- package/__tests__/__fixtures_versioned__/versions.json +1 -0
- package/__tests__/__snapshots__/ExampleDataLayer.test.js.snap +117 -0
- package/__tests__/__snapshots__/generateEventDocs.nested.test.js.snap +92 -0
- package/__tests__/__snapshots__/generateEventDocs.test.js.snap +113 -15
- package/__tests__/__snapshots__/generateEventDocs.versioned.test.js.snap +53 -0
- package/__tests__/components/FoldableRows.test.js +330 -0
- package/__tests__/components/PropertiesTable.test.js +31 -14
- package/__tests__/components/PropertyRow.test.js +471 -51
- package/__tests__/components/SchemaJsonViewer.test.js +23 -19
- package/__tests__/components/SchemaRows.test.js +96 -66
- package/__tests__/components/SchemaViewer.test.js +34 -17
- package/__tests__/components/TableHeader.test.js +12 -12
- package/__tests__/generateEventDocs.nested.test.js +80 -0
- package/__tests__/generateEventDocs.test.js +77 -71
- package/__tests__/generateEventDocs.versioned.test.js +69 -0
- package/__tests__/helpers/buildExampleFromSchema.test.js +160 -160
- package/__tests__/helpers/file-system.test.js +44 -0
- package/__tests__/helpers/getConstraints.test.js +48 -48
- package/__tests__/helpers/loadSchema.test.js +11 -5
- package/__tests__/helpers/path-helpers.test.js +34 -0
- package/__tests__/helpers/processSchema.test.js +42 -22
- package/__tests__/helpers/schema-processing.test.js +82 -0
- package/__tests__/helpers/schemaToExamples.test.js +56 -0
- package/__tests__/helpers/schemaToTableData.filtering.test.js +65 -0
- package/__tests__/helpers/schemaToTableData.hierarchicalLines.test.js +539 -0
- package/__tests__/helpers/schemaToTableData.test.js +222 -0
- package/__tests__/helpers/update-schema-ids.test.js +107 -0
- package/__tests__/update-schema-ids.test.js +39 -0
- package/__tests__/validateSchemas.test.js +125 -88
- package/components/ExampleDataLayer.js +59 -28
- package/components/FoldableRows.js +164 -0
- package/components/PropertiesTable.js +10 -7
- package/components/PropertyRow.js +169 -60
- package/components/SchemaJsonViewer.js +6 -6
- package/components/SchemaRows.css +236 -14
- package/components/SchemaRows.js +24 -41
- package/components/SchemaViewer.js +19 -13
- package/components/TableHeader.js +12 -12
- package/generateEventDocs.js +141 -61
- package/helpers/buildExampleFromSchema.js +58 -72
- package/helpers/choice-index-template.js +22 -0
- package/helpers/file-system.js +32 -0
- package/helpers/getConstraints.js +43 -44
- package/helpers/loadSchema.js +2 -2
- package/helpers/path-helpers.js +22 -0
- package/helpers/processSchema.js +19 -19
- package/helpers/{mdx-template.js → schema-doc-template.js} +12 -12
- package/helpers/schema-processing.js +75 -0
- package/helpers/schemaToExamples.js +99 -0
- package/helpers/schemaToTableData.js +311 -0
- package/helpers/update-schema-ids.js +47 -0
- package/index.js +143 -54
- package/package.json +1 -1
- package/validateSchemas.js +54 -71
|
@@ -1,40 +1,71 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import CodeBlock from '@theme/CodeBlock';
|
|
3
|
-
import
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
10
|
-
const
|
|
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
|
-
|
|
13
|
-
|
|
23
|
+
codeSnippet += `window.dataLayer.push(${JSON.stringify(example, null, 2)});`;
|
|
24
|
+
return codeSnippet;
|
|
25
|
+
};
|
|
14
26
|
|
|
15
|
-
|
|
16
|
-
|
|
27
|
+
export default function ExampleDataLayer({ schema }) {
|
|
28
|
+
const exampleGroups = schemaToExamples(schema);
|
|
17
29
|
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
29
|
-
|
|
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
|
-
|
|
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
|
-
|
|
66
|
+
if (!schema || !schema.properties) return [];
|
|
36
67
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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 {
|
|
4
|
+
import { schemaToTableData } from '../helpers/schemaToTableData';
|
|
5
5
|
|
|
6
6
|
export default function PropertiesTable({ schema }) {
|
|
7
|
+
const tableData = schemaToTableData(schema);
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
27
|
-
|
|
57
|
+
const indentStyle = {
|
|
58
|
+
paddingLeft: `${level * 1.25 + 0.5}rem`,
|
|
59
|
+
};
|
|
28
60
|
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
38
|
-
|
|
78
|
+
const allGradients = [];
|
|
79
|
+
const allSizes = [];
|
|
80
|
+
const allPositions = [];
|
|
39
81
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
}
|