docusaurus-plugin-generate-schema-docs 1.5.4 → 1.7.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/__tests__/__fixtures__/static/schemas/battle-test-event.json +771 -0
- package/__tests__/__fixtures__/static/schemas/conditional-event.json +52 -0
- package/__tests__/__fixtures__/static/schemas/nested-conditional-event.json +50 -0
- package/__tests__/__snapshots__/generateEventDocs.anchor.test.js.snap +3 -2
- package/__tests__/__snapshots__/generateEventDocs.nested.test.js.snap +4 -2
- package/__tests__/__snapshots__/generateEventDocs.test.js.snap +3 -2
- package/__tests__/components/ConditionalRows.test.js +150 -0
- package/__tests__/components/ConnectorLines.visualRegression.test.js +93 -0
- package/__tests__/components/FoldableRows.test.js +7 -4
- package/__tests__/components/SchemaRows.test.js +31 -0
- package/__tests__/components/__snapshots__/ConnectorLines.visualRegression.test.js.snap +7 -0
- package/__tests__/generateEventDocs.anchor.test.js +7 -0
- package/__tests__/generateEventDocs.nested.test.js +7 -0
- package/__tests__/generateEventDocs.partials.test.js +134 -0
- package/__tests__/generateEventDocs.test.js +7 -0
- package/__tests__/helpers/buildExampleFromSchema.test.js +49 -0
- package/__tests__/helpers/schemaToExamples.test.js +75 -0
- package/__tests__/helpers/schemaToTableData.battleTest.test.js +704 -0
- package/__tests__/helpers/schemaToTableData.hierarchicalLines.test.js +190 -7
- package/__tests__/helpers/schemaToTableData.test.js +263 -2
- package/__tests__/helpers/validator.test.js +6 -6
- package/components/ConditionalRows.js +156 -0
- package/components/FoldableRows.js +88 -61
- package/components/PropertiesTable.js +1 -1
- package/components/PropertyRow.js +24 -8
- package/components/SchemaRows.css +115 -0
- package/components/SchemaRows.js +31 -4
- package/generateEventDocs.js +55 -37
- package/helpers/buildExampleFromSchema.js +11 -0
- package/helpers/choice-index-template.js +2 -1
- package/helpers/continuingLinesStyle.js +169 -0
- package/helpers/schema-doc-template.js +2 -5
- package/helpers/schema-processing.js +3 -0
- package/helpers/schemaToExamples.js +75 -2
- package/helpers/schemaToTableData.js +252 -26
- package/helpers/update-schema-ids.js +3 -3
- package/helpers/validator.js +7 -19
- package/package.json +3 -2
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { getConstraints } from './getConstraints';
|
|
2
2
|
import { getExamples } from './example-helper';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Computes the bracket descriptor for a new group being opened at `level`.
|
|
6
|
+
* `bracketIndex` is the total number of existing parent brackets, so each
|
|
7
|
+
* nested group gets a unique visual position on the right side.
|
|
8
|
+
*/
|
|
9
|
+
function computeOwnBracket(level, parentGroupBrackets) {
|
|
10
|
+
const bracketIndex = parentGroupBrackets.length;
|
|
11
|
+
return { level, bracketIndex };
|
|
12
|
+
}
|
|
13
|
+
|
|
4
14
|
function processOptions(
|
|
5
15
|
choices,
|
|
6
16
|
level,
|
|
@@ -8,6 +18,8 @@ function processOptions(
|
|
|
8
18
|
isNestedInProperty,
|
|
9
19
|
requiredArray = [],
|
|
10
20
|
continuingLevels = [],
|
|
21
|
+
groupBrackets = [],
|
|
22
|
+
choiceIsLastInGroup = true,
|
|
11
23
|
) {
|
|
12
24
|
return choices.map((optionSchema, index) => {
|
|
13
25
|
const optionTitle = optionSchema.title || 'Option';
|
|
@@ -39,10 +51,12 @@ function processOptions(
|
|
|
39
51
|
description: optionSchema.description,
|
|
40
52
|
examples: getExamples(optionSchema),
|
|
41
53
|
constraints: constraints,
|
|
42
|
-
|
|
54
|
+
// Keep connector lines open when the enclosing choice block isn't truly last.
|
|
55
|
+
isLastInGroup: isLastOption && choiceIsLastInGroup,
|
|
43
56
|
hasChildren: false,
|
|
44
57
|
containerType: null,
|
|
45
58
|
continuingLevels: [...continuingLevels],
|
|
59
|
+
groupBrackets: [...groupBrackets],
|
|
46
60
|
});
|
|
47
61
|
} else {
|
|
48
62
|
// This is a complex object within a choice
|
|
@@ -53,7 +67,8 @@ function processOptions(
|
|
|
53
67
|
level,
|
|
54
68
|
isNestedInProperty ? [] : path,
|
|
55
69
|
continuingLevels,
|
|
56
|
-
isLastOption,
|
|
70
|
+
isLastOption && choiceIsLastInGroup,
|
|
71
|
+
groupBrackets,
|
|
57
72
|
);
|
|
58
73
|
}
|
|
59
74
|
|
|
@@ -71,6 +86,7 @@ export function schemaToTableData(
|
|
|
71
86
|
path = [],
|
|
72
87
|
parentContinuingLevels = [],
|
|
73
88
|
isLastOption = true,
|
|
89
|
+
parentGroupBrackets = [],
|
|
74
90
|
) {
|
|
75
91
|
const flatRows = [];
|
|
76
92
|
|
|
@@ -81,7 +97,7 @@ export function schemaToTableData(
|
|
|
81
97
|
) {
|
|
82
98
|
return false;
|
|
83
99
|
}
|
|
84
|
-
if (schemaNode.oneOf || schemaNode.anyOf) {
|
|
100
|
+
if (schemaNode.oneOf || schemaNode.anyOf || schemaNode.if) {
|
|
85
101
|
return false;
|
|
86
102
|
}
|
|
87
103
|
if (
|
|
@@ -93,18 +109,113 @@ export function schemaToTableData(
|
|
|
93
109
|
return Object.values(schemaNode.properties).every(isEffectivelyEmpty);
|
|
94
110
|
}
|
|
95
111
|
|
|
112
|
+
function buildConditionalRow(
|
|
113
|
+
subSchema,
|
|
114
|
+
currentLevel,
|
|
115
|
+
currentPath,
|
|
116
|
+
continuingLevels,
|
|
117
|
+
currentGroupBrackets = [],
|
|
118
|
+
ownContinuingLevels,
|
|
119
|
+
conditionalIsLastInGroup = true,
|
|
120
|
+
) {
|
|
121
|
+
// Inner rows (condition, branches) inherit the parent's continuingLevels.
|
|
122
|
+
// The immediate parent connector (currentLevel - 1) is handled by the
|
|
123
|
+
// ConditionalRows component via its ancestorLevels.push(level - 1).
|
|
124
|
+
const innerContinuingLevels = [...continuingLevels];
|
|
125
|
+
|
|
126
|
+
// Compute the bracket for this if/then/else group
|
|
127
|
+
const ownBracket = computeOwnBracket(currentLevel, currentGroupBrackets);
|
|
128
|
+
const innerGroupBrackets = [...currentGroupBrackets, ownBracket];
|
|
129
|
+
|
|
130
|
+
const conditionRows = schemaToTableData(
|
|
131
|
+
subSchema.if,
|
|
132
|
+
currentLevel,
|
|
133
|
+
currentPath,
|
|
134
|
+
innerContinuingLevels,
|
|
135
|
+
false, // branches always follow condition rows, so they are never "last"
|
|
136
|
+
innerGroupBrackets,
|
|
137
|
+
).map((row) => ({ ...row, isCondition: true }));
|
|
138
|
+
|
|
139
|
+
const hasThen = !!subSchema.then;
|
|
140
|
+
const hasElse = !!subSchema.else;
|
|
141
|
+
|
|
142
|
+
const branches = [];
|
|
143
|
+
if (hasThen) {
|
|
144
|
+
// Then is NOT the last branch if Else exists — use innerContinuingLevels
|
|
145
|
+
// to keep the parent line flowing. If Then IS the last branch, use original.
|
|
146
|
+
const thenLevels = hasElse ? innerContinuingLevels : continuingLevels;
|
|
147
|
+
branches.push({
|
|
148
|
+
title: 'Then',
|
|
149
|
+
description: subSchema.then.description,
|
|
150
|
+
rows: schemaToTableData(
|
|
151
|
+
subSchema.then,
|
|
152
|
+
currentLevel,
|
|
153
|
+
currentPath,
|
|
154
|
+
thenLevels,
|
|
155
|
+
// Keep branch connectors open if this conditional block isn't truly last.
|
|
156
|
+
!hasElse && conditionalIsLastInGroup,
|
|
157
|
+
innerGroupBrackets,
|
|
158
|
+
),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
if (hasElse) {
|
|
162
|
+
// Else is always the last branch — use original continuingLevels
|
|
163
|
+
branches.push({
|
|
164
|
+
title: 'Else',
|
|
165
|
+
description: subSchema.else.description,
|
|
166
|
+
rows: schemaToTableData(
|
|
167
|
+
subSchema.else,
|
|
168
|
+
currentLevel,
|
|
169
|
+
currentPath,
|
|
170
|
+
continuingLevels,
|
|
171
|
+
conditionalIsLastInGroup,
|
|
172
|
+
innerGroupBrackets,
|
|
173
|
+
),
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ownContinuingLevels (when provided) includes currentLevel for the row's
|
|
178
|
+
// header/toggle rendering, since sibling properties' tree lines must continue.
|
|
179
|
+
// Merge with innerContinuingLevels to also include the parent level.
|
|
180
|
+
const rowContinuingLevels = ownContinuingLevels
|
|
181
|
+
? [...new Set([...innerContinuingLevels, ...ownContinuingLevels])]
|
|
182
|
+
: innerContinuingLevels;
|
|
183
|
+
|
|
184
|
+
flatRows.push({
|
|
185
|
+
type: 'conditional',
|
|
186
|
+
path: [...currentPath, 'if/then/else'],
|
|
187
|
+
level: currentLevel,
|
|
188
|
+
isLastInGroup: conditionalIsLastInGroup,
|
|
189
|
+
hasChildren: false,
|
|
190
|
+
containerType: null,
|
|
191
|
+
continuingLevels: [...rowContinuingLevels],
|
|
192
|
+
groupBrackets: [...currentGroupBrackets],
|
|
193
|
+
condition: {
|
|
194
|
+
title: 'If',
|
|
195
|
+
description: subSchema.if.description,
|
|
196
|
+
rows: conditionRows,
|
|
197
|
+
},
|
|
198
|
+
branches,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
96
202
|
function buildRows(
|
|
97
203
|
subSchema,
|
|
98
204
|
currentLevel,
|
|
99
205
|
currentPath,
|
|
100
206
|
requiredFromParent = [],
|
|
101
207
|
continuingLevels = [],
|
|
208
|
+
currentGroupBrackets = [],
|
|
102
209
|
) {
|
|
103
210
|
if (!subSchema) return;
|
|
104
211
|
|
|
105
212
|
if (subSchema.properties) {
|
|
106
213
|
const propKeys = Object.keys(subSchema.properties);
|
|
107
|
-
const hasSiblingChoices = !!(
|
|
214
|
+
const hasSiblingChoices = !!(
|
|
215
|
+
subSchema.oneOf ||
|
|
216
|
+
subSchema.anyOf ||
|
|
217
|
+
subSchema.if
|
|
218
|
+
);
|
|
108
219
|
|
|
109
220
|
// Filter out properties that should be skipped to get accurate count
|
|
110
221
|
const visiblePropKeys = propKeys.filter((name) => {
|
|
@@ -127,20 +238,35 @@ export function schemaToTableData(
|
|
|
127
238
|
const isLast = isLastProp && (currentLevel !== level || isLastOption);
|
|
128
239
|
|
|
129
240
|
const isChoiceWrapper = !!(propSchema.oneOf || propSchema.anyOf);
|
|
241
|
+
const isConditionalWrapper = !!(
|
|
242
|
+
propSchema.if &&
|
|
243
|
+
(propSchema.then || propSchema.else)
|
|
244
|
+
);
|
|
130
245
|
|
|
131
246
|
// Determine if this property has children and what type
|
|
132
247
|
const hasNestedProperties = !!propSchema.properties;
|
|
133
248
|
const hasArrayItems =
|
|
134
|
-
propSchema.type === 'array' &&
|
|
249
|
+
propSchema.type === 'array' &&
|
|
250
|
+
!!(propSchema.items?.properties || propSchema.items?.if);
|
|
135
251
|
const hasNestedChoice = isChoiceWrapper;
|
|
252
|
+
const hasNestedConditional = isConditionalWrapper;
|
|
136
253
|
const hasChildren =
|
|
137
|
-
hasNestedProperties ||
|
|
254
|
+
hasNestedProperties ||
|
|
255
|
+
hasArrayItems ||
|
|
256
|
+
hasNestedChoice ||
|
|
257
|
+
hasNestedConditional;
|
|
138
258
|
|
|
139
259
|
// Determine container type for the symbol
|
|
140
260
|
let containerType = null;
|
|
261
|
+
const choiceOptions = propSchema.oneOf || propSchema.anyOf || [];
|
|
262
|
+
const choiceOptionsAreObjects =
|
|
263
|
+
isChoiceWrapper &&
|
|
264
|
+
choiceOptions.some((opt) => opt.type === 'object' || opt.properties);
|
|
141
265
|
if (
|
|
142
266
|
hasNestedProperties ||
|
|
143
|
-
(isChoiceWrapper && propSchema.type === 'object')
|
|
267
|
+
(isChoiceWrapper && propSchema.type === 'object') ||
|
|
268
|
+
(isConditionalWrapper && propSchema.type === 'object') ||
|
|
269
|
+
choiceOptionsAreObjects
|
|
144
270
|
) {
|
|
145
271
|
containerType = 'object';
|
|
146
272
|
} else if (hasArrayItems) {
|
|
@@ -149,24 +275,36 @@ export function schemaToTableData(
|
|
|
149
275
|
|
|
150
276
|
// Calculate continuing levels for children
|
|
151
277
|
// If this is not the last item, add current level to continuing levels for children
|
|
152
|
-
// If this IS the last item,
|
|
153
|
-
//
|
|
278
|
+
// If this IS the last item, don't add currentLevel (no more siblings at this level).
|
|
279
|
+
// We keep all existing continuingLevels intact — they represent ancestor lines
|
|
280
|
+
// that must continue through all descendants regardless of last-child status.
|
|
154
281
|
const childContinuingLevels = isLast
|
|
155
|
-
? continuingLevels
|
|
282
|
+
? [...continuingLevels]
|
|
156
283
|
: [...continuingLevels, currentLevel];
|
|
157
284
|
|
|
158
|
-
//
|
|
159
|
-
//
|
|
160
|
-
|
|
285
|
+
// A "simple" choice property like user_id: { oneOf: [{ type: "string" }, { type: "integer" }] }
|
|
286
|
+
// where the options are scalar types (no nested properties). These get unwrapped
|
|
287
|
+
// into a choice row directly without their own property row.
|
|
288
|
+
// In contrast, choice wrappers whose options are objects with properties
|
|
289
|
+
// (like contact_method) need their own property row to start a nesting level.
|
|
290
|
+
const isSimpleChoice =
|
|
161
291
|
isChoiceWrapper &&
|
|
162
292
|
!propSchema.properties &&
|
|
163
|
-
propSchema.type !== 'object'
|
|
164
|
-
|
|
293
|
+
propSchema.type !== 'object' &&
|
|
294
|
+
!(propSchema.oneOf || propSchema.anyOf).some((opt) => opt.properties);
|
|
295
|
+
|
|
296
|
+
if (isSimpleChoice) {
|
|
165
297
|
const choiceType = propSchema.oneOf ? 'oneOf' : 'anyOf';
|
|
166
298
|
const choices = propSchema[choiceType];
|
|
299
|
+
const ownBracket = computeOwnBracket(
|
|
300
|
+
currentLevel,
|
|
301
|
+
currentGroupBrackets,
|
|
302
|
+
);
|
|
303
|
+
const innerGroupBrackets = [...currentGroupBrackets, ownBracket];
|
|
167
304
|
flatRows.push({
|
|
168
305
|
type: 'choice',
|
|
169
306
|
choiceType,
|
|
307
|
+
name,
|
|
170
308
|
path: newPath,
|
|
171
309
|
level: currentLevel,
|
|
172
310
|
title: propSchema.title,
|
|
@@ -175,6 +313,7 @@ export function schemaToTableData(
|
|
|
175
313
|
hasChildren: false,
|
|
176
314
|
containerType: null,
|
|
177
315
|
continuingLevels: [...continuingLevels],
|
|
316
|
+
groupBrackets: [...currentGroupBrackets],
|
|
178
317
|
options: processOptions(
|
|
179
318
|
choices,
|
|
180
319
|
currentLevel,
|
|
@@ -182,6 +321,8 @@ export function schemaToTableData(
|
|
|
182
321
|
false,
|
|
183
322
|
subSchema.required || requiredFromParent,
|
|
184
323
|
childContinuingLevels,
|
|
324
|
+
innerGroupBrackets,
|
|
325
|
+
isLast,
|
|
185
326
|
),
|
|
186
327
|
});
|
|
187
328
|
} else {
|
|
@@ -208,6 +349,7 @@ export function schemaToTableData(
|
|
|
208
349
|
hasChildren,
|
|
209
350
|
containerType,
|
|
210
351
|
continuingLevels: [...continuingLevels],
|
|
352
|
+
groupBrackets: [...currentGroupBrackets],
|
|
211
353
|
});
|
|
212
354
|
|
|
213
355
|
if (propSchema.properties) {
|
|
@@ -217,23 +359,50 @@ export function schemaToTableData(
|
|
|
217
359
|
newPath,
|
|
218
360
|
propSchema.required,
|
|
219
361
|
childContinuingLevels,
|
|
362
|
+
currentGroupBrackets,
|
|
220
363
|
);
|
|
221
364
|
} else if (
|
|
222
365
|
propSchema.type === 'array' &&
|
|
223
|
-
propSchema.items?.properties
|
|
366
|
+
(propSchema.items?.properties || propSchema.items?.if)
|
|
224
367
|
) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
368
|
+
if (propSchema.items.properties) {
|
|
369
|
+
buildRows(
|
|
370
|
+
propSchema.items,
|
|
371
|
+
currentLevel + 1,
|
|
372
|
+
[...newPath, '[n]'],
|
|
373
|
+
propSchema.items.required,
|
|
374
|
+
childContinuingLevels,
|
|
375
|
+
currentGroupBrackets,
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
// Handle if/then/else inside array items
|
|
379
|
+
if (
|
|
380
|
+
propSchema.items.if &&
|
|
381
|
+
(propSchema.items.then || propSchema.items.else)
|
|
382
|
+
) {
|
|
383
|
+
buildConditionalRow(
|
|
384
|
+
propSchema.items,
|
|
385
|
+
currentLevel + 1,
|
|
386
|
+
[...newPath, '[n]'],
|
|
387
|
+
childContinuingLevels,
|
|
388
|
+
currentGroupBrackets,
|
|
389
|
+
undefined,
|
|
390
|
+
isLast,
|
|
391
|
+
);
|
|
392
|
+
}
|
|
232
393
|
} else if (isChoiceWrapper) {
|
|
233
394
|
// This handles the "complex" choice property like payment_method.
|
|
234
395
|
// A property row has already been created above, now we add the choice row.
|
|
235
396
|
const choiceType = propSchema.oneOf ? 'oneOf' : 'anyOf';
|
|
236
397
|
const choices = propSchema[choiceType];
|
|
398
|
+
const complexOwnBracket = computeOwnBracket(
|
|
399
|
+
currentLevel + 1,
|
|
400
|
+
currentGroupBrackets,
|
|
401
|
+
);
|
|
402
|
+
const complexInnerBrackets = [
|
|
403
|
+
...currentGroupBrackets,
|
|
404
|
+
complexOwnBracket,
|
|
405
|
+
];
|
|
237
406
|
flatRows.push({
|
|
238
407
|
type: 'choice',
|
|
239
408
|
choiceType,
|
|
@@ -245,6 +414,7 @@ export function schemaToTableData(
|
|
|
245
414
|
hasChildren: false,
|
|
246
415
|
containerType: null,
|
|
247
416
|
continuingLevels: childContinuingLevels,
|
|
417
|
+
groupBrackets: [...currentGroupBrackets],
|
|
248
418
|
options: processOptions(
|
|
249
419
|
choices,
|
|
250
420
|
currentLevel + 1,
|
|
@@ -252,13 +422,39 @@ export function schemaToTableData(
|
|
|
252
422
|
true,
|
|
253
423
|
propSchema.required,
|
|
254
424
|
childContinuingLevels,
|
|
425
|
+
complexInnerBrackets,
|
|
255
426
|
),
|
|
256
427
|
});
|
|
257
428
|
}
|
|
429
|
+
|
|
430
|
+
// Handle if/then/else nested inside a property without its own properties.
|
|
431
|
+
// When propSchema HAS properties, the recursive buildRows call above
|
|
432
|
+
// already handles if/then/else via the root-level check at the end of buildRows.
|
|
433
|
+
if (isConditionalWrapper && !propSchema.properties) {
|
|
434
|
+
buildConditionalRow(
|
|
435
|
+
propSchema,
|
|
436
|
+
currentLevel + 1,
|
|
437
|
+
newPath,
|
|
438
|
+
childContinuingLevels,
|
|
439
|
+
currentGroupBrackets,
|
|
440
|
+
undefined,
|
|
441
|
+
isLast,
|
|
442
|
+
);
|
|
443
|
+
}
|
|
258
444
|
}
|
|
259
445
|
});
|
|
260
446
|
}
|
|
261
447
|
|
|
448
|
+
// When properties coexist with root-level choices or conditionals,
|
|
449
|
+
// the header/toggle rows need the tree line at currentLevel to continue.
|
|
450
|
+
// Only used for the row's own continuingLevels — NOT propagated to inner rows.
|
|
451
|
+
const hasProperties =
|
|
452
|
+
subSchema.properties && Object.keys(subSchema.properties).length > 0;
|
|
453
|
+
const ownContinuingLevels =
|
|
454
|
+
hasProperties && !continuingLevels.includes(currentLevel)
|
|
455
|
+
? [...continuingLevels, currentLevel]
|
|
456
|
+
: [...continuingLevels];
|
|
457
|
+
|
|
262
458
|
// This handles choices at the root of a schema
|
|
263
459
|
const choiceType = subSchema.oneOf
|
|
264
460
|
? 'oneOf'
|
|
@@ -267,6 +463,10 @@ export function schemaToTableData(
|
|
|
267
463
|
: null;
|
|
268
464
|
if (choiceType) {
|
|
269
465
|
const choices = subSchema[choiceType];
|
|
466
|
+
const ownBracket = computeOwnBracket(currentLevel, currentGroupBrackets);
|
|
467
|
+
const innerGroupBrackets = [...currentGroupBrackets, ownBracket];
|
|
468
|
+
const choiceIsLastInGroup =
|
|
469
|
+
isLastOption && !(subSchema.if && (subSchema.then || subSchema.else));
|
|
270
470
|
flatRows.push({
|
|
271
471
|
type: 'choice',
|
|
272
472
|
choiceType,
|
|
@@ -274,10 +474,11 @@ export function schemaToTableData(
|
|
|
274
474
|
level: currentLevel,
|
|
275
475
|
title: subSchema.title,
|
|
276
476
|
description: subSchema.description,
|
|
277
|
-
isLastInGroup:
|
|
477
|
+
isLastInGroup: choiceIsLastInGroup,
|
|
278
478
|
hasChildren: false,
|
|
279
479
|
containerType: null,
|
|
280
|
-
continuingLevels: [...
|
|
480
|
+
continuingLevels: [...ownContinuingLevels],
|
|
481
|
+
groupBrackets: [...currentGroupBrackets],
|
|
281
482
|
options: processOptions(
|
|
282
483
|
choices,
|
|
283
484
|
currentLevel,
|
|
@@ -285,6 +486,8 @@ export function schemaToTableData(
|
|
|
285
486
|
false,
|
|
286
487
|
subSchema.required || requiredFromParent,
|
|
287
488
|
continuingLevels,
|
|
489
|
+
innerGroupBrackets,
|
|
490
|
+
choiceIsLastInGroup,
|
|
288
491
|
),
|
|
289
492
|
});
|
|
290
493
|
} else if (!subSchema.properties && subSchema.type) {
|
|
@@ -303,10 +506,33 @@ export function schemaToTableData(
|
|
|
303
506
|
hasChildren: false,
|
|
304
507
|
containerType: null,
|
|
305
508
|
continuingLevels: [...continuingLevels],
|
|
509
|
+
groupBrackets: [...currentGroupBrackets],
|
|
306
510
|
});
|
|
307
511
|
}
|
|
512
|
+
|
|
513
|
+
// Handle if/then/else at the schema root (or sub-schema root)
|
|
514
|
+
if (subSchema.if && (subSchema.then || subSchema.else)) {
|
|
515
|
+
// ownContinuingLevels includes currentLevel for the row's header/toggle rendering.
|
|
516
|
+
// Inner rows (condition, branches) use the original continuingLevels.
|
|
517
|
+
buildConditionalRow(
|
|
518
|
+
subSchema,
|
|
519
|
+
currentLevel,
|
|
520
|
+
currentPath,
|
|
521
|
+
continuingLevels,
|
|
522
|
+
currentGroupBrackets,
|
|
523
|
+
hasProperties ? [...ownContinuingLevels] : undefined,
|
|
524
|
+
isLastOption,
|
|
525
|
+
);
|
|
526
|
+
}
|
|
308
527
|
}
|
|
309
528
|
|
|
310
|
-
buildRows(
|
|
529
|
+
buildRows(
|
|
530
|
+
schema,
|
|
531
|
+
level,
|
|
532
|
+
path,
|
|
533
|
+
schema.required,
|
|
534
|
+
parentContinuingLevels,
|
|
535
|
+
parentGroupBrackets,
|
|
536
|
+
);
|
|
311
537
|
return flatRows;
|
|
312
538
|
}
|
|
@@ -28,8 +28,8 @@ export default function updateSchemaIds(siteDir, url, version = null) {
|
|
|
28
28
|
? [version]
|
|
29
29
|
: JSON.parse(fs.readFileSync(versionsJsonPath, 'utf8'));
|
|
30
30
|
|
|
31
|
-
for (const
|
|
32
|
-
const schemaDir = path.join(siteDir, 'static/schemas',
|
|
31
|
+
for (const v of versions) {
|
|
32
|
+
const schemaDir = path.join(siteDir, 'static/schemas', v);
|
|
33
33
|
if (!fs.existsSync(schemaDir)) {
|
|
34
34
|
continue;
|
|
35
35
|
}
|
|
@@ -41,7 +41,7 @@ export default function updateSchemaIds(siteDir, url, version = null) {
|
|
|
41
41
|
const relativePath = path.relative(path.join(siteDir, 'static'), file);
|
|
42
42
|
schema.$id = `${baseUrl}/${relativePath.replace(/\\/g, '/')}`;
|
|
43
43
|
fs.writeFileSync(file, JSON.stringify(schema, null, 2));
|
|
44
|
-
console.log(`Updated $id for ${file} in version ${
|
|
44
|
+
console.log(`Updated $id for ${file} in version ${v}`);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
}
|
package/helpers/validator.js
CHANGED
|
@@ -26,31 +26,23 @@ function createAjvInstance(schemas, mainSchema, schemaPath) {
|
|
|
26
26
|
return JSON.parse(schemaContent);
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
const options = {
|
|
29
|
+
const options = {
|
|
30
|
+
allErrors: true,
|
|
31
|
+
schemas: schemas,
|
|
32
|
+
strict: false,
|
|
33
|
+
loadSchema,
|
|
34
|
+
};
|
|
30
35
|
|
|
31
36
|
let ajv;
|
|
32
37
|
if (schemaVersion?.includes('2020-12')) {
|
|
33
|
-
options.strict = false;
|
|
34
|
-
options.loadSchema = loadSchema;
|
|
35
38
|
ajv = new Ajv2020(options);
|
|
36
39
|
} else if (schemaVersion?.includes('2019-09')) {
|
|
37
|
-
options.strict = false;
|
|
38
|
-
options.loadSchema = loadSchema;
|
|
39
40
|
ajv = new Ajv2019(options);
|
|
40
|
-
} else if (schemaVersion?.includes('draft-07')) {
|
|
41
|
-
options.strict = false;
|
|
42
|
-
options.loadSchema = loadSchema;
|
|
43
|
-
ajv = new Ajv(options);
|
|
44
|
-
} else if (schemaVersion?.includes('draft-06')) {
|
|
45
|
-
options.strict = false;
|
|
46
|
-
options.loadSchema = loadSchema;
|
|
47
|
-
ajv = new Ajv(options);
|
|
48
41
|
} else if (schemaVersion?.includes('draft-04')) {
|
|
49
42
|
ajv = new AjvDraft4();
|
|
50
43
|
schemas.forEach((s) => ajv.addSchema(s));
|
|
51
44
|
} else {
|
|
52
|
-
|
|
53
|
-
options.loadSchema = loadSchema;
|
|
45
|
+
// covers draft-07, draft-06, and unknown versions
|
|
54
46
|
ajv = new Ajv(options);
|
|
55
47
|
}
|
|
56
48
|
|
|
@@ -71,10 +63,6 @@ function createAjvInstance(schemas, mainSchema, schemaPath) {
|
|
|
71
63
|
* @returns {function(object): {valid: boolean, errors: object[]}} A function that takes data and returns a validation result.
|
|
72
64
|
*/
|
|
73
65
|
export async function createValidator(schemas, mainSchema, schemaPath) {
|
|
74
|
-
if (!mainSchema) {
|
|
75
|
-
mainSchema = schemas;
|
|
76
|
-
schemas = [mainSchema];
|
|
77
|
-
}
|
|
78
66
|
const ajv = createAjvInstance(schemas, mainSchema, schemaPath);
|
|
79
67
|
|
|
80
68
|
let validate;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docusaurus-plugin-generate-schema-docs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Docusaurus plugin to generate documentation from JSON schemas.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"license": "MIT",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"@apidevtools/json-schema-ref-parser": "^15.1.3",
|
|
13
13
|
"json-schema-merge-allof": "^0.8.1",
|
|
14
14
|
"ajv": "^8.17.1",
|
|
15
|
-
"ajv-draft-04": "^1.0.0"
|
|
15
|
+
"ajv-draft-04": "^1.0.0",
|
|
16
|
+
"ajv-keywords": "^5.1.0"
|
|
16
17
|
},
|
|
17
18
|
"publishConfig": {
|
|
18
19
|
"access": "public",
|