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.
Files changed (81) hide show
  1. package/README.md +60 -2
  2. package/__tests__/ExampleDataLayer.test.js +92 -0
  3. package/__tests__/__fixtures__/static/schemas/add-to-cart-event.json +44 -0
  4. package/__tests__/__fixtures__/static/schemas/choice-event.json +72 -0
  5. package/__tests__/__fixtures__/static/schemas/components/dataLayer.json +56 -0
  6. package/__tests__/__fixtures__/static/schemas/components/product.json +125 -0
  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 +8 -0
  14. package/__tests__/__fixtures__/validateSchemas/components/referenced.json +10 -0
  15. package/__tests__/__fixtures__/validateSchemas/invalid-example-schema.json +8 -0
  16. package/__tests__/__fixtures__/validateSchemas/main-schema-with-missing-ref.json +8 -0
  17. package/__tests__/__fixtures__/validateSchemas/main-schema-with-ref.json +8 -0
  18. package/__tests__/__fixtures__/validateSchemas/no-example-schema.json +12 -0
  19. package/__tests__/__fixtures__/validateSchemas/schema-A.json +7 -0
  20. package/__tests__/__fixtures__/validateSchemas/schema-B.json +7 -0
  21. package/__tests__/__fixtures__/validateSchemas/valid-schema.json +8 -0
  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 +151 -0
  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 +41 -0
  35. package/__tests__/components/PropertyRow.test.js +487 -0
  36. package/__tests__/components/SchemaJsonViewer.test.js +36 -0
  37. package/__tests__/components/SchemaRows.test.js +110 -0
  38. package/__tests__/components/SchemaViewer.test.js +44 -0
  39. package/__tests__/components/TableHeader.test.js +20 -0
  40. package/__tests__/generateEventDocs.nested.test.js +80 -0
  41. package/__tests__/generateEventDocs.test.js +90 -0
  42. package/__tests__/generateEventDocs.versioned.test.js +69 -0
  43. package/__tests__/helpers/buildExampleFromSchema.test.js +188 -0
  44. package/__tests__/helpers/file-system.test.js +44 -0
  45. package/__tests__/helpers/getConstraints.test.js +58 -0
  46. package/__tests__/helpers/loadSchema.test.js +20 -0
  47. package/__tests__/helpers/path-helpers.test.js +34 -0
  48. package/__tests__/helpers/processSchema.test.js +56 -0
  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 +137 -0
  57. package/components/ExampleDataLayer.js +60 -27
  58. package/components/FoldableRows.js +164 -0
  59. package/components/PropertiesTable.js +12 -14
  60. package/components/PropertyRow.js +183 -0
  61. package/components/SchemaJsonViewer.js +8 -7
  62. package/components/SchemaRows.css +250 -0
  63. package/components/SchemaRows.js +24 -69
  64. package/components/SchemaViewer.js +21 -13
  65. package/components/TableHeader.js +15 -0
  66. package/generateEventDocs.js +141 -60
  67. package/helpers/buildExampleFromSchema.js +59 -73
  68. package/helpers/choice-index-template.js +22 -0
  69. package/helpers/file-system.js +32 -0
  70. package/helpers/getConstraints.js +52 -0
  71. package/helpers/loadSchema.js +11 -0
  72. package/helpers/path-helpers.js +22 -0
  73. package/helpers/processSchema.js +32 -0
  74. package/helpers/schema-doc-template.js +36 -0
  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 +146 -47
  80. package/package.json +6 -3
  81. package/validateSchemas.js +56 -70
@@ -1,75 +1,30 @@
1
1
  import React from 'react';
2
+ import './SchemaRows.css';
3
+ import PropertyRow from './PropertyRow';
4
+ import FoldableRows from './FoldableRows';
2
5
 
