docusaurus-plugin-generate-schema-docs 1.8.4 → 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 +10 -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__/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/exampleModel.test.js +209 -0
- package/__tests__/helpers/file-system.test.js +73 -1
- package/__tests__/helpers/getConstraints.test.js +27 -0
- package/__tests__/helpers/mergeSchema.test.js +94 -0
- package/__tests__/helpers/processSchema.test.js +291 -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/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 +139 -3
- package/__tests__/update-schema-ids.test.js +70 -1
- package/__tests__/validateSchemas-integration.test.js +2 -2
- package/__tests__/validateSchemas.test.js +142 -1
- package/generateEventDocs.js +21 -1
- package/helpers/constraintSchemaPaths.js +10 -14
- package/helpers/schemaToTableData.js +538 -492
- 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 +25 -7
|
@@ -132,4 +132,213 @@ describe('buildExampleModel', () => {
|
|
|
132
132
|
'android-firebase-kotlin-sdk',
|
|
133
133
|
]);
|
|
134
134
|
});
|
|
135
|
+
|
|
136
|
+
it('falls back to default target when x-tracking-targets is null (optional chain)', () => {
|
|
137
|
+
const schema = {
|
|
138
|
+
'x-tracking-targets': null,
|
|
139
|
+
type: 'object',
|
|
140
|
+
properties: {
|
|
141
|
+
event: { type: 'string', examples: ['test_event'] },
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const targets = resolveExampleTargets(schema);
|
|
146
|
+
expect(targets.map((t) => t.id)).toEqual([DEFAULT_SNIPPET_TARGET_ID]);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('falls back to default target when x-tracking-targets is an empty array', () => {
|
|
150
|
+
const schema = {
|
|
151
|
+
'x-tracking-targets': [],
|
|
152
|
+
type: 'object',
|
|
153
|
+
properties: {
|
|
154
|
+
event: { type: 'string', examples: ['test_event'] },
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const targets = resolveExampleTargets(schema);
|
|
159
|
+
expect(targets.map((t) => t.id)).toEqual([DEFAULT_SNIPPET_TARGET_ID]);
|
|
160
|
+
expect(targets).toHaveLength(1);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('filters out null targets and falls back to default when all target IDs are invalid', () => {
|
|
164
|
+
const schema = {
|
|
165
|
+
'x-tracking-targets': ['nonexistent-target-id'],
|
|
166
|
+
type: 'object',
|
|
167
|
+
properties: {
|
|
168
|
+
event: { type: 'string', examples: ['test_event'] },
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// All invalid IDs should be caught, filtered out, then fall back to default
|
|
173
|
+
const targets = resolveExampleTargets(schema);
|
|
174
|
+
expect(targets.map((t) => t.id)).toEqual([DEFAULT_SNIPPET_TARGET_ID]);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('filters out null when one target ID is invalid but keeps valid ones', () => {
|
|
178
|
+
const schema = {
|
|
179
|
+
'x-tracking-targets': [
|
|
180
|
+
'web-datalayer-js',
|
|
181
|
+
'nonexistent-target-id',
|
|
182
|
+
'android-firebase-kotlin-sdk',
|
|
183
|
+
],
|
|
184
|
+
type: 'object',
|
|
185
|
+
properties: {
|
|
186
|
+
event: { type: 'string', examples: ['test_event'] },
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const targets = resolveExampleTargets(schema);
|
|
191
|
+
expect(targets.map((t) => t.id)).toEqual([
|
|
192
|
+
'web-datalayer-js',
|
|
193
|
+
'android-firebase-kotlin-sdk',
|
|
194
|
+
]);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('returns empty variantGroups and isSimpleDefault false when schema produces no examples', () => {
|
|
198
|
+
// A schema with type object but no properties and no examples yields no example groups
|
|
199
|
+
const schema = {
|
|
200
|
+
type: 'object',
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const model = buildExampleModel(schema);
|
|
204
|
+
expect(model.variantGroups).toEqual([]);
|
|
205
|
+
expect(model.isSimpleDefault).toBe(false);
|
|
206
|
+
expect(model.targets).toHaveLength(1);
|
|
207
|
+
expect(model.targets[0].id).toBe(DEFAULT_SNIPPET_TARGET_ID);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('sets isSimpleDefault to false when there are multiple variantGroups', () => {
|
|
211
|
+
const model = buildExampleModel(choiceEventSchema);
|
|
212
|
+
expect(model.isSimpleDefault).toBe(false);
|
|
213
|
+
expect(model.variantGroups.length).toBeGreaterThan(1);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('sets isSimpleDefault to false when single variantGroup property is not "default"', () => {
|
|
217
|
+
// A schema with exactly one oneOf choice point produces a single variantGroup
|
|
218
|
+
// whose property is the field name (not 'default')
|
|
219
|
+
const schema = {
|
|
220
|
+
type: 'object',
|
|
221
|
+
properties: {
|
|
222
|
+
event: { type: 'string', examples: ['test_event'] },
|
|
223
|
+
category: {
|
|
224
|
+
oneOf: [
|
|
225
|
+
{ title: 'Standard', const: 'standard' },
|
|
226
|
+
{ title: 'Premium', const: 'premium' },
|
|
227
|
+
],
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const model = buildExampleModel(schema);
|
|
233
|
+
expect(model.variantGroups).toHaveLength(1);
|
|
234
|
+
expect(model.variantGroups[0].property).not.toBe('default');
|
|
235
|
+
expect(model.isSimpleDefault).toBe(false);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it('falls back to default target when schema is undefined (optional chaining guard)', () => {
|
|
239
|
+
const targets = resolveExampleTargets(undefined);
|
|
240
|
+
expect(targets).toHaveLength(1);
|
|
241
|
+
expect(targets[0].id).toBe(DEFAULT_SNIPPET_TARGET_ID);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('falls back to default target when schema is null (optional chaining guard)', () => {
|
|
245
|
+
const targets = resolveExampleTargets(null);
|
|
246
|
+
expect(targets).toHaveLength(1);
|
|
247
|
+
expect(targets[0].id).toBe(DEFAULT_SNIPPET_TARGET_ID);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('uses configured array content (not empty) when x-tracking-targets is absent', () => {
|
|
251
|
+
// Kills ArrayDeclaration mutant: [DEFAULT_SNIPPET_TARGET_ID] -> []
|
|
252
|
+
// If the fallback were [], targets would be empty, triggering the line-27 fallback
|
|
253
|
+
// but the target IDs would differ in the mapping step
|
|
254
|
+
const schema = { type: 'object' };
|
|
255
|
+
const targets = resolveExampleTargets(schema);
|
|
256
|
+
expect(targets).toHaveLength(1);
|
|
257
|
+
expect(targets[0].id).toBe(DEFAULT_SNIPPET_TARGET_ID);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it('treats non-array x-tracking-targets as absent and falls back to default', () => {
|
|
261
|
+
// Kills ConditionalExpression mutant on line 12: configured.length > 0 -> true
|
|
262
|
+
// When configured is a string (truthy but not an Array), Array.isArray is false
|
|
263
|
+
// so it should still fall back to default
|
|
264
|
+
const schema = {
|
|
265
|
+
'x-tracking-targets': 'not-an-array',
|
|
266
|
+
type: 'object',
|
|
267
|
+
};
|
|
268
|
+
const targets = resolveExampleTargets(schema);
|
|
269
|
+
expect(targets).toHaveLength(1);
|
|
270
|
+
expect(targets[0].id).toBe(DEFAULT_SNIPPET_TARGET_ID);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('generates option ids from property name and index', () => {
|
|
274
|
+
// Kills StringLiteral mutant: `${group.property}-${index}` -> ``
|
|
275
|
+
const schema = {
|
|
276
|
+
type: 'object',
|
|
277
|
+
properties: {
|
|
278
|
+
event: { type: 'string', examples: ['test_event'] },
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const model = buildExampleModel(schema);
|
|
283
|
+
expect(model.variantGroups[0].options[0].id).toBe('default-0');
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it('generates sequential option ids for choice schemas', () => {
|
|
287
|
+
// Further kills StringLiteral mutant by checking index > 0
|
|
288
|
+
const schema = {
|
|
289
|
+
type: 'object',
|
|
290
|
+
properties: {
|
|
291
|
+
event: { type: 'string', examples: ['test_event'] },
|
|
292
|
+
category: {
|
|
293
|
+
oneOf: [
|
|
294
|
+
{ title: 'Standard', const: 'standard' },
|
|
295
|
+
{ title: 'Premium', const: 'premium' },
|
|
296
|
+
],
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const model = buildExampleModel(schema);
|
|
302
|
+
const group = model.variantGroups[0];
|
|
303
|
+
expect(group.options[0].id).toBe(`${group.property}-0`);
|
|
304
|
+
expect(group.options[1].id).toBe(`${group.property}-1`);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('sets isSimpleDefault to false for multiple groups even if first is "default"', () => {
|
|
308
|
+
// Kills ConditionalExpression mutant on line 66: variantGroups.length === 1 -> true
|
|
309
|
+
// choiceEventSchema produces multiple variant groups, so isSimpleDefault must be false
|
|
310
|
+
// even if the mutant forces length===1 to true
|
|
311
|
+
const model = buildExampleModel(choiceEventSchema);
|
|
312
|
+
expect(model.variantGroups.length).toBeGreaterThan(1);
|
|
313
|
+
expect(model.isSimpleDefault).toBe(false);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
it('returns early return shape when schema has no properties', () => {
|
|
317
|
+
// Kills BlockStatement and condition mutants on line 34
|
|
318
|
+
// Verifies the exact shape of the early-return object
|
|
319
|
+
const schema = { type: 'object' };
|
|
320
|
+
const model = buildExampleModel(schema);
|
|
321
|
+
expect(model).toEqual({
|
|
322
|
+
targets: expect.any(Array),
|
|
323
|
+
variantGroups: [],
|
|
324
|
+
isSimpleDefault: false,
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('includes snippets keyed by each target id when multiple targets are configured', () => {
|
|
329
|
+
const schema = {
|
|
330
|
+
'x-tracking-targets': ['web-datalayer-js', 'android-firebase-kotlin-sdk'],
|
|
331
|
+
type: 'object',
|
|
332
|
+
properties: {
|
|
333
|
+
event: { type: 'string', examples: ['test_event'] },
|
|
334
|
+
},
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
const model = buildExampleModel(schema);
|
|
338
|
+
const snippetKeys = Object.keys(model.variantGroups[0].options[0].snippets);
|
|
339
|
+
expect(snippetKeys).toEqual([
|
|
340
|
+
'web-datalayer-js',
|
|
341
|
+
'android-firebase-kotlin-sdk',
|
|
342
|
+
]);
|
|
343
|
+
});
|
|
135
344
|
});
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
readSchemas,
|
|
5
|
+
writeDoc,
|
|
6
|
+
createDir,
|
|
7
|
+
readSchemaSources,
|
|
8
|
+
} from '../../helpers/file-system';
|
|
4
9
|
|
|
5
10
|
jest.mock('fs', () => {
|
|
6
11
|
const memfs = require('memfs');
|
|
@@ -24,6 +29,16 @@ describe('file-system helpers', () => {
|
|
|
24
29
|
expect(schemas[0].fileName).toBe('schema1.json');
|
|
25
30
|
expect(schemas[1].fileName).toBe('schema2.json');
|
|
26
31
|
});
|
|
32
|
+
|
|
33
|
+
it('should parse schema content as JSON', () => {
|
|
34
|
+
// L17: StringLiteral → "" — encoding must be 'utf-8' to get string
|
|
35
|
+
fs.vol.reset();
|
|
36
|
+
fs.vol.fromJSON({
|
|
37
|
+
'/s/test.json': '{"id":"test-schema"}',
|
|
38
|
+
});
|
|
39
|
+
const schemas = readSchemas('/s');
|
|
40
|
+
expect(schemas[0].schema).toEqual({ id: 'test-schema' });
|
|
41
|
+
});
|
|
27
42
|
});
|
|
28
43
|
|
|
29
44
|
describe('writeDoc', () => {
|
|
@@ -33,6 +48,15 @@ describe('file-system helpers', () => {
|
|
|
33
48
|
const content = fs.readFileSync('/output/doc1.mdx', 'utf-8');
|
|
34
49
|
expect(content).toBe('content');
|
|
35
50
|
});
|
|
51
|
+
|
|
52
|
+
it('should log the generated file path', () => {
|
|
53
|
+
// L57: StringLiteral → `` — empty template literal
|
|
54
|
+
fs.mkdirSync('/out', { recursive: true });
|
|
55
|
+
const spy = jest.spyOn(console, 'log').mockImplementation(() => {});
|
|
56
|
+
writeDoc('/out', 'doc.mdx', 'hello');
|
|
57
|
+
expect(spy).toHaveBeenCalledWith(expect.stringContaining('Generated'));
|
|
58
|
+
spy.mockRestore();
|
|
59
|
+
});
|
|
36
60
|
});
|
|
37
61
|
|
|
38
62
|
describe('createDir', () => {
|
|
@@ -40,5 +64,53 @@ describe('file-system helpers', () => {
|
|
|
40
64
|
createDir('/new-dir');
|
|
41
65
|
expect(fs.existsSync('/new-dir')).toBe(true);
|
|
42
66
|
});
|
|
67
|
+
|
|
68
|
+
it('should not call mkdirSync when directory already exists', () => {
|
|
69
|
+
// L5: ConditionalExpression → true — mutant always calls mkdirSync
|
|
70
|
+
fs.mkdirSync('/existing-dir', { recursive: true });
|
|
71
|
+
const spy = jest.spyOn(fs, 'mkdirSync');
|
|
72
|
+
createDir('/existing-dir');
|
|
73
|
+
expect(spy).not.toHaveBeenCalled();
|
|
74
|
+
spy.mockRestore();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should create nested directories recursively', () => {
|
|
78
|
+
// L6: ObjectLiteral → {} and BooleanLiteral → false
|
|
79
|
+
// Without recursive: true, creating nested dirs would fail
|
|
80
|
+
createDir('/a/b/c/d');
|
|
81
|
+
expect(fs.existsSync('/a/b/c/d')).toBe(true);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('readSchemaSources', () => {
|
|
86
|
+
it('should read json files recursively and key by relative path', () => {
|
|
87
|
+
// L39: ConditionalExpression → false and StringLiteral → ""
|
|
88
|
+
// L45: StringLiteral → "" (encoding)
|
|
89
|
+
fs.vol.reset();
|
|
90
|
+
fs.vol.fromJSON({
|
|
91
|
+
'/root/a.json': '{"name":"a"}',
|
|
92
|
+
'/root/sub/b.json': '{"name":"b"}',
|
|
93
|
+
'/root/skip.txt': 'not json',
|
|
94
|
+
});
|
|
95
|
+
const result = readSchemaSources('/root');
|
|
96
|
+
expect(Object.keys(result)).toEqual(
|
|
97
|
+
expect.arrayContaining(['a.json', 'sub/b.json']),
|
|
98
|
+
);
|
|
99
|
+
expect(Object.keys(result)).not.toContain('skip.txt');
|
|
100
|
+
expect(result['a.json']).toEqual({ name: 'a' });
|
|
101
|
+
expect(result['sub/b.json']).toEqual({ name: 'b' });
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should only include .json files, not other extensions', () => {
|
|
105
|
+
// L39: StringLiteral → "" would match all files including .txt
|
|
106
|
+
fs.vol.reset();
|
|
107
|
+
fs.vol.fromJSON({
|
|
108
|
+
'/root/valid.json': '{}',
|
|
109
|
+
'/root/readme.txt': 'text',
|
|
110
|
+
'/root/data.csv': 'csv',
|
|
111
|
+
});
|
|
112
|
+
const result = readSchemaSources('/root');
|
|
113
|
+
expect(Object.keys(result)).toEqual(['valid.json']);
|
|
114
|
+
});
|
|
43
115
|
});
|
|
44
116
|
});
|
|
@@ -116,4 +116,31 @@ describe('getConstraints', () => {
|
|
|
116
116
|
};
|
|
117
117
|
expect(getConstraints(prop, false)).toEqual(['not: { type: "string" }']);
|
|
118
118
|
});
|
|
119
|
+
|
|
120
|
+
it('should not include uniqueItems constraint when value is false', () => {
|
|
121
|
+
const prop = { uniqueItems: false };
|
|
122
|
+
expect(getConstraints(prop, false)).toEqual([]);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should not include additionalProperties constraint when value is true', () => {
|
|
126
|
+
const prop = { additionalProperties: true };
|
|
127
|
+
expect(getConstraints(prop, false)).toEqual([]);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should render "not" constraint with nested array values', () => {
|
|
131
|
+
const prop = {
|
|
132
|
+
not: { enum: ['a', 'b'] },
|
|
133
|
+
};
|
|
134
|
+
expect(getConstraints(prop, false)).toEqual(['not: { enum: ["a", "b"] }']);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should render "not" constraint with deeply nested array of objects', () => {
|
|
138
|
+
const prop = {
|
|
139
|
+
not: { items: [{ type: 'string' }, { type: 'number' }] },
|
|
140
|
+
};
|
|
141
|
+
const result = getConstraints(prop, false);
|
|
142
|
+
expect(result).toEqual([
|
|
143
|
+
'not: { items: [{ type: "string" }, { type: "number" }] }',
|
|
144
|
+
]);
|
|
145
|
+
});
|
|
119
146
|
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { mergeSchema } from '../../helpers/mergeSchema';
|
|
2
|
+
|
|
3
|
+
describe('mergeSchema', () => {
|
|
4
|
+
it('merges allOf into a single schema', () => {
|
|
5
|
+
const result = mergeSchema({
|
|
6
|
+
allOf: [
|
|
7
|
+
{ type: 'object', properties: { a: { type: 'string' } } },
|
|
8
|
+
{ type: 'object', properties: { b: { type: 'number' } } },
|
|
9
|
+
],
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
expect(result.properties).toEqual({
|
|
13
|
+
a: { type: 'string' },
|
|
14
|
+
b: { type: 'number' },
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('preserves $defs via the baseResolvers', () => {
|
|
19
|
+
const result = mergeSchema({
|
|
20
|
+
allOf: [
|
|
21
|
+
{
|
|
22
|
+
type: 'object',
|
|
23
|
+
$defs: { shared: { type: 'string' } },
|
|
24
|
+
properties: { a: { type: 'string' } },
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
type: 'object',
|
|
28
|
+
$defs: { other: { type: 'number' } },
|
|
29
|
+
properties: { b: { type: 'number' } },
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
expect(result.$defs).toEqual({
|
|
35
|
+
shared: { type: 'string' },
|
|
36
|
+
other: { type: 'number' },
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('passes custom resolvers through to json-schema-merge-allof', () => {
|
|
41
|
+
const customTitleResolver = (values) => values.join(' + ');
|
|
42
|
+
|
|
43
|
+
const result = mergeSchema(
|
|
44
|
+
{
|
|
45
|
+
allOf: [
|
|
46
|
+
{
|
|
47
|
+
type: 'object',
|
|
48
|
+
title: 'Foo',
|
|
49
|
+
properties: { a: { type: 'string' } },
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
type: 'object',
|
|
53
|
+
title: 'Bar',
|
|
54
|
+
properties: { b: { type: 'number' } },
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
{ resolvers: { title: customTitleResolver } },
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
expect(result.title).toBe('Foo + Bar');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('works without custom options', () => {
|
|
65
|
+
const result = mergeSchema({
|
|
66
|
+
allOf: [{ type: 'object', properties: { x: { type: 'boolean' } } }],
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
expect(result.properties.x).toEqual({ type: 'boolean' });
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('merges additional options beyond resolvers', () => {
|
|
73
|
+
// ignoreAdditionalProperties is a real json-schema-merge-allof option
|
|
74
|
+
const result = mergeSchema(
|
|
75
|
+
{
|
|
76
|
+
allOf: [
|
|
77
|
+
{
|
|
78
|
+
type: 'object',
|
|
79
|
+
properties: { a: { type: 'string' } },
|
|
80
|
+
additionalProperties: false,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
type: 'object',
|
|
84
|
+
properties: { b: { type: 'number' } },
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
{ ignoreAdditionalProperties: true },
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
expect(result.properties.a).toEqual({ type: 'string' });
|
|
92
|
+
expect(result.properties.b).toEqual({ type: 'number' });
|
|
93
|
+
});
|
|
94
|
+
});
|