docusaurus-plugin-generate-schema-docs 1.8.3 → 1.8.5
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 +12 -0
- package/__tests__/__fixtures__/validateSchemas/main-schema-with-not-allof.json +11 -0
- package/__tests__/__fixtures__/validateSchemas/schema-with-not-anyof-multi.json +12 -0
- package/__tests__/__fixtures__/validateSchemas/schema-with-not-anyof.json +30 -0
- package/__tests__/__fixtures__/validateSchemas/schema-with-not-edge-cases.json +24 -0
- package/__tests__/__fixtures__/validateSchemas/schema-with-not-non-object.json +15 -0
- package/__tests__/__snapshots__/generateEventDocs.anchor.test.js.snap +6 -0
- package/__tests__/__snapshots__/generateEventDocs.nested.test.js.snap +6 -0
- package/__tests__/__snapshots__/generateEventDocs.test.js.snap +15 -0
- package/__tests__/__snapshots__/generateEventDocs.versioned.test.js.snap +6 -0
- package/__tests__/components/PropertiesTable.test.js +66 -0
- package/__tests__/components/PropertyRow.test.js +85 -4
- package/__tests__/components/SchemaJsonViewer.test.js +118 -0
- package/__tests__/generateEventDocs.anchor.test.js +1 -1
- package/__tests__/generateEventDocs.nested.test.js +1 -1
- package/__tests__/generateEventDocs.partials.test.js +1 -1
- package/__tests__/generateEventDocs.test.js +506 -1
- package/__tests__/generateEventDocs.versioned.test.js +1 -1
- package/__tests__/helpers/buildExampleFromSchema.test.js +240 -0
- package/__tests__/helpers/constraintSchemaPaths.test.js +208 -0
- package/__tests__/helpers/continuingLinesStyle.test.js +492 -0
- package/__tests__/helpers/example-helper.test.js +12 -0
- package/__tests__/helpers/exampleModel.test.js +209 -0
- package/__tests__/helpers/file-system.test.js +73 -1
- package/__tests__/helpers/getConstraints.test.js +43 -0
- package/__tests__/helpers/mergeSchema.test.js +94 -0
- package/__tests__/helpers/processSchema.test.js +309 -1
- package/__tests__/helpers/schema-doc-template.test.js +54 -0
- package/__tests__/helpers/schema-processing.test.js +122 -2
- package/__tests__/helpers/schemaToExamples.test.js +1007 -0
- package/__tests__/helpers/schemaToTableData.mutations.test.js +970 -0
- package/__tests__/helpers/schemaToTableData.test.js +157 -0
- package/__tests__/helpers/schemaTraversal.test.js +110 -0
- package/__tests__/helpers/snippetTargets.test.js +432 -0
- package/__tests__/helpers/trackingTargets.test.js +319 -0
- package/__tests__/helpers/validator.test.js +385 -1
- package/__tests__/index.test.js +436 -0
- package/__tests__/syncGtm.test.js +366 -6
- package/__tests__/update-schema-ids.test.js +70 -1
- package/__tests__/validateSchemas-integration.test.js +2 -2
- package/__tests__/validateSchemas.test.js +192 -1
- package/components/PropertiesTable.js +32 -2
- package/components/PropertyRow.js +29 -2
- package/components/SchemaJsonViewer.js +234 -131
- package/components/SchemaRows.css +40 -0
- package/components/SchemaViewer.js +11 -2
- package/generateEventDocs.js +21 -1
- package/helpers/constraintSchemaPaths.js +10 -14
- package/helpers/example-helper.js +2 -2
- package/helpers/getConstraints.js +20 -0
- package/helpers/processSchema.js +32 -1
- package/helpers/schema-doc-template.js +4 -0
- package/helpers/schemaToExamples.js +29 -35
- package/helpers/schemaToTableData.js +538 -492
- package/helpers/schemaTraversal.cjs +148 -0
- package/helpers/trackingTargets.js +26 -3
- package/helpers/validator.js +18 -4
- package/index.js +1 -2
- package/package.json +1 -1
- package/scripts/sync-gtm.js +65 -34
- package/test-data/payloadContracts.js +35 -0
- package/validateSchemas.js +1 -1
|
@@ -1,14 +1,43 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
2
|
import Link from '@docusaurus/Link';
|
|
3
|
+
import { usePrismTheme } from '@docusaurus/theme-common';
|
|
4
|
+
import { Highlight } from 'prism-react-renderer';
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
const SCHEMA_META_KEYS = [
|
|
7
|
+
'$schema',
|
|
8
|
+
'$id',
|
|
9
|
+
'$anchor',
|
|
10
|
+
'$dynamicAnchor',
|
|
11
|
+
'$comment',
|
|
12
|
+
'$vocabulary',
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const SCHEMA_STRUCTURAL_KEYS = new Set([
|
|
16
|
+
'$ref',
|
|
17
|
+
'$defs',
|
|
18
|
+
'properties',
|
|
19
|
+
'required',
|
|
20
|
+
'allOf',
|
|
21
|
+
'anyOf',
|
|
22
|
+
'oneOf',
|
|
23
|
+
'if',
|
|
24
|
+
'then',
|
|
25
|
+
'else',
|
|
26
|
+
'not',
|
|
27
|
+
'items',
|
|
28
|
+
'prefixItems',
|
|
29
|
+
'contains',
|
|
30
|
+
'dependentSchemas',
|
|
31
|
+
'patternProperties',
|
|
32
|
+
'additionalProperties',
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
const SCHEMA_NAME_MAP_KEYS = new Set([
|
|
36
|
+
'properties',
|
|
37
|
+
'patternProperties',
|
|
38
|
+
'$defs',
|
|
39
|
+
'dependentSchemas',
|
|
40
|
+
]);
|
|
12
41
|
|
|
13
42
|
function isExternalRef(value) {
|
|
14
43
|
return typeof value === 'string' && /^https?:\/\//.test(value);
|
|
@@ -51,137 +80,189 @@ function resolveLocalRef(currentPath, refValue) {
|
|
|
51
80
|
return normalizePathSegments(`${dirname(currentPath)}/${refValue}`);
|
|
52
81
|
}
|
|
53
82
|
|
|
54
|
-
function
|
|
55
|
-
|
|
83
|
+
function getSchemaKeywordClassName(key, parentKey) {
|
|
84
|
+
if (parentKey && SCHEMA_NAME_MAP_KEYS.has(parentKey)) {
|
|
85
|
+
return '';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (SCHEMA_META_KEYS.includes(key)) {
|
|
89
|
+
return 'schema-json-viewer__keyword schema-json-viewer__keyword--meta';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (SCHEMA_STRUCTURAL_KEYS.has(key)) {
|
|
93
|
+
return 'schema-json-viewer__keyword schema-json-viewer__keyword--structural';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return '';
|
|
56
97
|
}
|
|
57
98
|
|
|
58
|
-
function
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
99
|
+
function joinClassNames(...classNames) {
|
|
100
|
+
return classNames.filter(Boolean).join(' ');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function createParserState() {
|
|
104
|
+
return {
|
|
105
|
+
stack: [],
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function beginNestedValue(state, tokenContent) {
|
|
110
|
+
const currentContext = state.stack[state.stack.length - 1];
|
|
111
|
+
let parentKey = null;
|
|
112
|
+
|
|
113
|
+
if (currentContext?.type === 'object' && currentContext.afterColon) {
|
|
114
|
+
parentKey = currentContext.currentKey;
|
|
115
|
+
currentContext.currentKey = null;
|
|
116
|
+
currentContext.afterColon = false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
state.stack.push({
|
|
120
|
+
type: tokenContent === '{' ? 'object' : 'array',
|
|
121
|
+
parentKey,
|
|
122
|
+
currentKey: null,
|
|
123
|
+
afterColon: false,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function classifyRenderedToken(state, token) {
|
|
128
|
+
const currentContext = state.stack[state.stack.length - 1];
|
|
129
|
+
const tokenTypes = new Set(token.types);
|
|
130
|
+
const content = token.content;
|
|
131
|
+
const semantic = {};
|
|
132
|
+
|
|
133
|
+
if (!content) {
|
|
134
|
+
return semantic;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (tokenTypes.has('property')) {
|
|
138
|
+
const key = JSON.parse(content);
|
|
139
|
+
semantic.propertyKey = key;
|
|
140
|
+
semantic.parentKey = currentContext?.parentKey ?? null;
|
|
141
|
+
|
|
142
|
+
if (currentContext?.type === 'object') {
|
|
143
|
+
currentContext.currentKey = key;
|
|
144
|
+
currentContext.afterColon = false;
|
|
95
145
|
}
|
|
96
146
|
|
|
97
|
-
return
|
|
147
|
+
return semantic;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (content === ':') {
|
|
151
|
+
if (
|
|
152
|
+
currentContext?.type === 'object' &&
|
|
153
|
+
currentContext.currentKey !== null
|
|
154
|
+
) {
|
|
155
|
+
currentContext.afterColon = true;
|
|
156
|
+
}
|
|
157
|
+
return semantic;
|
|
98
158
|
}
|
|
99
159
|
|
|
100
|
-
if (
|
|
101
|
-
|
|
160
|
+
if (content === '{' || content === '[') {
|
|
161
|
+
beginNestedValue(state, content);
|
|
162
|
+
return semantic;
|
|
102
163
|
}
|
|
103
164
|
|
|
104
|
-
if (
|
|
105
|
-
|
|
165
|
+
if (content === '}' || content === ']') {
|
|
166
|
+
state.stack.pop();
|
|
167
|
+
return semantic;
|
|
106
168
|
}
|
|
107
169
|
|
|
108
|
-
|
|
170
|
+
if (content === ',') {
|
|
171
|
+
if (currentContext?.type === 'object') {
|
|
172
|
+
currentContext.currentKey = null;
|
|
173
|
+
currentContext.afterColon = false;
|
|
174
|
+
}
|
|
175
|
+
return semantic;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (currentContext?.type === 'object' && currentContext.afterColon) {
|
|
179
|
+
if (tokenTypes.has('string') && content.trim().startsWith('"')) {
|
|
180
|
+
semantic.valueKey = currentContext.currentKey;
|
|
181
|
+
semantic.stringValue = JSON.parse(content);
|
|
182
|
+
currentContext.currentKey = null;
|
|
183
|
+
currentContext.afterColon = false;
|
|
184
|
+
return semantic;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (
|
|
188
|
+
tokenTypes.has('number') ||
|
|
189
|
+
tokenTypes.has('boolean') ||
|
|
190
|
+
(tokenTypes.has('keyword') && content === 'null')
|
|
191
|
+
) {
|
|
192
|
+
currentContext.currentKey = null;
|
|
193
|
+
currentContext.afterColon = false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return semantic;
|
|
109
198
|
}
|
|
110
199
|
|
|
111
|
-
function
|
|
112
|
-
|
|
113
|
-
|
|
200
|
+
function renderToken({
|
|
201
|
+
token,
|
|
202
|
+
tokenIndex,
|
|
203
|
+
getTokenProps,
|
|
204
|
+
semantic,
|
|
114
205
|
currentPath,
|
|
115
206
|
schemaSources,
|
|
116
207
|
onNavigate,
|
|
117
|
-
propertyKey = null,
|
|
118
208
|
}) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
209
|
+
const tokenProps = getTokenProps({ token, key: tokenIndex });
|
|
210
|
+
const propertyKeyClassName = semantic.propertyKey
|
|
211
|
+
? getSchemaKeywordClassName(semantic.propertyKey, semantic.parentKey)
|
|
212
|
+
: '';
|
|
213
|
+
const className = joinClassNames(tokenProps.className, propertyKeyClassName);
|
|
214
|
+
|
|
215
|
+
if (
|
|
216
|
+
semantic.valueKey === '$ref' &&
|
|
217
|
+
typeof semantic.stringValue === 'string'
|
|
218
|
+
) {
|
|
219
|
+
if (isExternalRef(semantic.stringValue)) {
|
|
220
|
+
return (
|
|
221
|
+
<Link
|
|
222
|
+
key={tokenIndex}
|
|
223
|
+
className={joinClassNames(
|
|
224
|
+
className,
|
|
225
|
+
'schema-json-viewer__link',
|
|
226
|
+
'schema-json-viewer__ref-link',
|
|
227
|
+
)}
|
|
228
|
+
style={tokenProps.style}
|
|
229
|
+
href={semantic.stringValue}
|
|
230
|
+
target="_blank"
|
|
231
|
+
rel="noreferrer"
|
|
232
|
+
>
|
|
233
|
+
{token.content}
|
|
234
|
+
</Link>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
145
237
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
/>
|
|
165
|
-
{index < entries.length - 1 && (
|
|
166
|
-
<span className="token punctuation">,</span>
|
|
167
|
-
)}
|
|
168
|
-
<br />
|
|
169
|
-
</Fragment>
|
|
170
|
-
))}
|
|
171
|
-
{entries.length > 0 && <JsonIndent depth={depth} />}
|
|
172
|
-
<span className="token punctuation">{'}'}</span>
|
|
173
|
-
</>
|
|
174
|
-
);
|
|
238
|
+
const resolvedRef = resolveLocalRef(currentPath, semantic.stringValue);
|
|
239
|
+
if (resolvedRef && schemaSources?.[resolvedRef]) {
|
|
240
|
+
return (
|
|
241
|
+
<button
|
|
242
|
+
key={tokenIndex}
|
|
243
|
+
type="button"
|
|
244
|
+
className={joinClassNames(
|
|
245
|
+
className,
|
|
246
|
+
'schema-json-viewer__link',
|
|
247
|
+
'schema-json-viewer__ref-link',
|
|
248
|
+
)}
|
|
249
|
+
style={tokenProps.style}
|
|
250
|
+
onClick={() => onNavigate(resolvedRef)}
|
|
251
|
+
>
|
|
252
|
+
{token.content}
|
|
253
|
+
</button>
|
|
254
|
+
);
|
|
255
|
+
}
|
|
175
256
|
}
|
|
176
257
|
|
|
177
258
|
return (
|
|
178
|
-
<
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
259
|
+
<span
|
|
260
|
+
key={tokenIndex}
|
|
261
|
+
className={className || tokenProps.className}
|
|
262
|
+
style={tokenProps.style}
|
|
263
|
+
>
|
|
264
|
+
{token.content}
|
|
265
|
+
</span>
|
|
185
266
|
);
|
|
186
267
|
}
|
|
187
268
|
|
|
@@ -190,6 +271,7 @@ export default function SchemaJsonViewer({
|
|
|
190
271
|
sourcePath = null,
|
|
191
272
|
schemaSources = null,
|
|
192
273
|
}) {
|
|
274
|
+
const prismTheme = usePrismTheme();
|
|
193
275
|
const resolvedSchemaSources =
|
|
194
276
|
schemaSources || (sourcePath ? { [sourcePath]: schema } : {});
|
|
195
277
|
const rootPath = sourcePath;
|
|
@@ -197,6 +279,7 @@ export default function SchemaJsonViewer({
|
|
|
197
279
|
|
|
198
280
|
const currentSchema =
|
|
199
281
|
(currentPath && resolvedSchemaSources?.[currentPath]) || schema;
|
|
282
|
+
const formattedSchema = JSON.stringify(currentSchema, null, 2);
|
|
200
283
|
|
|
201
284
|
return (
|
|
202
285
|
<details className="schema-json-viewer">
|
|
@@ -212,17 +295,37 @@ export default function SchemaJsonViewer({
|
|
|
212
295
|
</button>
|
|
213
296
|
</div>
|
|
214
297
|
) : null}
|
|
215
|
-
<
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
298
|
+
<Highlight code={formattedSchema} language="json" theme={prismTheme}>
|
|
299
|
+
{({ className, style, tokens, getLineProps, getTokenProps }) => {
|
|
300
|
+
const parserState = createParserState();
|
|
301
|
+
|
|
302
|
+
return (
|
|
303
|
+
<pre className={className} style={style} data-language="json">
|
|
304
|
+
<code className="language-json">
|
|
305
|
+
{tokens.map((line, lineIndex) => (
|
|
306
|
+
<span
|
|
307
|
+
key={lineIndex}
|
|
308
|
+
{...getLineProps({ line, key: lineIndex })}
|
|
309
|
+
>
|
|
310
|
+
{line.map((token, tokenIndex) =>
|
|
311
|
+
renderToken({
|
|
312
|
+
token,
|
|
313
|
+
tokenIndex,
|
|
314
|
+
getTokenProps,
|
|
315
|
+
semantic: classifyRenderedToken(parserState, token),
|
|
316
|
+
currentPath,
|
|
317
|
+
schemaSources: resolvedSchemaSources,
|
|
318
|
+
onNavigate: setCurrentPath,
|
|
319
|
+
}),
|
|
320
|
+
)}
|
|
321
|
+
{'\n'}
|
|
322
|
+
</span>
|
|
323
|
+
))}
|
|
324
|
+
</code>
|
|
325
|
+
</pre>
|
|
326
|
+
);
|
|
327
|
+
}}
|
|
328
|
+
</Highlight>
|
|
226
329
|
</details>
|
|
227
330
|
);
|
|
228
331
|
}
|
|
@@ -46,6 +46,29 @@
|
|
|
46
46
|
text-decoration: underline;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
.schema-json-viewer__ref-link {
|
|
50
|
+
text-decoration: underline;
|
|
51
|
+
text-decoration-thickness: 1.5px;
|
|
52
|
+
text-underline-offset: 0.14em;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.schema-json-viewer__ref-link:hover {
|
|
56
|
+
color: var(--ifm-link-hover-color) !important;
|
|
57
|
+
text-decoration-thickness: 2px;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.schema-json-viewer__keyword {
|
|
61
|
+
font-weight: 600;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.schema-json-viewer__keyword--meta {
|
|
65
|
+
color: var(--ifm-color-info-light);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.schema-json-viewer__keyword--structural {
|
|
69
|
+
color: var(--ifm-color-success-light);
|
|
70
|
+
}
|
|
71
|
+
|
|
49
72
|
/* --- Property Name and Container Symbol Styles --- */
|
|
50
73
|
|
|
51
74
|
.property-name {
|
|
@@ -62,6 +85,8 @@
|
|
|
62
85
|
position: relative;
|
|
63
86
|
display: inline-flex;
|
|
64
87
|
align-items: center;
|
|
88
|
+
flex-wrap: wrap;
|
|
89
|
+
gap: 0.35rem;
|
|
65
90
|
}
|
|
66
91
|
|
|
67
92
|
.property-keyword-stack {
|
|
@@ -76,6 +101,21 @@
|
|
|
76
101
|
font-weight: 600;
|
|
77
102
|
}
|
|
78
103
|
|
|
104
|
+
.property-keyword-badge {
|
|
105
|
+
display: inline-flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
padding: 0.1rem 0.4rem;
|
|
108
|
+
border-radius: 999px;
|
|
109
|
+
border: 1px solid var(--ifm-table-border-color);
|
|
110
|
+
background-color: var(--ifm-color-emphasis-100);
|
|
111
|
+
color: var(--ifm-color-emphasis-800);
|
|
112
|
+
font-size: 0.68rem;
|
|
113
|
+
font-weight: 700;
|
|
114
|
+
letter-spacing: 0.02em;
|
|
115
|
+
text-transform: uppercase;
|
|
116
|
+
white-space: nowrap;
|
|
117
|
+
}
|
|
118
|
+
|
|
79
119
|
.property-keyword-pattern {
|
|
80
120
|
font-size: 0.85em;
|
|
81
121
|
color: var(--ifm-color-emphasis-700);
|
|
@@ -3,7 +3,16 @@ import Heading from '@theme/Heading';
|
|
|
3
3
|
import ExampleDataLayer from './ExampleDataLayer';
|
|
4
4
|
import PropertiesTable from './PropertiesTable';
|
|
5
5
|
|
|
6
|
-
export default function SchemaViewer({
|
|
6
|
+
export default function SchemaViewer({
|
|
7
|
+
schema,
|
|
8
|
+
sourceSchema,
|
|
9
|
+
sourcePath,
|
|
10
|
+
schemaSources,
|
|
11
|
+
dataLayerName,
|
|
12
|
+
}) {
|
|
13
|
+
const resolvedSourceSchema =
|
|
14
|
+
(sourcePath && schemaSources?.[sourcePath]) || sourceSchema || schema;
|
|
15
|
+
|
|
7
16
|
const hasOneOfAnyOf =
|
|
8
17
|
schema.oneOf ||
|
|
9
18
|
schema.anyOf ||
|
|
@@ -21,7 +30,7 @@ export default function SchemaViewer({ schema, dataLayerName }) {
|
|
|
21
30
|
<ExampleDataLayer schema={schema} dataLayerName={dataLayerName} />
|
|
22
31
|
|
|
23
32
|
<Heading as="h2">Event Properties</Heading>
|
|
24
|
-
<PropertiesTable schema={schema} />
|
|
33
|
+
<PropertiesTable schema={schema} sourceSchema={resolvedSourceSchema} />
|
|
25
34
|
</div>
|
|
26
35
|
);
|
|
27
36
|
}
|
package/generateEventDocs.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
writeDoc,
|
|
8
8
|
createDir,
|
|
9
9
|
} from './helpers/file-system.js';
|
|
10
|
-
import { processOneOfSchema
|
|
10
|
+
import { processOneOfSchema } from './helpers/schema-processing.js';
|
|
11
11
|
import SchemaDocTemplate from './helpers/schema-doc-template.js';
|
|
12
12
|
import ChoiceIndexTemplate from './helpers/choice-index-template.js';
|
|
13
13
|
import processSchema from './helpers/processSchema.js';
|
|
@@ -233,6 +233,26 @@ async function generateOneOfDocs(
|
|
|
233
233
|
|
|
234
234
|
const processed = await processOneOfSchema(schema, filePath);
|
|
235
235
|
|
|
236
|
+
// Remove stale files/dirs from previous runs that are no longer in the schema
|
|
237
|
+
const expectedNames = new Set(['index.mdx']);
|
|
238
|
+
for (const [
|
|
239
|
+
index,
|
|
240
|
+
{ slug, schema: processedSchema },
|
|
241
|
+
] of processed.entries()) {
|
|
242
|
+
const prefixedSlug = `${(index + 1).toString().padStart(2, '0')}-${slug}`;
|
|
243
|
+
expectedNames.add(
|
|
244
|
+
processedSchema.oneOf ? prefixedSlug : `${prefixedSlug}.mdx`,
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
for (const entry of fs.readdirSync(eventOutputDir, { withFileTypes: true })) {
|
|
248
|
+
if (!expectedNames.has(entry.name)) {
|
|
249
|
+
const fullPath = path.join(eventOutputDir, entry.name);
|
|
250
|
+
entry.isDirectory()
|
|
251
|
+
? fs.rmSync(fullPath, { recursive: true })
|
|
252
|
+
: fs.unlinkSync(fullPath);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
236
256
|
const indexPageContent = ChoiceIndexTemplate({
|
|
237
257
|
schema,
|
|
238
258
|
processedOptions: processed,
|
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
|
|
4
|
+
function buildCandidatePaths(baseSegments, packageName) {
|
|
5
|
+
return [
|
|
6
|
+
path.resolve(process.cwd(), ...baseSegments, packageName),
|
|
7
|
+
path.resolve(process.cwd(), '..', ...baseSegments, packageName),
|
|
8
|
+
path.resolve(process.cwd(), '..', '..', ...baseSegments, packageName),
|
|
9
|
+
];
|
|
10
|
+
}
|
|
11
|
+
|
|
4
12
|
function getConstraintsPackageRoot() {
|
|
5
13
|
const candidates = [
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
),
|
|
14
|
+
...buildCandidatePaths(['packages'], 'tracking-target-constraints'),
|
|
15
|
+
...buildCandidatePaths(['node_modules'], 'tracking-target-constraints'),
|
|
20
16
|
];
|
|
21
17
|
|
|
22
18
|
return candidates.find((candidate) => fs.existsSync(candidate));
|
|
@@ -5,7 +5,7 @@ export function getSingleExampleValue(propSchema) {
|
|
|
5
5
|
if (propSchema.examples?.length > 0) {
|
|
6
6
|
return propSchema.examples[0];
|
|
7
7
|
}
|
|
8
|
-
if (propSchema
|
|
8
|
+
if (Object.prototype.hasOwnProperty.call(propSchema, 'example')) {
|
|
9
9
|
return propSchema.example;
|
|
10
10
|
}
|
|
11
11
|
if (Object.prototype.hasOwnProperty.call(propSchema, 'default')) {
|
|
@@ -25,7 +25,7 @@ export function getExamples(propSchema) {
|
|
|
25
25
|
examples.push(...propSchema.examples);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
if (propSchema
|
|
28
|
+
if (Object.prototype.hasOwnProperty.call(propSchema, 'example')) {
|
|
29
29
|
if (!examples.includes(propSchema.example)) {
|
|
30
30
|
examples.push(propSchema.example);
|
|
31
31
|
}
|
|
@@ -1,4 +1,23 @@
|
|
|
1
1
|
// A list of JSON Schema keywords that have simple key-value constraints.
|
|
2
|
+
function formatInlineConstraintValue(value) {
|
|
3
|
+
if (Array.isArray(value)) {
|
|
4
|
+
return `[${value.map((item) => formatInlineConstraintValue(item)).join(', ')}]`;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
if (value && typeof value === 'object') {
|
|
8
|
+
const entries = Object.entries(value).map(
|
|
9
|
+
([key, nested]) => `${key}: ${formatInlineConstraintValue(nested)}`,
|
|
10
|
+
);
|
|
11
|
+
return `{ ${entries.join(', ')} }`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return JSON.stringify(value);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function formatNotConstraint(val) {
|
|
18
|
+
return `not: ${formatInlineConstraintValue(val)}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
2
21
|
const constraintHandlers = {
|
|
3
22
|
// Simple key-value constraints
|
|
4
23
|
minLength: (val) => `minLength: ${val}`,
|
|
@@ -32,6 +51,7 @@ const constraintHandlers = {
|
|
|
32
51
|
contains: (val) => `contains: ${JSON.stringify(val)}`,
|
|
33
52
|
enum: (val) => `enum: [${val.join(', ')}]`,
|
|
34
53
|
const: (val) => `const: ${JSON.stringify(val)}`,
|
|
54
|
+
not: (val) => formatNotConstraint(val),
|
|
35
55
|
};
|
|
36
56
|
|
|
37
57
|
export const getConstraints = (prop, isReq) => {
|
package/helpers/processSchema.js
CHANGED
|
@@ -3,6 +3,37 @@ import fs from 'fs';
|
|
|
3
3
|
import { resolveConstraintSchemaPath } from './constraintSchemaPaths.js';
|
|
4
4
|
import { mergeSchema } from './mergeSchema.js';
|
|
5
5
|
|
|
6
|
+
function unwrapRedundantNotAnyOf(node) {
|
|
7
|
+
if (!node || typeof node !== 'object') {
|
|
8
|
+
return node;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (Array.isArray(node)) {
|
|
12
|
+
return node.map(unwrapRedundantNotAnyOf);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const normalized = {};
|
|
16
|
+
for (const [key, value] of Object.entries(node)) {
|
|
17
|
+
normalized[key] = unwrapRedundantNotAnyOf(value);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (normalized.not && typeof normalized.not === 'object') {
|
|
21
|
+
let candidate = normalized.not;
|
|
22
|
+
while (
|
|
23
|
+
candidate &&
|
|
24
|
+
typeof candidate === 'object' &&
|
|
25
|
+
!Array.isArray(candidate) &&
|
|
26
|
+
Array.isArray(candidate.anyOf) &&
|
|
27
|
+
candidate.anyOf.length === 1
|
|
28
|
+
) {
|
|
29
|
+
candidate = candidate.anyOf[0];
|
|
30
|
+
}
|
|
31
|
+
normalized.not = candidate;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return normalized;
|
|
35
|
+
}
|
|
36
|
+
|
|
6
37
|
/**
|
|
7
38
|
* Processes a JSON schema file by bundling external references,
|
|
8
39
|
* dereferencing internal references, and merging allOf properties.
|
|
@@ -41,5 +72,5 @@ export default async function processSchema(filePath) {
|
|
|
41
72
|
// Then merge allOf properties
|
|
42
73
|
const mergedSchema = mergeSchema(dereferencedSchema);
|
|
43
74
|
|
|
44
|
-
return mergedSchema;
|
|
75
|
+
return unwrapRedundantNotAnyOf(mergedSchema);
|
|
45
76
|
}
|