3
- const SchemaRows = ({ properties, requiredList = [], level = 0 }) => {
4
- return (
5
- <>
6
- {Object.entries(properties).map(([key, prop]) => {
7
- const isReq = requiredList.includes(key);
6
+ /**
7
+ * Renders the rows of the schema table from a flat `tableData` array.
8
+ * It maps over the array and renders the appropriate component for each row.
9
+ */
10
+ export default function SchemaRows({ tableData }) {
11
+ if (!tableData) {
12
+ return null;
13
+ }
8
14
 
9
- // 1. Calculate if it has children (Same as before)
10
- const hasChildren =
11
- (prop.type === 'object' &&
12
- prop.properties &&
13
- Object.keys(prop.properties).length > 0) ||
14
- (prop.type === 'array' &&
15
- prop.items &&
16
- prop.items.properties &&
17
- Object.keys(prop.items.properties).length > 0);
15
+ return tableData.map((row) => {
16
+ const key = row.path.join('.');
18
17
 
19
- const isObject = prop.type === 'object';
20
- const isArrayOfObjects = prop.type === 'array' && prop.items && prop.items.type === 'object';
18
+ if (row.type === 'choice') {
19
+ return <FoldableRows key={key} row={row} />;
20
+ }
21
21
 
22
- if ((isObject || isArrayOfObjects) && !hasChildren)
23
- {
24
- return null;
25
- }
22
+ if (row.type === 'property') {
23
+ return (
24
+ <PropertyRow key={key} row={row} isLastInGroup={row.isLastInGroup} />
25
+ );
26
+ }
26
27
 
27
- return (
28
- <React.Fragment key={key}>
29
- {/* Main property row */}
30
- <tr style={{ backgroundColor: isReq ? 'rgba(255,0,0,0.05)' : 'transparent' }}>
31
- <td>
32
- <strong>{key}</strong>
33
- {hasChildren && <span style={{ fontSize: '0.8em', marginLeft: '5px' }}>⤵</span>}
34
- </td>
35
- <td><code>{Array.isArray(prop.type) ? prop.type.join('|') : prop.type}</code></td>
36
- <td style={{ textAlign: 'center' }}>{isReq ? '✅' : ''}</td>
37
- <td>{prop.examples ? prop.examples.join(', ') : ''}</td>
38
- <td>{prop.description || ''}</td>
39
- </tr>
40
-
41
- {/* Nested children rendered immediately after parent */}
42
- {hasChildren && (
43
- <tr>
44
- <td colSpan="5" style={{ paddingLeft: '20px', borderLeft: '4px solid #eee' }}>
45
- <strong>{prop.type === 'array' ? `${key} [ ]` : `${key} { }`}</strong>
46
- <table style={{ width: '100%', marginTop: '5px' }}>
47
- <thead>
48
- <tr>
49
- <th width="20%">Property</th>
50
- <th width="15%">Type</th>
51
- <th width="10%">Req</th>
52
- <th width="15%">Examples</th>
53
- <th>Description</th>
54
- </tr>
55
- </thead>
56
- <tbody>
57
- <SchemaRows
58
- properties={prop.type === 'object' ? prop.properties : prop.items.properties}
59
- requiredList={prop.type === 'object' ? prop.required || [] : prop.items.required || []}
60
- level={level + 1}
61
- />
62
- </tbody>
63
- </table>
64
- </td>
65
- </tr>
66
- )
67
- }
68
- </React.Fragment >
69
- );
70
- })}
71
- </>
72
- );
73
- };
74
-
75
- export default SchemaRows;
28
+ return null;
29
+ });
30
+ }
@@ -1,19 +1,27 @@
1
+ import React from 'react';
2
+ import Heading from '@theme/Heading';
1
3
  import ExampleDataLayer from './ExampleDataLayer';
2
4
  import PropertiesTable from './PropertiesTable';
3
5
 
