docusaurus-plugin-generate-schema-docs 1.1.1 → 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 +60 -2
- package/__tests__/ExampleDataLayer.test.js +92 -0
- package/__tests__/__fixtures__/static/schemas/add-to-cart-event.json +44 -0
- package/__tests__/__fixtures__/static/schemas/choice-event.json +72 -0
- package/__tests__/__fixtures__/static/schemas/components/dataLayer.json +56 -0
- package/__tests__/__fixtures__/static/schemas/components/product.json +125 -0
- 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 +8 -0
- package/__tests__/__fixtures__/validateSchemas/components/referenced.json +10 -0
- package/__tests__/__fixtures__/validateSchemas/invalid-example-schema.json +8 -0
- package/__tests__/__fixtures__/validateSchemas/main-schema-with-missing-ref.json +8 -0
- package/__tests__/__fixtures__/validateSchemas/main-schema-with-ref.json +8 -0
- package/__tests__/__fixtures__/validateSchemas/no-example-schema.json +12 -0
- package/__tests__/__fixtures__/validateSchemas/schema-A.json +7 -0
- package/__tests__/__fixtures__/validateSchemas/schema-B.json +7 -0
- package/__tests__/__fixtures__/validateSchemas/valid-schema.json +8 -0
- 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 +151 -0
- package/__tests__/__snapshots__/generateEventDocs.versioned.test.js.snap +53 -0
- package/__tests__/components/FoldableRows.test.js +330 -0
- package/__tests__/components/PropertiesTable.test.js +41 -0
- package/__tests__/components/PropertyRow.test.js +487 -0
- package/__tests__/components/SchemaJsonViewer.test.js +36 -0
- package/__tests__/components/SchemaRows.test.js +110 -0
- package/__tests__/components/SchemaViewer.test.js +44 -0
- package/__tests__/components/TableHeader.test.js +20 -0
- package/__tests__/generateEventDocs.nested.test.js +80 -0
- package/__tests__/generateEventDocs.test.js +90 -0
- package/__tests__/generateEventDocs.versioned.test.js +69 -0
- package/__tests__/helpers/buildExampleFromSchema.test.js +188 -0
- package/__tests__/helpers/file-system.test.js +44 -0
- package/__tests__/helpers/getConstraints.test.js +58 -0
- package/__tests__/helpers/loadSchema.test.js +20 -0
- package/__tests__/helpers/path-helpers.test.js +34 -0
- package/__tests__/helpers/processSchema.test.js +56 -0
- 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 +137 -0
- package/components/ExampleDataLayer.js +60 -27
- package/components/FoldableRows.js +164 -0
- package/components/PropertiesTable.js +12 -14
- package/components/PropertyRow.js +183 -0
- package/components/SchemaJsonViewer.js +8 -7
- package/components/SchemaRows.css +250 -0
- package/components/SchemaRows.js +24 -69
- package/components/SchemaViewer.js +21 -13
- package/components/TableHeader.js +15 -0
- package/generateEventDocs.js +141 -60
- package/helpers/buildExampleFromSchema.js +59 -73
- package/helpers/choice-index-template.js +22 -0
- package/helpers/file-system.js +32 -0
- package/helpers/getConstraints.js +52 -0
- package/helpers/loadSchema.js +11 -0
- package/helpers/path-helpers.js +22 -0
- package/helpers/processSchema.js +32 -0
- package/helpers/schema-doc-template.js +36 -0
- 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 +146 -47
- package/package.json +6 -3
- package/validateSchemas.js +56 -70
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
4
|
+
import FoldableRows from '../../components/FoldableRows';
|
|
5
|
+
|
|
6
|
+
jest.mock('../../components/SchemaRows', () => {
|
|
7
|
+
const MockSchemaRows = (props) => (
|
|
8
|
+
// The mock needs to return a valid element to be a child of a tbody
|
|
9
|
+
// We'll use a data-testid to check for its presence.
|
|
10
|
+
<tr data-testid="schema-rows">
|
|
11
|
+
<td>{JSON.stringify(props.tableData)}</td>
|
|
12
|
+
</tr>
|
|
13
|
+
);
|
|
14
|
+
MockSchemaRows.displayName = 'MockSchemaRows';
|
|
15
|
+
return MockSchemaRows;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
jest.mock('@theme/Heading', () => {
|
|
19
|
+
const MockHeading = ({ as: Component, children, ...props }) => (
|
|
20
|
+
<Component {...props}>{children}</Component>
|
|
21
|
+
);
|
|
22
|
+
MockHeading.displayName = 'MockHeading';
|
|
23
|
+
return MockHeading;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('FoldableRows', () => {
|
|
27
|
+
const oneOfRow = {
|
|
28
|
+
type: 'choice',
|
|
29
|
+
choiceType: 'oneOf',
|
|
30
|
+
path: ['payment'],
|
|
31
|
+
level: 1,
|
|
32
|
+
description: 'Select one payment method:',
|
|
33
|
+
options: [
|
|
34
|
+
{
|
|
35
|
+
title: 'Credit Card',
|
|
36
|
+
description: 'Pay with card',
|
|
37
|
+
rows: [{ name: 'cardNumber' }],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
title: 'PayPal',
|
|
41
|
+
description: 'Pay with PayPal',
|
|
42
|
+
rows: [{ name: 'email' }],
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const anyOfRow = {
|
|
48
|
+
type: 'choice',
|
|
49
|
+
choiceType: 'anyOf',
|
|
50
|
+
path: ['contact'],
|
|
51
|
+
level: 1,
|
|
52
|
+
description: 'Select any contact method:',
|
|
53
|
+
options: [
|
|
54
|
+
{
|
|
55
|
+
title: 'Email',
|
|
56
|
+
description: 'Contact via email',
|
|
57
|
+
rows: [{ name: 'email_address' }],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
title: 'Phone',
|
|
61
|
+
description: 'Contact via phone',
|
|
62
|
+
rows: [{ name: 'phone_number' }],
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
it('renders oneOf as a radio-style accordion', () => {
|
|
68
|
+
render(
|
|
69
|
+
<table>
|
|
70
|
+
<tbody>
|
|
71
|
+
<FoldableRows row={oneOfRow} />
|
|
72
|
+
</tbody>
|
|
73
|
+
</table>,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const creditCardToggle = screen.getByText('Credit Card');
|
|
77
|
+
const paypalToggle = screen.getByText('PayPal');
|
|
78
|
+
|
|
79
|
+
// Initially, first option is open
|
|
80
|
+
expect(
|
|
81
|
+
screen.getByText(JSON.stringify([{ name: 'cardNumber' }])),
|
|
82
|
+
).toBeInTheDocument();
|
|
83
|
+
expect(
|
|
84
|
+
screen.queryByText(JSON.stringify([{ name: 'email' }])),
|
|
85
|
+
).not.toBeInTheDocument();
|
|
86
|
+
|
|
87
|
+
// Click the second option
|
|
88
|
+
fireEvent.click(paypalToggle);
|
|
89
|
+
|
|
90
|
+
// Now, second option should be open and first should be closed
|
|
91
|
+
expect(
|
|
92
|
+
screen.queryByText(JSON.stringify([{ name: 'cardNumber' }])),
|
|
93
|
+
).not.toBeInTheDocument();
|
|
94
|
+
expect(
|
|
95
|
+
screen.getByText(JSON.stringify([{ name: 'email' }])),
|
|
96
|
+
).toBeInTheDocument();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('renders anyOf as a checkbox-style accordion', () => {
|
|
100
|
+
render(
|
|
101
|
+
<table>
|
|
102
|
+
<tbody>
|
|
103
|
+
<FoldableRows row={anyOfRow} />
|
|
104
|
+
</tbody>
|
|
105
|
+
</table>,
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
const emailToggle = screen.getByText('Email');
|
|
109
|
+
const phoneToggle = screen.getByText('Phone');
|
|
110
|
+
|
|
111
|
+
// Initially, nothing is open
|
|
112
|
+
expect(screen.queryByTestId('schema-rows')).not.toBeInTheDocument();
|
|
113
|
+
|
|
114
|
+
// Click the first option
|
|
115
|
+
fireEvent.click(emailToggle);
|
|
116
|
+
expect(
|
|
117
|
+
screen.getByText(JSON.stringify([{ name: 'email_address' }])),
|
|
118
|
+
).toBeInTheDocument();
|
|
119
|
+
expect(
|
|
120
|
+
screen.queryByText(JSON.stringify([{ name: 'phone_number' }])),
|
|
121
|
+
).not.toBeInTheDocument();
|
|
122
|
+
|
|
123
|
+
// Click the second option
|
|
124
|
+
fireEvent.click(phoneToggle);
|
|
125
|
+
expect(
|
|
126
|
+
screen.getByText(JSON.stringify([{ name: 'email_address' }])),
|
|
127
|
+
).toBeInTheDocument();
|
|
128
|
+
expect(
|
|
129
|
+
screen.getByText(JSON.stringify([{ name: 'phone_number' }])),
|
|
130
|
+
).toBeInTheDocument();
|
|
131
|
+
|
|
132
|
+
// Click the first option again to close it
|
|
133
|
+
fireEvent.click(emailToggle);
|
|
134
|
+
expect(
|
|
135
|
+
screen.queryByText(JSON.stringify([{ name: 'email_address' }])),
|
|
136
|
+
).not.toBeInTheDocument();
|
|
137
|
+
expect(
|
|
138
|
+
screen.getByText(JSON.stringify([{ name: 'phone_number' }])),
|
|
139
|
+
).toBeInTheDocument();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
describe('hierarchical lines feature', () => {
|
|
143
|
+
it('applies padding-left based on level using rem units', () => {
|
|
144
|
+
const rowWithLevel = {
|
|
145
|
+
type: 'choice',
|
|
146
|
+
choiceType: 'oneOf',
|
|
147
|
+
path: ['nested', 'payment'],
|
|
148
|
+
level: 2,
|
|
149
|
+
description: 'Nested choice',
|
|
150
|
+
continuingLevels: [],
|
|
151
|
+
options: [
|
|
152
|
+
{
|
|
153
|
+
title: 'Option A',
|
|
154
|
+
description: 'First option',
|
|
155
|
+
rows: [{ name: 'fieldA' }],
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const { container } = render(
|
|
161
|
+
<table>
|
|
162
|
+
<tbody>
|
|
163
|
+
<FoldableRows row={rowWithLevel} />
|
|
164
|
+
</tbody>
|
|
165
|
+
</table>,
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const cells = container.querySelectorAll('td[colspan="5"]');
|
|
169
|
+
// level 2: 2 * 1.25 + 0.5 = 3rem
|
|
170
|
+
cells.forEach((cell) => {
|
|
171
|
+
expect(cell.style.paddingLeft).toBe('3rem');
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('applies background-image for continuing ancestor lines', () => {
|
|
176
|
+
const rowWithContinuingLevels = {
|
|
177
|
+
type: 'choice',
|
|
178
|
+
choiceType: 'anyOf',
|
|
179
|
+
path: ['deeply', 'nested', 'choice'],
|
|
180
|
+
level: 2,
|
|
181
|
+
description: 'Choice with continuing lines',
|
|
182
|
+
continuingLevels: [0], // Ancestor at level 0 has more siblings
|
|
183
|
+
options: [
|
|
184
|
+
{
|
|
185
|
+
title: 'Option A',
|
|
186
|
+
rows: [{ name: 'fieldA' }],
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const { container } = render(
|
|
192
|
+
<table>
|
|
193
|
+
<tbody>
|
|
194
|
+
<FoldableRows row={rowWithContinuingLevels} />
|
|
195
|
+
</tbody>
|
|
196
|
+
</table>,
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
const cells = container.querySelectorAll('td[colspan="5"]');
|
|
200
|
+
cells.forEach((cell) => {
|
|
201
|
+
expect(cell.style.backgroundImage).toContain('linear-gradient');
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('applies background-image for immediate parent level connection', () => {
|
|
206
|
+
const rowWithParentLevel = {
|
|
207
|
+
type: 'choice',
|
|
208
|
+
choiceType: 'oneOf',
|
|
209
|
+
path: ['parent', 'choice'],
|
|
210
|
+
level: 1,
|
|
211
|
+
description: 'Choice at level 1',
|
|
212
|
+
continuingLevels: [],
|
|
213
|
+
options: [
|
|
214
|
+
{
|
|
215
|
+
title: 'Option A',
|
|
216
|
+
rows: [{ name: 'fieldA' }],
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const { container } = render(
|
|
222
|
+
<table>
|
|
223
|
+
<tbody>
|
|
224
|
+
<FoldableRows row={rowWithParentLevel} />
|
|
225
|
+
</tbody>
|
|
226
|
+
</table>,
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
const cells = container.querySelectorAll('td[colspan="5"]');
|
|
230
|
+
// Should have a line at parent level (level 0) position
|
|
231
|
+
cells.forEach((cell) => {
|
|
232
|
+
expect(cell.style.backgroundImage).toContain('linear-gradient');
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('has no background-image for root level choices with no continuing levels', () => {
|
|
237
|
+
const rootLevelRow = {
|
|
238
|
+
type: 'choice',
|
|
239
|
+
choiceType: 'oneOf',
|
|
240
|
+
path: ['user_id'],
|
|
241
|
+
level: 0,
|
|
242
|
+
description: 'Root level choice',
|
|
243
|
+
continuingLevels: [],
|
|
244
|
+
options: [
|
|
245
|
+
{
|
|
246
|
+
title: 'Option A',
|
|
247
|
+
rows: [{ name: 'fieldA' }],
|
|
248
|
+
},
|
|
249
|
+
],
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const { container } = render(
|
|
253
|
+
<table>
|
|
254
|
+
<tbody>
|
|
255
|
+
<FoldableRows row={rootLevelRow} />
|
|
256
|
+
</tbody>
|
|
257
|
+
</table>,
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
const cells = container.querySelectorAll('td[colspan="5"]');
|
|
261
|
+
cells.forEach((cell) => {
|
|
262
|
+
expect(cell.style.backgroundImage).toBe('');
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it('combines multiple continuing levels in background-image', () => {
|
|
267
|
+
const rowWithMultipleLevels = {
|
|
268
|
+
type: 'choice',
|
|
269
|
+
choiceType: 'anyOf',
|
|
270
|
+
path: ['a', 'b', 'c', 'choice'],
|
|
271
|
+
level: 3,
|
|
272
|
+
description: 'Deeply nested choice',
|
|
273
|
+
continuingLevels: [0, 1], // Multiple ancestors have siblings
|
|
274
|
+
options: [
|
|
275
|
+
{
|
|
276
|
+
title: 'Option A',
|
|
277
|
+
rows: [{ name: 'fieldA' }],
|
|
278
|
+
},
|
|
279
|
+
],
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const { container } = render(
|
|
283
|
+
<table>
|
|
284
|
+
<tbody>
|
|
285
|
+
<FoldableRows row={rowWithMultipleLevels} />
|
|
286
|
+
</tbody>
|
|
287
|
+
</table>,
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
const cells = container.querySelectorAll('td[colspan="5"]');
|
|
291
|
+
cells.forEach((cell) => {
|
|
292
|
+
const bgImage = cell.style.backgroundImage;
|
|
293
|
+
// Should have multiple gradients (one for each continuing level + parent)
|
|
294
|
+
const gradientCount = (bgImage.match(/linear-gradient/g) || []).length;
|
|
295
|
+
expect(gradientCount).toBeGreaterThanOrEqual(2);
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('applies correct indentation for level 0', () => {
|
|
300
|
+
const levelZeroRow = {
|
|
301
|
+
type: 'choice',
|
|
302
|
+
choiceType: 'oneOf',
|
|
303
|
+
path: ['user_id'],
|
|
304
|
+
level: 0,
|
|
305
|
+
description: 'Level 0 choice',
|
|
306
|
+
continuingLevels: [],
|
|
307
|
+
options: [
|
|
308
|
+
{
|
|
309
|
+
title: 'Option A',
|
|
310
|
+
rows: [{ name: 'fieldA' }],
|
|
311
|
+
},
|
|
312
|
+
],
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const { container } = render(
|
|
316
|
+
<table>
|
|
317
|
+
<tbody>
|
|
318
|
+
<FoldableRows row={levelZeroRow} />
|
|
319
|
+
</tbody>
|
|
320
|
+
</table>,
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
const cells = container.querySelectorAll('td[colspan="5"]');
|
|
324
|
+
// level 0: 0 * 1.25 + 0.5 = 0.5rem
|
|
325
|
+
cells.forEach((cell) => {
|
|
326
|
+
expect(cell.style.paddingLeft).toBe('0.5rem');
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { render } from '@testing-library/react';
|
|
4
|
+
import PropertiesTable from '../../components/PropertiesTable';
|
|
5
|
+
|
|
6
|
+
jest.mock('../../components/TableHeader', () => {
|
|
7
|
+
const MockTableHeader = () => (
|
|
8
|
+
<thead>
|
|
9
|
+
<tr>
|
|
10
|
+
<th>Mocked TableHeader</th>
|
|
11
|
+
</tr>
|
|
12
|
+
</thead>
|
|
13
|
+
);
|
|
14
|
+
MockTableHeader.displayName = 'MockTableHeader';
|
|
15
|
+
return MockTableHeader;
|
|
16
|
+
});
|
|
17
|
+
jest.mock('../../components/SchemaRows', () => {
|
|
18
|
+
const MockSchemaRows = () => (
|
|
19
|
+
<tr>
|
|
20
|
+
<td>Mocked SchemaRows</td>
|
|
21
|
+
</tr>
|
|
22
|
+
);
|
|
23
|
+
MockSchemaRows.displayName = 'MockSchemaRows';
|
|
24
|
+
return MockSchemaRows;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe('PropertiesTable', () => {
|
|
28
|
+
it('renders the table with header and schema rows', () => {
|
|
29
|
+
const schema = {
|
|
30
|
+
properties: {
|
|
31
|
+
name: { type: 'string' },
|
|
32
|
+
},
|
|
33
|
+
required: ['name'],
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const { getByText } = render(<PropertiesTable schema={schema} />);
|
|
37
|
+
|
|
38
|
+
expect(getByText('Mocked TableHeader')).toBeInTheDocument();
|
|
39
|
+
expect(getByText('Mocked SchemaRows')).toBeInTheDocument();
|
|
40
|
+
});
|
|
41
|
+
});
|