docusaurus-plugin-generate-schema-docs 1.8.1 → 1.8.3
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 +17 -7
- package/__tests__/__fixtures__/validateSchemas/main-schema-with-constraints-ref.json +20 -0
- package/__tests__/__snapshots__/generateEventDocs.anchor.test.js.snap +15 -3
- package/__tests__/__snapshots__/generateEventDocs.nested.test.js.snap +20 -4
- package/__tests__/__snapshots__/generateEventDocs.test.js.snap +30 -6
- package/__tests__/__snapshots__/generateEventDocs.versioned.test.js.snap +10 -2
- package/__tests__/components/ConditionalRows.test.js +28 -0
- package/__tests__/components/FoldableRows.test.js +31 -290
- package/__tests__/components/PropertyRow.test.js +216 -0
- package/__tests__/components/SchemaJsonViewer.test.js +76 -10
- package/__tests__/components/SchemaRows.test.js +62 -12
- package/__tests__/components/__snapshots__/ConnectorLines.visualRegression.test.js.snap +3 -3
- package/__tests__/generateEventDocs.partials.test.js +95 -0
- package/__tests__/generateEventDocs.test.js +3 -0
- package/__tests__/helpers/processSchema.test.js +29 -0
- package/__tests__/helpers/schemaToTableData.test.js +112 -0
- package/__tests__/helpers/validator.test.js +32 -0
- package/components/ConditionalRows.js +6 -3
- package/components/FoldableRows.js +9 -3
- package/components/PropertiesTable.js +2 -1
- package/components/PropertyRow.js +90 -5
- package/components/SchemaJsonViewer.js +221 -4
- package/components/SchemaRows.css +98 -7
- package/components/SchemaRows.js +11 -1
- package/generateEventDocs.js +184 -18
- package/helpers/buildExampleFromSchema.js +3 -3
- package/helpers/choice-index-template.js +6 -2
- package/helpers/constraintSchemaPaths.js +46 -0
- package/helpers/file-system.js +28 -0
- package/helpers/mergeSchema.js +16 -0
- package/helpers/processSchema.js +19 -6
- package/helpers/schema-doc-template.js +7 -1
- package/helpers/schema-processing.js +4 -11
- package/helpers/schemaToExamples.js +4 -4
- package/helpers/schemaToTableData.js +68 -7
- package/helpers/validator.js +7 -0
- package/package.json +1 -1
package/generateEventDocs.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import { getPathsForVersion } from './helpers/path-helpers.js';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
readSchemas,
|
|
6
|
+
readSchemaSources,
|
|
7
|
+
writeDoc,
|
|
8
|
+
createDir,
|
|
9
|
+
} from './helpers/file-system.js';
|
|
5
10
|
import { processOneOfSchema, slugify } from './helpers/schema-processing.js';
|
|
6
11
|
import SchemaDocTemplate from './helpers/schema-doc-template.js';
|
|
7
12
|
import ChoiceIndexTemplate from './helpers/choice-index-template.js';
|
|
@@ -12,15 +17,129 @@ function buildEditUrl(organizationName, projectName, siteDir, filePath) {
|
|
|
12
17
|
return `${baseEditUrl}/${path.relative(path.join(siteDir, '..'), filePath)}`;
|
|
13
18
|
}
|
|
14
19
|
|
|
15
|
-
function
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
function toSiteImportPath(siteDir, absolutePath) {
|
|
21
|
+
return `@site/${path.relative(siteDir, absolutePath).split(path.sep).join('/')}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function resolvePartial({
|
|
25
|
+
scopedPartialPath,
|
|
26
|
+
fallbackPartialPath,
|
|
27
|
+
componentPrefix,
|
|
28
|
+
siteDir,
|
|
29
|
+
allowFallback,
|
|
30
|
+
}) {
|
|
31
|
+
const selectedPartialPath = fs.existsSync(scopedPartialPath)
|
|
32
|
+
? scopedPartialPath
|
|
33
|
+
: allowFallback && fs.existsSync(fallbackPartialPath)
|
|
34
|
+
? fallbackPartialPath
|
|
35
|
+
: null;
|
|
36
|
+
|
|
37
|
+
if (!selectedPartialPath) return { import: '', component: '' };
|
|
38
|
+
const fileImportPath = toSiteImportPath(siteDir, selectedPartialPath);
|
|
18
39
|
return {
|
|
19
|
-
import: `import ${componentPrefix} from '
|
|
40
|
+
import: `import ${componentPrefix} from '${fileImportPath}';`,
|
|
20
41
|
component: `<${componentPrefix} />`,
|
|
21
42
|
};
|
|
22
43
|
}
|
|
23
44
|
|
|
45
|
+
function isPlainObject(value) {
|
|
46
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function toSchemaSourceKey(schemaDir, filePath) {
|
|
50
|
+
return path.relative(schemaDir, filePath).split(path.sep).join('/');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function resolveLocalSchemaRef(currentPath, ref) {
|
|
54
|
+
if (!ref || ref.startsWith('#') || /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(ref)) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const [fileRef] = ref.split('#');
|
|
59
|
+
return path
|
|
60
|
+
.normalize(path.join(path.dirname(currentPath), fileRef))
|
|
61
|
+
.split(path.sep)
|
|
62
|
+
.join('/');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function collectReachableSchemaSources(sourcePath, allSchemaSources) {
|
|
66
|
+
if (!sourcePath || !allSchemaSources[sourcePath]) return {};
|
|
67
|
+
|
|
68
|
+
const visited = new Set();
|
|
69
|
+
const reachableSources = {};
|
|
70
|
+
|
|
71
|
+
function walkSchema(currentPath) {
|
|
72
|
+
if (visited.has(currentPath) || !allSchemaSources[currentPath]) return;
|
|
73
|
+
visited.add(currentPath);
|
|
74
|
+
|
|
75
|
+
const schema = allSchemaSources[currentPath];
|
|
76
|
+
reachableSources[currentPath] = schema;
|
|
77
|
+
|
|
78
|
+
function walkNode(node) {
|
|
79
|
+
if (Array.isArray(node)) {
|
|
80
|
+
node.forEach(walkNode);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (!isPlainObject(node)) return;
|
|
85
|
+
|
|
86
|
+
if (typeof node.$ref === 'string') {
|
|
87
|
+
const resolvedRefPath = resolveLocalSchemaRef(currentPath, node.$ref);
|
|
88
|
+
if (resolvedRefPath) {
|
|
89
|
+
walkSchema(resolvedRefPath);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
Object.values(node).forEach(walkNode);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
walkNode(schema);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
walkSchema(sourcePath);
|
|
100
|
+
return reachableSources;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function collectLeafEventNames(schema, filePath, eventNames) {
|
|
104
|
+
if (!schema.oneOf) {
|
|
105
|
+
eventNames.push(path.basename(filePath, '.json'));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const processed = await processOneOfSchema(schema, filePath);
|
|
110
|
+
for (const { slug, schema: processedSchema, sourceFilePath } of processed) {
|
|
111
|
+
if (processedSchema.oneOf) {
|
|
112
|
+
await collectLeafEventNames(
|
|
113
|
+
processedSchema,
|
|
114
|
+
sourceFilePath || filePath,
|
|
115
|
+
eventNames,
|
|
116
|
+
);
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
eventNames.push(slug);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function getPartialNameConflicts(schemas) {
|
|
124
|
+
const eventNames = [];
|
|
125
|
+
|
|
126
|
+
for (const { fileName, filePath, schema } of schemas) {
|
|
127
|
+
if (schema.oneOf) {
|
|
128
|
+
await collectLeafEventNames(schema, filePath, eventNames);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
eventNames.push(fileName.replace('.json', ''));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const counts = new Map();
|
|
135
|
+
eventNames.forEach((name) => counts.set(name, (counts.get(name) || 0) + 1));
|
|
136
|
+
return new Set(
|
|
137
|
+
[...counts.entries()]
|
|
138
|
+
.filter(([, count]) => count > 1)
|
|
139
|
+
.map(([name]) => name),
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
24
143
|
async function generateAndWriteDoc(
|
|
25
144
|
filePath,
|
|
26
145
|
schema,
|
|
@@ -29,27 +148,39 @@ async function generateAndWriteDoc(
|
|
|
29
148
|
options,
|
|
30
149
|
alreadyMergedSchema = null,
|
|
31
150
|
editFilePath = null,
|
|
151
|
+
partialNameConflicts = new Set(),
|
|
152
|
+
schemaSources = {},
|
|
153
|
+
schemaDir,
|
|
32
154
|
) {
|
|
33
155
|
const { organizationName, projectName, siteDir, dataLayerName, version } =
|
|
34
156
|
options;
|
|
35
157
|
|
|
36
158
|
const { outputDir: versionOutputDir } = getPathsForVersion(version, siteDir);
|
|
37
159
|
const PARTIALS_DIR = path.join(versionOutputDir, 'partials');
|
|
38
|
-
const
|
|
160
|
+
const docRelativeDir = path.relative(versionOutputDir, outputDir);
|
|
161
|
+
const scopedPartialsDir =
|
|
162
|
+
!docRelativeDir || docRelativeDir === '.'
|
|
163
|
+
? PARTIALS_DIR
|
|
164
|
+
: path.join(PARTIALS_DIR, docRelativeDir);
|
|
165
|
+
const allowBasenameFallback = !partialNameConflicts.has(eventName);
|
|
39
166
|
|
|
40
167
|
const mergedSchema = alreadyMergedSchema || (await processSchema(filePath));
|
|
41
168
|
|
|
42
|
-
//
|
|
43
|
-
const top = resolvePartial(
|
|
44
|
-
path.join(
|
|
45
|
-
|
|
46
|
-
'TopPartial',
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
169
|
+
// Resolve scoped partials first; basename fallback is disabled for ambiguous names.
|
|
170
|
+
const top = resolvePartial({
|
|
171
|
+
scopedPartialPath: path.join(scopedPartialsDir, `_${eventName}.mdx`),
|
|
172
|
+
fallbackPartialPath: path.join(PARTIALS_DIR, `_${eventName}.mdx`),
|
|
173
|
+
componentPrefix: 'TopPartial',
|
|
174
|
+
siteDir,
|
|
175
|
+
allowFallback: allowBasenameFallback,
|
|
176
|
+
});
|
|
177
|
+
const bottom = resolvePartial({
|
|
178
|
+
scopedPartialPath: path.join(scopedPartialsDir, `_${eventName}_bottom.mdx`),
|
|
179
|
+
fallbackPartialPath: path.join(PARTIALS_DIR, `_${eventName}_bottom.mdx`),
|
|
180
|
+
componentPrefix: 'BottomPartial',
|
|
181
|
+
siteDir,
|
|
182
|
+
allowFallback: allowBasenameFallback,
|
|
183
|
+
});
|
|
53
184
|
|
|
54
185
|
const editUrl = buildEditUrl(
|
|
55
186
|
organizationName,
|
|
@@ -68,6 +199,11 @@ async function generateAndWriteDoc(
|
|
|
68
199
|
topPartialComponent: top.component,
|
|
69
200
|
bottomPartialComponent: bottom.component,
|
|
70
201
|
dataLayerName,
|
|
202
|
+
sourcePath: toSchemaSourceKey(schemaDir, editFilePath || filePath),
|
|
203
|
+
schemaSources: collectReachableSchemaSources(
|
|
204
|
+
toSchemaSourceKey(schemaDir, editFilePath || filePath),
|
|
205
|
+
schemaSources,
|
|
206
|
+
),
|
|
71
207
|
});
|
|
72
208
|
|
|
73
209
|
const outputFilename = path.basename(filePath).replace('.json', '.mdx');
|
|
@@ -80,6 +216,9 @@ async function generateOneOfDocs(
|
|
|
80
216
|
filePath,
|
|
81
217
|
outputDir,
|
|
82
218
|
options,
|
|
219
|
+
partialNameConflicts,
|
|
220
|
+
schemaSources,
|
|
221
|
+
schemaDir,
|
|
83
222
|
) {
|
|
84
223
|
const { organizationName, projectName, siteDir } = options;
|
|
85
224
|
const editUrl = buildEditUrl(
|
|
@@ -98,6 +237,11 @@ async function generateOneOfDocs(
|
|
|
98
237
|
schema,
|
|
99
238
|
processedOptions: processed,
|
|
100
239
|
editUrl,
|
|
240
|
+
sourcePath: toSchemaSourceKey(schemaDir, filePath),
|
|
241
|
+
schemaSources: collectReachableSchemaSources(
|
|
242
|
+
toSchemaSourceKey(schemaDir, filePath),
|
|
243
|
+
schemaSources,
|
|
244
|
+
),
|
|
101
245
|
});
|
|
102
246
|
writeDoc(eventOutputDir, 'index.mdx', indexPageContent);
|
|
103
247
|
|
|
@@ -115,6 +259,9 @@ async function generateOneOfDocs(
|
|
|
115
259
|
sourceFilePath || filePath,
|
|
116
260
|
eventOutputDir,
|
|
117
261
|
options,
|
|
262
|
+
partialNameConflicts,
|
|
263
|
+
schemaSources,
|
|
264
|
+
schemaDir,
|
|
118
265
|
);
|
|
119
266
|
} else {
|
|
120
267
|
await generateAndWriteDoc(
|
|
@@ -125,6 +272,9 @@ async function generateOneOfDocs(
|
|
|
125
272
|
options,
|
|
126
273
|
processedSchema,
|
|
127
274
|
sourceFilePath || filePath,
|
|
275
|
+
partialNameConflicts,
|
|
276
|
+
schemaSources,
|
|
277
|
+
schemaDir,
|
|
128
278
|
);
|
|
129
279
|
}
|
|
130
280
|
}
|
|
@@ -136,6 +286,8 @@ export default async function generateEventDocs(options) {
|
|
|
136
286
|
|
|
137
287
|
createDir(outputDir);
|
|
138
288
|
const schemas = readSchemas(schemaDir);
|
|
289
|
+
const schemaSources = readSchemaSources(schemaDir);
|
|
290
|
+
const partialNameConflicts = await getPartialNameConflicts(schemas);
|
|
139
291
|
|
|
140
292
|
console.log(`🚀 Generating documentation for ${schemas.length} schemas...`);
|
|
141
293
|
|
|
@@ -152,7 +304,16 @@ export default async function generateEventDocs(options) {
|
|
|
152
304
|
}
|
|
153
305
|
|
|
154
306
|
if (schema.oneOf) {
|
|
155
|
-
await generateOneOfDocs(
|
|
307
|
+
await generateOneOfDocs(
|
|
308
|
+
eventName,
|
|
309
|
+
schema,
|
|
310
|
+
filePath,
|
|
311
|
+
outputDir,
|
|
312
|
+
options,
|
|
313
|
+
partialNameConflicts,
|
|
314
|
+
schemaSources,
|
|
315
|
+
schemaDir,
|
|
316
|
+
);
|
|
156
317
|
} else {
|
|
157
318
|
await generateAndWriteDoc(
|
|
158
319
|
filePath,
|
|
@@ -160,6 +321,11 @@ export default async function generateEventDocs(options) {
|
|
|
160
321
|
eventName,
|
|
161
322
|
outputDir,
|
|
162
323
|
options,
|
|
324
|
+
null,
|
|
325
|
+
null,
|
|
326
|
+
partialNameConflicts,
|
|
327
|
+
schemaSources,
|
|
328
|
+
schemaDir,
|
|
163
329
|
);
|
|
164
330
|
}
|
|
165
331
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getSingleExampleValue } from './example-helper';
|
|
2
|
-
import
|
|
2
|
+
import { mergeSchema } from './mergeSchema.js';
|
|
3
3
|
|
|
4
4
|
const getPrimitivePlaceholder = (type) => {
|
|
5
5
|
switch (type) {
|
|
@@ -26,7 +26,7 @@ const buildExampleFromSchema = (schema) => {
|
|
|
26
26
|
const newSchema = { ...schema };
|
|
27
27
|
const choice = newSchema[choiceType][0];
|
|
28
28
|
delete newSchema[choiceType];
|
|
29
|
-
const merged =
|
|
29
|
+
const merged = mergeSchema({ allOf: [newSchema, choice] });
|
|
30
30
|
return buildExampleFromSchema(merged);
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -37,7 +37,7 @@ const buildExampleFromSchema = (schema) => {
|
|
|
37
37
|
delete newSchema.if;
|
|
38
38
|
delete newSchema.then;
|
|
39
39
|
delete newSchema.else;
|
|
40
|
-
const merged =
|
|
40
|
+
const merged = mergeSchema({ allOf: [newSchema, thenBranch] });
|
|
41
41
|
return buildExampleFromSchema(merged);
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export default function ChoiceIndexTemplate(data) {
|
|
2
|
-
const { schema, processedOptions, editUrl } = data;
|
|
2
|
+
const { schema, processedOptions, editUrl, sourcePath, schemaSources } = data;
|
|
3
3
|
|
|
4
4
|
return `---
|
|
5
5
|
title: ${schema.title}
|
|
@@ -18,6 +18,10 @@ ${processedOptions
|
|
|
18
18
|
.map((option) => `- [${option.schema.title}](./${option.slug})`)
|
|
19
19
|
.join('\n')}
|
|
20
20
|
|
|
21
|
-
<SchemaJsonViewer
|
|
21
|
+
<SchemaJsonViewer
|
|
22
|
+
schema={${JSON.stringify(schema)}}
|
|
23
|
+
sourcePath={${JSON.stringify(sourcePath)}}
|
|
24
|
+
schemaSources={${JSON.stringify(schemaSources)}}
|
|
25
|
+
/>
|
|
22
26
|
`;
|
|
23
27
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
|
|
4
|
+
function getConstraintsPackageRoot() {
|
|
5
|
+
const candidates = [
|
|
6
|
+
path.resolve(process.cwd(), 'packages', 'tracking-target-constraints'),
|
|
7
|
+
path.resolve(
|
|
8
|
+
process.cwd(),
|
|
9
|
+
'..',
|
|
10
|
+
'packages',
|
|
11
|
+
'tracking-target-constraints',
|
|
12
|
+
),
|
|
13
|
+
path.resolve(
|
|
14
|
+
process.cwd(),
|
|
15
|
+
'..',
|
|
16
|
+
'..',
|
|
17
|
+
'packages',
|
|
18
|
+
'tracking-target-constraints',
|
|
19
|
+
),
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
return candidates.find((candidate) => fs.existsSync(candidate));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function stripConstraintsPrefix(value) {
|
|
26
|
+
return value.replace(/^\/?constraints\//, '');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function resolveConstraintSchemaPath(uri) {
|
|
30
|
+
if (!uri || typeof uri !== 'string') return null;
|
|
31
|
+
|
|
32
|
+
const constraintsPackageRoot = getConstraintsPackageRoot();
|
|
33
|
+
if (!constraintsPackageRoot) return null;
|
|
34
|
+
|
|
35
|
+
if (uri.startsWith('http://') || uri.startsWith('https://')) {
|
|
36
|
+
const { pathname } = new URL(uri);
|
|
37
|
+
if (!pathname.startsWith('/constraints/')) return null;
|
|
38
|
+
return path.join(constraintsPackageRoot, stripConstraintsPrefix(pathname));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (uri.startsWith('/constraints/') || uri.startsWith('constraints/')) {
|
|
42
|
+
return path.join(constraintsPackageRoot, stripConstraintsPrefix(uri));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return null;
|
|
46
|
+
}
|
package/helpers/file-system.js
CHANGED
|
@@ -23,6 +23,34 @@ export function readSchemas(directory) {
|
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
export function readSchemaSources(directory) {
|
|
27
|
+
const schemaSources = {};
|
|
28
|
+
|
|
29
|
+
function walk(currentDirectory) {
|
|
30
|
+
const entries = fs.readdirSync(currentDirectory, { withFileTypes: true });
|
|
31
|
+
|
|
32
|
+
entries.forEach((entry) => {
|
|
33
|
+
const entryPath = path.join(currentDirectory, entry.name);
|
|
34
|
+
if (entry.isDirectory()) {
|
|
35
|
+
walk(entryPath);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!entry.name.endsWith('.json')) return;
|
|
40
|
+
const relativePath = path
|
|
41
|
+
.relative(directory, entryPath)
|
|
42
|
+
.split(path.sep)
|
|
43
|
+
.join('/');
|
|
44
|
+
schemaSources[relativePath] = JSON.parse(
|
|
45
|
+
fs.readFileSync(entryPath, 'utf-8'),
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
walk(directory);
|
|
51
|
+
return schemaSources;
|
|
52
|
+
}
|
|
53
|
+
|
|
26
54
|
export function writeDoc(outputDir, fileName, content) {
|
|
27
55
|
fs.writeFileSync(path.join(outputDir, fileName), content);
|
|
28
56
|
console.log(
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import mergeJsonSchema from 'json-schema-merge-allof';
|
|
2
|
+
|
|
3
|
+
const baseResolvers = {
|
|
4
|
+
$defs: mergeJsonSchema.options.resolvers.definitions,
|
|
5
|
+
defaultResolver: mergeJsonSchema.options.resolvers.title,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export function mergeSchema(schema, options = {}) {
|
|
9
|
+
return mergeJsonSchema(schema, {
|
|
10
|
+
...options,
|
|
11
|
+
resolvers: {
|
|
12
|
+
...baseResolvers,
|
|
13
|
+
...(options.resolvers || {}),
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
}
|
package/helpers/processSchema.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import $RefParser from '@apidevtools/json-schema-ref-parser';
|
|
2
|
-
import
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { resolveConstraintSchemaPath } from './constraintSchemaPaths.js';
|
|
4
|
+
import { mergeSchema } from './mergeSchema.js';
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* Processes a JSON schema file by bundling external references,
|
|
@@ -12,6 +14,21 @@ export default async function processSchema(filePath) {
|
|
|
12
14
|
// 1. Bundle all external references into a single, self-contained schema
|
|
13
15
|
const bundledSchema = await $RefParser.bundle(filePath, {
|
|
14
16
|
mutateInputSchema: false,
|
|
17
|
+
resolve: {
|
|
18
|
+
constraints: {
|
|
19
|
+
order: 1,
|
|
20
|
+
canRead: (file) => Boolean(resolveConstraintSchemaPath(file.url)),
|
|
21
|
+
read: (file) => {
|
|
22
|
+
const localPath = resolveConstraintSchemaPath(file.url);
|
|
23
|
+
if (!localPath) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`Could not resolve local path for constraint ref: ${file.url}`,
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
return fs.readFileSync(localPath, 'utf8');
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
15
32
|
});
|
|
16
33
|
|
|
17
34
|
// 2. Dereference the bundled schema to resolve internal refs for allOf merging
|
|
@@ -22,11 +39,7 @@ export default async function processSchema(filePath) {
|
|
|
22
39
|
});
|
|
23
40
|
|
|
24
41
|
// Then merge allOf properties
|
|
25
|
-
const mergedSchema =
|
|
26
|
-
resolvers: {
|
|
27
|
-
defaultResolver: mergeJsonSchema.options.resolvers.title,
|
|
28
|
-
},
|
|
29
|
-
});
|
|
42
|
+
const mergedSchema = mergeSchema(dereferencedSchema);
|
|
30
43
|
|
|
31
44
|
return mergedSchema;
|
|
32
45
|
}
|
|
@@ -9,6 +9,8 @@ export default function MdxTemplate(data) {
|
|
|
9
9
|
topPartialComponent,
|
|
10
10
|
bottomPartialComponent,
|
|
11
11
|
dataLayerName,
|
|
12
|
+
sourcePath,
|
|
13
|
+
schemaSources,
|
|
12
14
|
} = data;
|
|
13
15
|
|
|
14
16
|
return `---
|
|
@@ -33,7 +35,11 @@ ${topPartialComponent}
|
|
|
33
35
|
schema={${JSON.stringify(mergedSchema)}}
|
|
34
36
|
${dataLayerName ? ` dataLayerName={'${dataLayerName}'}` : ''}
|
|
35
37
|
/>
|
|
36
|
-
<SchemaJsonViewer
|
|
38
|
+
<SchemaJsonViewer
|
|
39
|
+
schema={${JSON.stringify(schema)}}
|
|
40
|
+
sourcePath={${JSON.stringify(sourcePath)}}
|
|
41
|
+
schemaSources={${JSON.stringify(schemaSources)}}
|
|
42
|
+
/>
|
|
37
43
|
|
|
38
44
|
${bottomPartialComponent}
|
|
39
45
|
`;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import processSchema from './processSchema.js';
|
|
4
|
-
import
|
|
4
|
+
import { mergeSchema } from './mergeSchema.js';
|
|
5
5
|
|
|
6
6
|
function mergePropertySchemas(baseProperties = {}, optionProperties = {}) {
|
|
7
7
|
const mergedProperties = {
|
|
@@ -14,16 +14,9 @@ function mergePropertySchemas(baseProperties = {}, optionProperties = {}) {
|
|
|
14
14
|
continue;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
mergedProperties[key] =
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
resolvers: {
|
|
23
|
-
defaultResolver: mergeJsonSchema.options.resolvers.title,
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
);
|
|
17
|
+
mergedProperties[key] = mergeSchema({
|
|
18
|
+
allOf: [baseProperties[key], optionProperties[key]],
|
|
19
|
+
});
|
|
27
20
|
}
|
|
28
21
|
|
|
29
22
|
return mergedProperties;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import buildExampleFromSchema from './buildExampleFromSchema';
|
|
2
|
-
import
|
|
2
|
+
import { mergeSchema } from './mergeSchema.js';
|
|
3
3
|
|
|
4
4
|
const findChoicePoints = (subSchema, path = []) => {
|
|
5
5
|
if (!subSchema) {
|
|
@@ -47,7 +47,7 @@ const generateExampleForChoice = (rootSchema, path, option) => {
|
|
|
47
47
|
if (path.length === 0) {
|
|
48
48
|
delete schemaVariant.oneOf;
|
|
49
49
|
delete schemaVariant.anyOf;
|
|
50
|
-
const newSchemaVariant =
|
|
50
|
+
const newSchemaVariant = mergeSchema({
|
|
51
51
|
allOf: [schemaVariant, option],
|
|
52
52
|
});
|
|
53
53
|
return buildExampleFromSchema(newSchemaVariant);
|
|
@@ -112,7 +112,7 @@ const generateConditionalExample = (rootSchema, path, branch) => {
|
|
|
112
112
|
delete schemaVariant.else;
|
|
113
113
|
if (branchSchema) {
|
|
114
114
|
const merged = pruneSiblingConditionalProperties(
|
|
115
|
-
|
|
115
|
+
mergeSchema({ allOf: [schemaVariant, branchSchema] }),
|
|
116
116
|
branchSchema,
|
|
117
117
|
siblingBranchSchema,
|
|
118
118
|
baseRequired,
|
|
@@ -134,7 +134,7 @@ const generateConditionalExample = (rootSchema, path, branch) => {
|
|
|
134
134
|
delete target.else;
|
|
135
135
|
if (branchSchema) {
|
|
136
136
|
const merged = pruneSiblingConditionalProperties(
|
|
137
|
-
|
|
137
|
+
mergeSchema({ allOf: [target, branchSchema] }),
|
|
138
138
|
branchSchema,
|
|
139
139
|
siblingBranchSchema,
|
|
140
140
|
baseRequired,
|