4
- // --- Main Exported Component ---
5
- // Helper: Build an example payload from per-property `examples` or other hints
6
-
7
-
8
6
  export default function SchemaViewer({ schema }) {
7
+ const hasOneOfAnyOf =
8
+ schema.oneOf ||
9
+ schema.anyOf ||
10
+ (schema.properties &&
11
+ Object.values(schema.properties).some(
12
+ (prop) => prop.oneOf || prop.anyOf,
13
+ ));
14
+ const exampleTitle = hasOneOfAnyOf
15
+ ? 'DataLayer Examples'
16
+ : 'DataLayer Example';
9
17
 
10
- return (
11
- <div>
12
- <h2>DataLayer Example</h2>
13
- <ExampleDataLayer schema={schema} />
18
+ return (
19
+ <div>
20
+ <Heading as="h2">{exampleTitle}</Heading>
21
+ <ExampleDataLayer schema={schema} />
14
22
 
15
- <h2>Event Properties</h2>
16
- <PropertiesTable schema={schema} />
17
- </div>
18
- );
19
- }
23
+ <Heading as="h2">Event Properties</Heading>
24
+ <PropertiesTable schema={schema} />
25
+ </div>
26
+ );
27
+ }
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+
3
+ export default function TableHeader() {
4
+ return (
5
+ <thead>
6
+ <tr>
7
+ <th>Property</th>
8
+ <th>Type</th>
9
+ <th>Constraints</th>
10
+ <th>Examples</th>
11
+ <th>Description</th>
12
+ </tr>
13
+ </thead>
14
+ );
15
+ }
@@ -1,68 +1,149 @@
1
- import $RefParser from "@apidevtools/json-schema-ref-parser";
2
- import mergeJsonSchema from "json-schema-merge-allof";
3
- import fs from 'fs';
4
1
  import path from 'path';
2
+ import fs from 'fs';
3
+ import { getPathsForVersion } from './helpers/path-helpers.js';
4
+ import { readSchemas, writeDoc, createDir } from './helpers/file-system.js';
5
+ import { processOneOfSchema, slugify } from './helpers/schema-processing.js';
6
+ import SchemaDocTemplate from './helpers/schema-doc-template.js';
7
+ import ChoiceIndexTemplate from './helpers/choice-index-template.js';
8
+ import processSchema from './helpers/processSchema.js';
9
+
10
+ async function generateAndWriteDoc(
11
+ filePath,
12
+ schema,
13
+ eventName,
14
+ outputDir,
15
+ options,
16
+ alreadyMergedSchema = null,
17
+ ) {
18
+ const { organizationName, projectName, siteDir } = options;
19
+ const baseEditUrl = `https://github.com/${organizationName}/${projectName}/edit/main`;
20
+ const PARTIALS_DIR = path.join(siteDir, 'docs/partials');
21
+
22
+ const mergedSchema = alreadyMergedSchema || (await processSchema(filePath));
23
+
24
+ // Check for partials
25
+ const topPartialPath = path.join(PARTIALS_DIR, `${eventName}.mdx`);
26
+ const bottomPartialPath = path.join(PARTIALS_DIR, `${eventName}_bottom.mdx`);
27
+
28
+ let topPartialImport = '';
29
+ let topPartialComponent = '';
30
+ if (fs.existsSync(topPartialPath)) {
31
+ topPartialImport = `import TopPartial from '@site/docs/partials/${eventName}.mdx';`;
32
+ topPartialComponent = '<TopPartial />';
33
+ }
34
+
35
+ let bottomPartialImport = '';
36
+ let bottomPartialComponent = '';
37
+ if (fs.existsSync(bottomPartialPath)) {
38
+ bottomPartialImport = `import BottomPartial from '@site/docs/partials/${eventName}_bottom.mdx';`;
39
+ bottomPartialComponent = '<BottomPartial />';
40
+ }
41
+
42
+ const editUrl = `${baseEditUrl}/${path.relative(
43
+ path.join(siteDir, '..'),
44
+ filePath,
45
+ )}`;
46
+
47
+ const mdxContent = SchemaDocTemplate({
48
+ schema,
49
+ mergedSchema,
50
+ editUrl,
51
+ file: path.basename(filePath),
52
+ topPartialImport,
53
+ bottomPartialImport,
54
+ topPartialComponent,
55
+ bottomPartialComponent,
56
+ });
57
+
58
+ const outputFilename = path.basename(filePath).replace('.json', '.mdx');
59
+ writeDoc(outputDir, outputFilename, mdxContent);
60
+ }
61
+
62
+ async function generateOneOfDocs(
63
+ eventName,
64
+ schema,
65
+ filePath,
66
+ outputDir,
67
+ options,
68
+ ) {
69
+ const eventOutputDir = path.join(outputDir, eventName);
70
+ createDir(eventOutputDir);
71
+
72
+ const processed = await processOneOfSchema(schema, filePath);
73
+
74
+ const indexPageContent = ChoiceIndexTemplate({
75
+ schema,
76
+ processedOptions: processed,
77
+ });
78
+ writeDoc(eventOutputDir, 'index.mdx', indexPageContent);
79
+
80
+ for (const [
81
+ index,
82
+ { slug, schema: processedSchema },
83
+ ] of processed.entries()) {
84
+ const subChoiceType = processedSchema.oneOf ? 'oneOf' : null;
85
+ const prefixedSlug = `${(index + 1).toString().padStart(2, '0')}-${slug}`;
86
+
87
+ if (subChoiceType) {
88
+ const tempFilePath = path.join(eventOutputDir, `${slug}.json`);
89
+ fs.writeFileSync(tempFilePath, JSON.stringify(processedSchema, null, 2));
90
+ await generateOneOfDocs(
91
+ prefixedSlug,
92
+ processedSchema,
93
+ tempFilePath,
94
+ eventOutputDir,
95
+ options,
96
+ );
97
+ fs.unlinkSync(tempFilePath);
98
+ } else {
99
+ const tempFilePath = path.join(eventOutputDir, `${prefixedSlug}.json`);
100
+ fs.writeFileSync(tempFilePath, JSON.stringify(processedSchema, null, 2));
101
+ await generateAndWriteDoc(
102
+ tempFilePath,
103
+ processedSchema,
104
+ slug,
105
+ eventOutputDir,
106
+ options,
107
+ processedSchema,
108
+ );
109
+ fs.unlinkSync(tempFilePath);
110
+ }
111
+ }
112
+ }
113
+
114
+ export default async function generateEventDocs(options) {
115
+ const { siteDir, version, url } = options || {};
116
+ const { schemaDir, outputDir } = getPathsForVersion(version, siteDir);
117
+
118
+ createDir(outputDir);
119
+ const schemas = readSchemas(schemaDir);
120
+
121
+ console.log(`🚀 Generating documentation for ${schemas.length} schemas...`);
5
122
 
6
- export default async function generateEventDocs() {
7
- // CONFIGURATION
8
- const SCHEMA_DIR = 'schemas'; // Where your JSON files are
9
- const OUTPUT_DIR = 'docs/events'; // Where MDX goes
123
+ for (const { fileName, filePath, schema } of schemas) {
124
+ const eventName = fileName.replace('.json', '');
10
125
 
11
- // Ensure output dir exists
12
- if (!fs.existsSync(OUTPUT_DIR))
13
- {
14
- fs.mkdirSync(OUTPUT_DIR, { recursive: true });
126
+ if (version) {
127
+ const baseUrl = url.endsWith('/') ? url.slice(0, -1) : url;
128
+ if (version !== 'current') {
129
+ schema.$id = `${baseUrl}/schemas/${version}/${fileName}`;
130
+ } else {
131
+ schema.$id = `${baseUrl}/schemas/next/${fileName}`;
132
+ }
15
133
  }
16
134
 
17
- // Read all JSON files
18
- const files = fs.readdirSync(SCHEMA_DIR).filter(file => file.endsWith('.json'));
19
-
20
- console.log(`🚀 Generating documentation for ${files.length} schemas...`);
21
-
22
- for (const file of files)
23
- {
24
- const filePath = path.join(SCHEMA_DIR, file);
25
- const rawContent = fs.readFileSync(filePath, 'utf-8');
26
- const schema = JSON.parse(rawContent);
27
-
28
- // First, dereference all $ref properties
29
- const clonedSchema = await $RefParser.dereference(filePath, {
30
- mutateInputSchema: false, dereference: {
31
- circular: 'ignore'
32
- }
33
- });
34
-
35
- // Then merge allOf properties
36
- const mergedSchema = mergeJsonSchema(clonedSchema, {
37
- resolvers: {
38
- defaultResolver: mergeJsonSchema.options.resolvers.title
39
- }
40
- });
41
-
42
- // Define the MDX Content
43
- // We embed the JSON directly into the file to avoid Webpack import issues
44
- const mdxContent = `---
45
- title: ${schema.title}
46
- description: ${schema.description}
47
- sidebar_label: ${schema.title}
48
- ---
49
-
50
- import SchemaViewer from '@theme/SchemaViewer';
51
- import SchemaJsonViewer from '@theme/SchemaJsonViewer';
52
-
53
- # ${schema.title}
54
-
55
- ${schema.description}
56
-
57
- <SchemaViewer schema={${JSON.stringify(mergedSchema)}} />
58
- <SchemaJsonViewer schema={${JSON.stringify(schema)}} />
59
- `;
60
-
61
- // Write the .mdx file
62
- const outputFilename = file.replace('.json', '.mdx');
63
- fs.writeFileSync(path.join(OUTPUT_DIR, outputFilename), mdxContent);
64
- console.log(`✅ Generated docs/events/${outputFilename}`);
135
+ if (schema.oneOf) {
136
+ await generateOneOfDocs(eventName, schema, filePath, outputDir, options);
137
+ } else {
138
+ await generateAndWriteDoc(
139
+ filePath,
140
+ schema,
141
+ eventName,
142
+ outputDir,
143
+ options,
144
+ );
65
145
  }
146
+ }
66
147
 
67
- console.log('🎉 Documentation generation complete!');
148
+ console.log('🎉 Documentation generation complete!');
68
149
  }
@@ -1,83 +1,69 @@
1
+ /**
2
+ * Recursively builds a single, default example object from a JSON schema.
3
+ * It prefers explicit examples, consts, or defaults. For choices (`oneOf`/`anyOf`),
4
+ * it defaults to the first option.
5
+ *
6
+ * @param {object} schema The schema to build an example from.
7
+ * @returns {object|undefined} The generated example.
8
+ */
1
9
  const buildExampleFromSchema = (schema) => {
2
- const buildValue = (prop) => {
3
- if (!prop) return undefined;
10
+ if (!schema) return undefined;
4
11
 
5
- // 1. Prefer explicit examples or constants if available
6
- if (prop.examples && prop.examples.length) return prop.examples[0];
7
- if (prop.const !== undefined) return prop.const;
8
- if (prop.default !== undefined) return prop.default;
12
+ // For choices, default to the first option.
13
+ if (schema.oneOf?.length > 0) {
14
+ return buildExampleFromSchema(schema.oneOf[0]);
15
+ }
16
+ if (schema.anyOf?.length > 0) {
17
+ return buildExampleFromSchema(schema.anyOf[0]);
18
+ }
9
19
 
10
- const type = Array.isArray(prop.type) ? prop.type[0] : prop.type;
20
+ // Prefer const, explicit examples, or default values.
21
+ if (typeof schema.const !== 'undefined') return schema.const;
22
+ if (schema.examples?.length > 0) return schema.examples[0];
23
+ if (typeof schema.default !== 'undefined') return schema.default;
11
24
 
12
- if (type === 'object')
13
- {
14
- if (prop.properties)
15
- {
16
- const obj = {};
17
- Object.entries(prop.properties).forEach(([k, v]) => {
18
- const val = buildValue(v);
19
- // Only add the property if it has a valid value (not undefined)
20
- if (val !== undefined)
21
- {
22
- obj[k] = val;
23
- }
24
- });
25
+ let type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
26
+ if (!type && schema.properties) {
27
+ type = 'object';
28
+ }
25
29
 
26
- // If the object ends up having no keys, consider it "empty" and return undefined
27
- if (Object.keys(obj).length === 0) return undefined;
28
- return obj;
29
- }
30
- // Object with no properties defined
31
- return {};
30
+ if (type === 'object') {
31
+ if (schema.properties) {
32
+ const obj = {};
33
+ Object.entries(schema.properties).forEach(([key, propSchema]) => {
34
+ const value = buildExampleFromSchema(propSchema);
35
+ if (typeof value !== 'undefined') {
36
+ obj[key] = value;
32
37
  }
33
-
34
- if (type === 'array')
35
- {
36
- if (prop.items)
37
- {
38
- const itemVal = buildValue(prop.items);
39
- // If the inner item is valid, return it as an array
40
- if (itemVal !== undefined)
41
- {
42
- return [itemVal];
43
- }
44
- }
45
- // Empty array or array of undefined items
46
- return [];
47
- }
48
-
49
- switch (type)
50
- {
51
- case 'string': return '';
52
- case 'integer':
53
- case 'number': return 0;
54
- case 'boolean': return false;
55
- default: return undefined;
56
- }
57
- };
58
-
59
- // If the schema provides a top-level examples array with an object, prefer it
60
- if (schema && schema.examples && schema.examples.length)
61
- {
62
- const first = schema.examples[0];
63
- if (typeof first === 'object' && first !== null) return first;
38
+ });
39
+ // Return undefined for objects that end up empty.
40
+ return Object.keys(obj).length > 0 ? obj : undefined;
64
41
  }
42
+ // No properties defined, treat as an empty object (which we filter out).
43
+ return undefined;
44
+ }
65
45
 
66
- // Otherwise, build from properties
67
- if (schema && schema.properties)
68
- {
69
- const out = {};
70
- Object.entries(schema.properties).forEach(([k, p]) => {
71
- const val = buildValue(p);
72
- // Only add top-level keys if they are not undefined
73
- if (val !== undefined)
74
- {
75
- out[k] = val;
76
- }
77
- });
78
- return out;
46
+ if (type === 'array') {
47
+ if (schema.items) {
48
+ const itemValue = buildExampleFromSchema(schema.items);
49
+ // Only return an array if the item schema generates a value.
50
+ return typeof itemValue !== 'undefined' ? [itemValue] : undefined;
79
51
  }
52
+ return undefined; // No items defined.
53
+ }
54
+
55
+ // Return placeholder values for primitive types if no other value is found.
56
+ switch (type) {
57
+ case 'string':
58
+ return '';
59
+ case 'integer':
60
+ case 'number':
61
+ return 0;
62
+ case 'boolean':
63
+ return false;
64
+ default:
65
+ return undefined;
66
+ }
67
+ };
80
68
 
81
- return {};
82
- }
83
- export default buildExampleFromSchema;
69
+ export default buildExampleFromSchema;
@@ -0,0 +1,22 @@
1
+ export default function ChoiceIndexTemplate(data) {
2
+ const { schema, processedOptions } = data;
3
+
4
+ return `---
5
+ title: ${schema.title}
6
+ description: "${schema.description}"
7
+ ---
8
+ import SchemaJsonViewer from '@theme/SchemaJsonViewer';
9
+
10
+ # ${schema.title}
11
+
12
+ ${schema.description}
13
+
14
+ Please select one of the following options:
15
+
16
+ ${processedOptions
17
+ .map((option) => `- [${option.schema.title}](./${option.slug})`)
18
+ .join('\n')}
19
+
20
+ <SchemaJsonViewer schema={${JSON.stringify(schema)}} />
21
+ `;
22
+ }
@@ -0,0 +1,32 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import loadSchema from './loadSchema';
4
+
5
+ export function createDir(directory) {
6
+ if (!fs.existsSync(directory)) {
7
+ fs.mkdirSync(directory, { recursive: true });
8
+ }
9
+ }
10
+
11
+ export function readSchemas(directory) {
12
+ const files = fs
13
+ .readdirSync(directory)
14
+ .filter((file) => file.endsWith('.json'));
15
+
16
+ return files.map((file) => {
17
+ const filePath = path.join(directory, file);
18
+ const schema = loadSchema(filePath);
19
+ return {
20
+ fileName: file,
21
+ filePath,
22
+ schema,
23
+ };
24
+ });
25
+ }
26
+
27
+ export function writeDoc(outputDir, fileName, content) {
28
+ fs.writeFileSync(path.join(outputDir, fileName), content);
29
+ console.log(
30
+ `✅ Generated ${path.relative(process.cwd(), path.join(outputDir, fileName))}`,
31
+ );
32
+ }
@@ -0,0 +1,52 @@
1
+ // A list of JSON Schema keywords that have simple key-value constraints.
2
+ const constraintHandlers = {
3
+ // Simple key-value constraints
4
+ minLength: (val) => `minLength: ${val}`,
5
+ maxLength: (val) => `maxLength: ${val}`,
6
+ minimum: (val) => `minimum: ${val}`,
7
+ maximum: (val) => `maximum: ${val}`,
8
+ exclusiveMinimum: (val) => `exclusiveMinimum: ${val}`,
9
+ exclusiveMaximum: (val) => `exclusiveMaximum: ${val}`,
10
+ minItems: (val) => `minItems: ${val}`,
11
+ maxItems: (val) => `maxItems: ${val}`,
12
+ minProperties: (val) => `minProperties: ${val}`,
13
+ maxProperties: (val) => `maxProperties: ${val}`,
14
+ multipleOf: (val) => `multipleOf: ${val}`,
15
+ format: (val) => `format: ${val}`,
16
+ minContains: (val) => `minContains: ${val}`,
17
+ maxContains: (val) => `maxContains: ${val}`,
18
+
19
+ // Special-cased constraints
20
+ pattern: (val) => `pattern: /${val}/`,
21
+ uniqueItems: (val) => (val ? 'uniqueItems: true' : null),
22
+ additionalProperties: (val) =>
23
+ val === false ? 'additionalProperties: false' : null,
24
+ propertyNames: (val) => `propertyNames: ${JSON.stringify(val)}`,
25
+ dependentRequired: (val) => {
26
+ const deps = Object.entries(val)
27
+ .map(([key, depVal]) => `${key} -> [${depVal.join(', ')}]`)
28
+ .join('; ');
29
+ return `dependentRequired: ${deps}`;
30
+ },
31
+ contains: (val) => `contains: ${JSON.stringify(val)}`,
32
+ enum: (val) => `enum: [${val.join(', ')}]`,
33
+ const: (val) => `const: ${JSON.stringify(val)}`,
34
+ };
35
+
36
+ export const getConstraints = (prop, isReq) => {
37
+ const constraints = [];
38
+ if (isReq) {
39
+ constraints.push('required');
40
+ }
41
+
42
+ for (const keyword in constraintHandlers) {
43
+ if (prop[keyword] !== undefined) {
44
+ const handler = constraintHandlers[keyword];
45
+ const result = handler(prop[keyword]);
46
+ if (result) {
47
+ constraints.push(result);
48
+ }
49
+ }
50
+ }
51
+ return constraints;
52
+ };
@@ -0,0 +1,11 @@
1
+ import fs from 'fs';
2
+
3
+ /**
4
+ * Loads a JSON schema file and returns its content as a JSON object.
5
+ * @param {string} filePath Path to the JSON schema file.
6
+ * @returns {object} The parsed JSON schema.
7
+ */
8
+ export default function loadSchema(filePath) {
9
+ const rawContent = fs.readFileSync(filePath, 'utf-8');
10
+ return JSON.parse(rawContent);
11
+ }
@@ -0,0 +1,22 @@
1
+ import path from 'path';
2
+
3
+ export function getPathsForVersion(version, siteDir) {
4
+ let schemaDir;
5
+ let outputDir;
6
+
7
+ if (version) {
8
+ if (version !== 'current') {
9
+ schemaDir = path.join(siteDir, 'static/schemas', version);
10
+ outputDir = path.join(siteDir, 'versioned_docs', `version-${version}`);
11
+ } else {
12
+ schemaDir = path.join(siteDir, 'static/schemas', 'next');
13
+ outputDir = path.join(siteDir, 'docs');
14
+ }
15
+ } else {
16
+ // Non-versioned
17
+ schemaDir = path.join(siteDir, 'static/schemas');
18
+ outputDir = path.join(siteDir, 'docs');
19
+ }
20
+
21
+ return { schemaDir, outputDir };
22
+ }