• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SignpostMarv / JSON-Schema-TypeScript-CodeGen / 19434745916

17 Nov 2025 03:11PM UTC coverage: 99.427% (-0.6%) from 100.0%
19434745916

push

github

SignpostMarv
increasing coverage

639 of 649 branches covered (98.46%)

Branch coverage included in aggregate %.

9256 of 9303 relevant lines covered (99.49%)

210.06 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.27
/src/JSONSchema/SomethingOf.ts
1
import type {
19✔
2
        Expression,
19✔
3
        KeywordTypeNode,
19✔
4
        PropertyAssignment,
19✔
5
        SyntaxKind,
19✔
6
        TypeNode,
19✔
7
} from 'typescript';
19✔
8
import {
19✔
9
        isObjectLiteralExpression,
19✔
10
        isPropertyAssignment,
19✔
11
} from 'typescript';
19✔
12

19✔
13
import {
19✔
14
        object_has_property,
19✔
15
} from '@satisfactory-dev/predicates.ts';
19✔
16

19✔
17
import type {
19✔
18
        SchemaDefinitionDefinition,
19✔
19
        SchemaDefinitionDefinitionWithNoSpecifiedProperties,
19✔
20
} from './Type.ts';
19✔
21
import {
19✔
22
        Type,
19✔
23
} from './Type.ts';
19✔
24

19✔
25
import type {
19✔
26
        $ref_type,
19✔
27
} from './Ref.ts';
19✔
28
import {
19✔
29
        $ref,
19✔
30
} from './Ref.ts';
19✔
31

19✔
32
import {
19✔
33
        $defs,
19✔
34
} from './$defs.ts';
19✔
35

19✔
36
import type {
19✔
37
        ObjectOfSchemas,
19✔
38
        SchemaObject,
19✔
39
// eslint-disable-next-line imports/no-relative-parent-imports
19✔
40
} from '../types.ts';
19✔
41

19✔
42
import type {
19✔
43
        SchemaParser,
19✔
44
// eslint-disable-next-line imports/no-relative-parent-imports
19✔
45
} from '../SchemaParser.ts';
19✔
46

19✔
47
import type {
19✔
48
        IntersectionTypeNode,
19✔
49
        UnionTypeNode,
19✔
50
// eslint-disable-next-line imports/no-relative-parent-imports
19✔
51
} from '../typescript/types.ts';
19✔
52

19✔
53
import {
19✔
54
        factory,
19✔
55
// eslint-disable-next-line imports/no-relative-parent-imports
19✔
56
} from '../typescript/factory.ts';
19✔
57

19✔
58
import {
19✔
59
        SchemaValidationError,
19✔
60
// eslint-disable-next-line imports/no-relative-parent-imports
19✔
61
} from '../SchemaValidationError.ts';
19✔
62

19✔
63
type type_choices = [SchemaObject, SchemaObject, ...SchemaObject[]];
19✔
64

19✔
65
type something_of_kind = 'oneOf'|'anyOf'|'allOf';
19✔
66
type something_of_mode = 'specified'|'unspecified';
19✔
67

19✔
68
type something_of_type<
19✔
69
        Kind extends something_of_kind,
19✔
70
        Mode extends something_of_mode = something_of_mode,
19✔
71
        Choices extends type_choices = type_choices,
19✔
72
        Defs extends ObjectOfSchemas = ObjectOfSchemas,
19✔
73
> = {
19✔
74
        oneOf: {
19✔
75
                specified: {
19✔
76
                        $defs?: Defs,
19✔
77
                        oneOf: Choices,
19✔
78
                },
19✔
79
                unspecified: Record<string, never>,
19✔
80
        }[Mode],
19✔
81
        anyOf: {
19✔
82
                specified: {
19✔
83
                        $defs?: Defs,
19✔
84
                        anyOf: Choices,
19✔
85
                },
19✔
86
                unspecified: Record<string, never>,
19✔
87
        }[Mode],
19✔
88
        allOf: {
19✔
89
                specified: {
19✔
90
                        $defs?: Defs,
19✔
91
                        allOf: Choices,
19✔
92
                },
19✔
93
                unspecified: Record<string, never>,
19✔
94
        }[Mode],
19✔
95
}[Kind];
19✔
96

19✔
97
type something_of_type_options<
19✔
98
        Kind extends something_of_kind,
19✔
99
        Mode extends something_of_mode = something_of_mode,
19✔
100
        Choices extends type_choices = type_choices,
19✔
101
        Defs extends ObjectOfSchemas = ObjectOfSchemas,
19✔
102
> = {
19✔
103
        specified: {
19✔
104
                kind: Kind,
19✔
105
                mode: Mode,
19✔
106
                choices: Choices,
19✔
107
                $defs?: Defs,
19✔
108
        },
19✔
109
        unspecified: {
19✔
110
                kind: Kind,
19✔
111
                mode: Mode,
19✔
112
                choices?: never[],
19✔
113
        },
19✔
114
}[Mode];
19✔
115

19✔
116
type schema_choices = [
19✔
117
        SchemaDefinitionDefinition,
19✔
118
        SchemaDefinitionDefinition,
19✔
119
        ...SchemaDefinitionDefinition[],
19✔
120
];
19✔
121

19✔
122
type something_of_schema_options<
19✔
123
        Kind extends something_of_kind,
19✔
124
        Mode extends something_of_mode = something_of_mode,
19✔
125
        Choices extends schema_choices = schema_choices,
19✔
126
> = {
19✔
127
        specified: {
19✔
128
                kind: Kind,
19✔
129
                mode: Mode,
19✔
130
                choices: Choices,
19✔
131
        },
19✔
132
        unspecified: {
19✔
133
                kind: Kind,
19✔
134
                mode: Mode,
19✔
135
                choices?: never[],
19✔
136
        },
19✔
137
}[Mode];
19✔
138

19✔
139
type something_of_schema<
19✔
140
        Kind extends something_of_kind,
19✔
141
        Mode extends something_of_mode = something_of_mode,
19✔
142
        Choices extends schema_choices = schema_choices,
19✔
143
> = {
19✔
144
        specified: SchemaDefinitionDefinition<
19✔
145
                [Kind],
19✔
146
                {
19✔
147
                        oneOf: {
19✔
148
                                $defs: {
19✔
149
                                        type: 'object',
19✔
150
                                        additionalProperties: {
19✔
151
                                                type: 'object',
19✔
152
                                        },
19✔
153
                                },
19✔
154
                                oneOf: {
19✔
155
                                        type: 'array',
19✔
156
                                        const: Choices,
19✔
157
                                },
19✔
158
                        },
19✔
159
                        anyOf: {
19✔
160
                                $defs: {
19✔
161
                                        type: 'object',
19✔
162
                                        additionalProperties: {
19✔
163
                                                type: 'object',
19✔
164
                                        },
19✔
165
                                },
19✔
166
                                anyOf: {
19✔
167
                                        type: 'array',
19✔
168
                                        const: Choices,
19✔
169
                                },
19✔
170
                        },
19✔
171
                        allOf: {
19✔
172
                                $defs: {
19✔
173
                                        type: 'object',
19✔
174
                                        additionalProperties: {
19✔
175
                                                type: 'object',
19✔
176
                                        },
19✔
177
                                },
19✔
178
                                allOf: {
19✔
179
                                        type: 'array',
19✔
180
                                        const: Choices,
19✔
181
                                },
19✔
182
                        },
19✔
183
                }[Kind]
19✔
184
        >,
19✔
185
        unspecified: SchemaDefinitionDefinition<
19✔
186
                [Kind],
19✔
187
                {
19✔
188
                        oneOf: {
19✔
189
                                $defs: {
19✔
190
                                        type: 'object',
19✔
191
                                        additionalProperties: {
19✔
192
                                                type: 'object',
19✔
193
                                        },
19✔
194
                                },
19✔
195
                                oneOf: {
19✔
196
                                        type: 'array',
19✔
197
                                        minItems: 2,
19✔
198
                                        items: SchemaDefinitionDefinitionWithNoSpecifiedProperties,
19✔
199
                                },
19✔
200
                        },
19✔
201
                        anyOf: {
19✔
202
                                $defs: {
19✔
203
                                        type: 'object',
19✔
204
                                        additionalProperties: {
19✔
205
                                                type: 'object',
19✔
206
                                        },
19✔
207
                                },
19✔
208
                                anyOf: {
19✔
209
                                        type: 'array',
19✔
210
                                        minItems: 2,
19✔
211
                                        items: SchemaDefinitionDefinitionWithNoSpecifiedProperties,
19✔
212
                                },
19✔
213
                        },
19✔
214
                        allOf: {
19✔
215
                                $defs: {
19✔
216
                                        type: 'object',
19✔
217
                                        additionalProperties: {
19✔
218
                                                type: 'object',
19✔
219
                                        },
19✔
220
                                },
19✔
221
                                allOf: {
19✔
222
                                        type: 'array',
19✔
223
                                        minItems: 2,
19✔
224
                                        items: SchemaDefinitionDefinitionWithNoSpecifiedProperties,
19✔
225
                                },
19✔
226
                        },
19✔
227
                }[Kind]
19✔
228
        >,
19✔
229
}[Mode];
19✔
230

19✔
231
abstract class SomethingOf<
19✔
232
        T,
19✔
233
        Kind extends something_of_kind,
19✔
234
        Mode extends something_of_mode = something_of_mode,
19✔
235
        TypeChoices extends type_choices = type_choices,
19✔
236
        SchemaChoices extends schema_choices = schema_choices,
19✔
237
        Defs extends ObjectOfSchemas = ObjectOfSchemas,
19✔
238
> extends
19✔
239
        Type<
19✔
240
                T,
19✔
241
                something_of_type<Kind, Mode, TypeChoices, Defs>,
19✔
242
                something_of_type_options<Kind, Mode, TypeChoices, Defs>,
19✔
243
                something_of_schema<Kind, Mode, SchemaChoices>,
19✔
244
                something_of_schema_options<Kind, Mode, SchemaChoices>,
19✔
245
                {
19✔
246
                        oneOf: KeywordTypeNode<SyntaxKind.UnknownKeyword> | UnionTypeNode,
19✔
247
                        anyOf: KeywordTypeNode<SyntaxKind.UnknownKeyword> | UnionTypeNode,
19✔
248
                        allOf: (
19✔
249
                                | KeywordTypeNode<SyntaxKind.UnknownKeyword>
19✔
250
                                | IntersectionTypeNode<[TypeNode, ...TypeNode[]]>
19✔
251
                        ),
19✔
252
                }[Kind],
19✔
253
                Expression
19✔
254
        > {
19✔
255
        generate_typescript_data(
19✔
256
                data: T,
45✔
257
                schema_parser: SchemaParser,
45✔
258
                schema: something_of_type<Kind, Mode, TypeChoices, Defs>,
45✔
259
        ) {
45✔
260
                if (SomethingOf.#is_allOf(schema)) {
45✔
261
                        return this.#merge_subschema_for_data(
23✔
262
                                data,
23✔
263
                                schema,
23✔
264
                                schema_parser,
23✔
265
                        );
23✔
266
                }
23✔
267

22✔
268
                const [
22✔
269
                        sub_schema,
22✔
270
                        matched_type,
22✔
271
                ] = this.#sub_schema_handler(
22✔
272
                        data,
22✔
273
                        schema,
22✔
274
                        schema_parser,
22✔
275
                );
22✔
276

22✔
277
                return matched_type.generate_typescript_data(
22✔
278
                        data,
22✔
279
                        schema_parser,
22✔
280
                        sub_schema,
22✔
281
                );
22✔
282
        }
45✔
283

19✔
284
        async generate_typescript_type(
19✔
285
                {
19✔
286
                        data,
19✔
287
                        schema,
19✔
288
                        schema_parser,
19✔
289
                }: {
19✔
290
                        data: T,
19✔
291
                        schema: Record<string, never>,
19✔
292
                        schema_parser: SchemaParser,
19✔
293
                },
19✔
294
        ): Promise<TypeNode>;
19✔
295
        async generate_typescript_type(
19✔
296
                {
19✔
297
                        data,
19✔
298
                        schema,
19✔
299
                        schema_parser,
19✔
300
                }: {
19✔
301
                        data: T,
19✔
302
                        schema: something_of_type<Kind, Mode, TypeChoices, Defs>,
19✔
303
                        schema_parser: SchemaParser,
19✔
304
                },
19✔
305
        ): Promise<{
19✔
306
                oneOf: UnionTypeNode,
19✔
307
                anyOf: UnionTypeNode,
19✔
308
                allOf: IntersectionTypeNode<[TypeNode, ...TypeNode[]]>,
19✔
309
        }[Kind]>;
19✔
310
        async generate_typescript_type(
19✔
311
                {
15✔
312
                        data,
15✔
313
                        schema,
15✔
314
                        schema_parser,
15✔
315
                }: {
15✔
316
                        data: T,
15✔
317
                        schema: (
15✔
318
                                | something_of_type<Kind, Mode, TypeChoices, Defs>
15✔
319
                                | Record<string, never>
15✔
320
                        ),
15✔
321
                        schema_parser: SchemaParser,
15✔
322
                },
15✔
323
        ): Promise<{
15✔
324
                oneOf: TypeNode | UnionTypeNode,
15✔
325
                anyOf: TypeNode | UnionTypeNode,
15✔
326
                allOf: (
15✔
327
                        | TypeNode
15✔
328
                        | IntersectionTypeNode<[TypeNode, ...TypeNode[]]>
15✔
329
                ),
15✔
330
        }[Kind]> {
15✔
331
                if (!SomethingOf.#is_non_empty_schema(schema)) {
15✔
332
                        return schema_parser.parse_by_type(
3✔
333
                                data,
3✔
334
                                undefined,
3✔
335
                        ).generate_typescript_type({
3✔
336
                                data,
3✔
337
                                schema,
3✔
338
                                schema_parser,
3✔
339
                        });
3✔
340
                }
3✔
341

12✔
342
                const choices = 'oneOf' in schema
12✔
343
                        ? schema.oneOf
14✔
344
                        : ('allOf' in schema ? schema.allOf : schema.anyOf);
15✔
345

15✔
346
                const sub_types = await Promise.all(
15✔
347
                        choices.map((
15✔
348
                                sub_schema,
24✔
349
                        ) => SomethingOf.maybe_add_$defs(
24✔
350
                                schema,
24✔
351
                                sub_schema,
24✔
352
                        )).map((sub_schema) => {
15✔
353
                                return schema_parser.parse(
24✔
354
                                        SomethingOf.maybe_add_$defs(
24✔
355
                                                schema,
24✔
356
                                                sub_schema,
24✔
357
                                        ),
24✔
358
                                ).generate_typescript_type({
24✔
359
                                        data: data,
24✔
360
                                        schema: sub_schema,
24✔
361
                                        schema_parser,
24✔
362
                                });
24✔
363
                        }),
15✔
364
                );
15✔
365

12✔
366
                let result: {
12✔
367
                        oneOf: UnionTypeNode,
12✔
368
                        anyOf: UnionTypeNode,
12✔
369
                        allOf: IntersectionTypeNode<[TypeNode, ...TypeNode[]]>,
12✔
370
                }[Kind];
12✔
371

12✔
372
                if (SomethingOf.#is_allOf_schema(schema)) {
14✔
373
                        const sanity_check: IntersectionTypeNode<
2✔
374
                                [TypeNode, ...TypeNode[]]
2✔
375
                        > = factory.createIntersectionTypeNode(sub_types);
2✔
376

2✔
377
                        result = sanity_check as typeof result;
2✔
378
                } else {
15✔
379
                        const sanity_check: UnionTypeNode = factory.createUnionTypeNode(
10✔
380
                                sub_types,
10✔
381
                        );
10✔
382

10✔
383
                        result = sanity_check as typeof result;
10✔
384
                }
10✔
385

12✔
386
                return result;
12✔
387
        }
15✔
388

19✔
389
        static #is_allOf<
19✔
390
                Mode extends something_of_mode = something_of_mode,
45✔
391
                Choices extends type_choices = type_choices,
45✔
392
                Defs extends ObjectOfSchemas = ObjectOfSchemas,
45✔
393
        >(
45✔
394
                schema: something_of_type<something_of_kind, Mode, Choices, Defs>,
45✔
395
        ): schema is something_of_type<'allOf', Mode, Choices, Defs> {
45✔
396
                return 'allOf' in schema;
45✔
397
        }
45✔
398

19✔
399
        #merge_subschema_for_data(
19✔
400
                data: T,
23✔
401
                schema: something_of_type<'allOf', Mode, TypeChoices, Defs>,
23✔
402
                schema_parser: SchemaParser,
23✔
403
        ): Expression {
23✔
404
                const properties: PropertyAssignment[] = [];
23✔
405

23✔
406
                const choices = schema.allOf.map((sub_schema) => {
23✔
407
                        if ('$ref' in sub_schema) {
45✔
408
                                const $ref_type = schema_parser.types
33✔
409
                                        .find((maybe) => maybe instanceof $ref);
33✔
410

33✔
411
                                if (undefined === $ref_type) {
33✔
412
                                        throw new TypeError(
1✔
413
                                                '$ref schema found but could not get parser type!',
1✔
414
                                        );
1✔
415
                                }
1✔
416

32✔
417
                                return $ref_type.resolve_def(
32✔
418
                                        sub_schema as $ref_type,
32✔
419
                                        schema.$defs || {},
33✔
420
                                );
33✔
421
                        }
33✔
422

12✔
423
                        return sub_schema;
12✔
424
                });
23✔
425

23✔
426
                const has_const = choices.find((maybe) => 'const' in maybe);
23✔
427

23✔
428
                if (has_const) {
23✔
429
                        return schema_parser.parse(has_const).generate_typescript_data(
4✔
430
                                data,
4✔
431
                                schema_parser,
4✔
432
                                has_const,
4✔
433
                        );
4✔
434
                }
4✔
435

17✔
436
                if (
17✔
437
                        'object' !== typeof data
17✔
438
                        || null === data
17✔
439
                        || Array.isArray(data)
23✔
440
                ) {
23✔
441
                        throw new TypeError('Only object data supported here!');
1✔
442
                }
1✔
443

16✔
444
                const expected_properties = Object.keys(data);
16✔
445
                const found_properties: string[] = [];
16✔
446

16✔
447
                for (const unmodified of choices) {
23✔
448
                        const resolved = SomethingOf.maybe_add_$defs(schema, unmodified);
30✔
449

30✔
450
                        if ('object' !== resolved.type) {
30✔
451
                                throw new TypeError('Only object types supported here!');
1✔
452
                        } else if ('patternProperties' in resolved) {
30✔
453
                                throw new TypeError('patternProperties not yet supported!');
1✔
454
                        } else if (!('properties' in resolved)) {
29✔
455
                                throw new TypeError('properties not present in schema!');
1✔
456
                        }
1✔
457

27✔
458
                        const sub_data: {[key: string]: unknown} = {};
27✔
459

27✔
460
                        for (const property of Object.keys(resolved.properties)) {
30✔
461
                                if (found_properties.includes(property)) {
29✔
462
                                        throw new TypeError(
1✔
463
                                                `Schema contains multiple references to ${property}`,
1✔
464
                                        );
1✔
465
                                }
1✔
466

28✔
467
                                if (!object_has_property(data, property)) {
29✔
468
                                        throw new TypeError(
1✔
469
                                                `Data does not have property ${property}`,
1✔
470
                                        );
1✔
471
                                }
1✔
472

27✔
473
                                sub_data[property] = data[property];
27✔
474

27✔
475
                                found_properties.push(property);
27✔
476
                        }
27✔
477

25✔
478
                        if ('$ref' in resolved) {
30✔
479
                                throw new Error('nested $ref not implemented!');
1✔
480
                        }
1✔
481

24✔
482
                        const sub_type = schema_parser.parse(resolved);
24✔
483

24✔
484
                        const resolved_data = sub_type.generate_typescript_data(
24✔
485
                                sub_data,
24✔
486
                                schema_parser,
24✔
487
                                resolved,
24✔
488
                        );
24✔
489

24✔
490
                        if (!isObjectLiteralExpression(resolved_data)) {
30!
491
                                throw new TypeError('Was expecting ObjectLiteralExpression!');
×
492
                        }
×
493

24✔
494
                        for (const property of resolved_data.properties) {
30✔
495
                                if (!isPropertyAssignment(property)) {
26!
496
                                        throw new TypeError('Was expecting PropertyAssignment!');
×
497
                                }
×
498

26✔
499
                                properties.push(property);
26✔
500
                        }
26✔
501
                }
24✔
502

10✔
503
                const missing = expected_properties
10✔
504
                        .filter((maybe) => !found_properties.includes(maybe));
10✔
505

10✔
506
                if (missing.length > 0) {
23✔
507
                        throw new TypeError(
1✔
508
                                `Schema is missing definition for some properties: ${
1✔
509
                                        missing.join(', ')
1✔
510
                                }`,
1✔
511
                        );
1✔
512
                }
1✔
513

9✔
514
                return factory.createObjectLiteralExpression(
9✔
515
                        properties,
9✔
516
                        true,
9✔
517
                );
9✔
518
        }
23✔
519

19✔
520
        #sub_schema_handler(
19✔
521
                data: T,
22✔
522
                schema: something_of_type<Kind, Mode, TypeChoices, Defs>,
22✔
523
                schema_parser: SchemaParser,
22✔
524
        ): [SchemaObject, Type<unknown>] {
22✔
525
                const ajv = schema_parser.share_ajv((ajv) => ajv);
22✔
526
                const validator = ajv.compile(schema);
22✔
527

22✔
528
                if (!validator(data)) {
22✔
529
                        throw new SchemaValidationError('Data was not valid!', validator);
4✔
530
                }
4✔
531

18✔
532
                if (0 === Object.keys(schema).length) {
18✔
533
                        return [{}, schema_parser.parse_by_type<
8✔
534
                                Type<unknown>
8✔
535
                        >(
8✔
536
                                data,
8✔
537
                                (maybe): maybe is Type<unknown> => {
8✔
538
                                        return Type.is_a(maybe) && (
23✔
539
                                                !(maybe instanceof SomethingOf)
23✔
540
                                                && !(maybe instanceof $defs)
23✔
541
                                        );
23✔
542
                                },
8✔
543
                        )];
8✔
544
                }
8✔
545

10✔
546
                const choices = 'oneOf' in schema
10✔
547
                        ? schema.oneOf
18✔
548
                        : ('allOf' in schema ? schema.allOf : schema.anyOf);
22!
549

22✔
550
                const sub_schema = choices.map((
22✔
551
                        sub_schema,
20✔
552
                ) => SomethingOf.maybe_add_$defs(schema, sub_schema)).find((maybe) => {
22✔
553
                        const ajv = schema_parser.share_ajv((ajv) => ajv);
13✔
554
                        const validator = ajv.compile(maybe);
13✔
555

13✔
556
                        return validator(data);
13✔
557
                }) as SchemaObject;
22✔
558

22✔
559
                const modified = SomethingOf.maybe_add_$defs(
22✔
560
                        schema,
22✔
561
                        sub_schema,
22✔
562
                );
22✔
563

22✔
564
                const result = schema_parser.maybe_parse<Type<unknown>>(
22✔
565
                        modified,
22✔
566
                        Type,
22✔
567
                );
22✔
568

22✔
569
                if (result) {
22✔
570
                        return [modified, result];
2✔
571
                }
2✔
572

8✔
573
                return [modified, schema_parser.parse(modified)];
8✔
574
        }
22✔
575

19✔
576
        static generate_schema_definition<
19✔
577
                Kind extends something_of_kind,
924✔
578
                Mode extends something_of_mode = something_of_mode,
924✔
579
                Choices extends schema_choices = schema_choices,
924✔
580
        >(
924✔
581
                {
924✔
582
                        kind,
924✔
583
                        choices,
924✔
584
                }: something_of_schema_options<Kind, Mode, Choices>,
924✔
585
        ): Readonly<something_of_schema<Kind, Mode, Choices>> {
924✔
586
                let result: something_of_schema<Kind, Mode, Choices>;
924✔
587

924✔
588
                if (
924✔
589
                        undefined === choices
924✔
590
                        || !SomethingOf.#is_const_schema_choices(choices)
924✔
591
                ) {
924✔
592
                        let properties: something_of_schema<
906✔
593
                                Kind,
906✔
594
                                'unspecified',
906✔
595
                                Choices
906✔
596
                        >['properties'];
906✔
597

906✔
598
                        if (kind === 'oneOf') {
906✔
599
                                const sanity_check: something_of_schema<
302✔
600
                                        'oneOf',
302✔
601
                                        'unspecified',
302✔
602
                                        Choices
302✔
603
                                >['properties'] = {
302✔
604
                                        $defs: {
302✔
605
                                                type: 'object',
302✔
606
                                                additionalProperties: {
302✔
607
                                                        type: 'object',
302✔
608
                                                },
302✔
609
                                        },
302✔
610
                                        oneOf: {
302✔
611
                                                type: 'array',
302✔
612
                                                minItems: 2,
302✔
613
                                                items: {
302✔
614
                                                        type: 'object',
302✔
615
                                                        minProperties: 1,
302✔
616
                                                        additionalProperties: {},
302✔
617
                                                },
302✔
618
                                        },
302✔
619
                                };
302✔
620

302✔
621
                                properties = sanity_check as typeof properties;
302✔
622
                        } else if ('allOf' === kind) {
906✔
623
                                const sanity_check: something_of_schema<
302✔
624
                                        'allOf',
302✔
625
                                        'unspecified',
302✔
626
                                        Choices
302✔
627
                                >['properties'] = {
302✔
628
                                        $defs: {
302✔
629
                                                type: 'object',
302✔
630
                                                additionalProperties: {
302✔
631
                                                        type: 'object',
302✔
632
                                                },
302✔
633
                                        },
302✔
634
                                        allOf: {
302✔
635
                                                type: 'array',
302✔
636
                                                minItems: 2,
302✔
637
                                                items: {
302✔
638
                                                        type: 'object',
302✔
639
                                                        minProperties: 1,
302✔
640
                                                        additionalProperties: {},
302✔
641
                                                },
302✔
642
                                        },
302✔
643
                                };
302✔
644

302✔
645
                                properties = sanity_check as typeof properties;
302✔
646
                        } else {
302✔
647
                                const sanity_check: something_of_schema<
302✔
648
                                        'anyOf',
302✔
649
                                        'unspecified',
302✔
650
                                        Choices
302✔
651
                                >['properties'] = {
302✔
652
                                        $defs: {
302✔
653
                                                type: 'object',
302✔
654
                                                additionalProperties: {
302✔
655
                                                        type: 'object',
302✔
656
                                                },
302✔
657
                                        },
302✔
658
                                        anyOf: {
302✔
659
                                                type: 'array',
302✔
660
                                                minItems: 2,
302✔
661
                                                items: {
302✔
662
                                                        type: 'object',
302✔
663
                                                        minProperties: 1,
302✔
664
                                                        additionalProperties: {},
302✔
665
                                                },
302✔
666
                                        },
302✔
667
                                };
302✔
668

302✔
669
                                properties = sanity_check as typeof properties;
302✔
670
                        }
302✔
671

906✔
672
                        const sanity_check: something_of_schema<
906✔
673
                                Kind,
906✔
674
                                'unspecified',
906✔
675
                                Choices
906✔
676
                        > = {
906✔
677
                                type: 'object',
906✔
678
                                additionalProperties: false,
906✔
679
                                required: [kind],
906✔
680
                                properties,
906✔
681
                        };
906✔
682

906✔
683
                        result = sanity_check as typeof result;
906✔
684
                } else {
924✔
685
                        let properties: something_of_schema<
18✔
686
                                Kind,
18✔
687
                                'specified',
18✔
688
                                Choices
18✔
689
                        >['properties'];
18✔
690

18✔
691
                        if (kind === 'oneOf') {
18✔
692
                                const sanity_check: something_of_schema<
6✔
693
                                        'oneOf',
6✔
694
                                        'specified',
6✔
695
                                        Choices
6✔
696
                                >['properties'] = {
6✔
697
                                        $defs: {
6✔
698
                                                type: 'object',
6✔
699
                                                additionalProperties: {
6✔
700
                                                        type: 'object',
6✔
701
                                                },
6✔
702
                                        },
6✔
703
                                        oneOf: {
6✔
704
                                                type: 'array',
6✔
705
                                                const: choices,
6✔
706
                                        },
6✔
707
                                };
6✔
708

6✔
709
                                properties = sanity_check as typeof properties;
6✔
710
                        } else if ('allOf' === kind) {
18✔
711
                                const sanity_check: something_of_schema<
6✔
712
                                        'allOf',
6✔
713
                                        'specified',
6✔
714
                                        Choices
6✔
715
                                >['properties'] = {
6✔
716
                                        $defs: {
6✔
717
                                                type: 'object',
6✔
718
                                                additionalProperties: {
6✔
719
                                                        type: 'object',
6✔
720
                                                },
6✔
721
                                        },
6✔
722
                                        allOf: {
6✔
723
                                                type: 'array',
6✔
724
                                                const: choices,
6✔
725
                                        },
6✔
726
                                };
6✔
727

6✔
728
                                properties = sanity_check as typeof properties;
6✔
729
                        } else {
6✔
730
                                const sanity_check: something_of_schema<
6✔
731
                                        'anyOf',
6✔
732
                                        'specified',
6✔
733
                                        Choices
6✔
734
                                >['properties'] = {
6✔
735
                                        $defs: {
6✔
736
                                                type: 'object',
6✔
737
                                                additionalProperties: {
6✔
738
                                                        type: 'object',
6✔
739
                                                },
6✔
740
                                        },
6✔
741
                                        anyOf: {
6✔
742
                                                type: 'array',
6✔
743
                                                const: choices,
6✔
744
                                        },
6✔
745
                                };
6✔
746

6✔
747
                                properties = sanity_check as typeof properties;
6✔
748
                        }
6✔
749

18✔
750
                        const sanity_check: something_of_schema<
18✔
751
                                Kind,
18✔
752
                                'specified',
18✔
753
                                schema_choices
18✔
754
                        > = {
18✔
755
                                type: 'object',
18✔
756
                                additionalProperties: false,
18✔
757
                                required: [kind],
18✔
758
                                properties,
18✔
759
                        };
18✔
760

18✔
761
                        result = sanity_check as typeof result;
18✔
762
                }
18✔
763

924✔
764
                return Object.freeze(result);
924✔
765
        }
924✔
766

19✔
767
        static generate_type_definition<
19✔
768
                Kind extends something_of_kind,
951✔
769
                Mode extends something_of_mode = something_of_mode,
951✔
770
                Choices extends type_choices = type_choices,
951✔
771
                Defs extends ObjectOfSchemas = ObjectOfSchemas,
951✔
772
        >(
951✔
773
                options: something_of_type_options<Kind, Mode, Choices, Defs>,
951✔
774
        ): Readonly<something_of_type<Kind, Mode, Choices, Defs>> {
951✔
775
                let result: something_of_type<Kind, Mode, Choices, Defs>;
951✔
776
                const {
951✔
777
                        kind,
951✔
778
                        choices,
951✔
779
                } = options;
951✔
780

951✔
781
                if ((choices || []).length < 2) {
951✔
782
                        const sanity_check: something_of_type<Kind, 'unspecified'> = {};
915✔
783

915✔
784
                        result = sanity_check as typeof result;
915✔
785
                } else {
951✔
786
                        if ('oneOf' === kind) {
36✔
787
                                const sanity_check: something_of_type<
12✔
788
                                        'oneOf',
12✔
789
                                        'specified',
12✔
790
                                        Choices,
12✔
791
                                        Defs
12✔
792
                                > = {oneOf: choices as Choices};
12✔
793

12✔
794
                                result = sanity_check as typeof result;
12✔
795
                        } else if ('allOf' === kind) {
36✔
796
                                const sanity_check: something_of_type<
12✔
797
                                        'allOf',
12✔
798
                                        'specified',
12✔
799
                                        Choices,
12✔
800
                                        Defs
12✔
801
                                > = {allOf: choices as Choices};
12✔
802

12✔
803
                                result = sanity_check as typeof result;
12✔
804
                        } else {
12✔
805
                                const sanity_check: something_of_type<
12✔
806
                                        'anyOf',
12✔
807
                                        'specified',
12✔
808
                                        Choices,
12✔
809
                                        Defs
12✔
810
                                > = {anyOf: choices as Choices};
12✔
811

12✔
812
                                result = sanity_check as typeof result;
12✔
813
                        }
12✔
814

36✔
815
                        if ('$defs' in options) {
36✔
816
                                result.$defs = options.$defs;
18✔
817
                        }
18✔
818
                }
36✔
819

951✔
820
                return Object.freeze(result);
951✔
821
        }
951✔
822

19✔
823
        static #is_allOf_schema(
19✔
824
                maybe: something_of_type<something_of_kind>,
12✔
825
        ): maybe is something_of_type<'allOf'> {
12✔
826
                return 'allOf' in maybe;
12✔
827
        }
12✔
828

19✔
829
        static #is_const_schema_choices<
19✔
830
                Choices extends schema_choices,
18✔
831
        >(
18✔
832
                maybe: never[]|Choices,
18✔
833
        ): maybe is Choices {
18✔
834
                return maybe.length >= 2;
18✔
835
        }
18✔
836

19✔
837
        static #is_non_empty_schema(
19✔
838
                maybe: something_of_type<something_of_kind>|Record<string, never>,
15✔
839
        ): maybe is something_of_type<something_of_kind> {
15✔
840
                return 0 !== Object.keys(maybe).length;
15✔
841
        }
15✔
842
}
19✔
843

19✔
844
export type {
19✔
845
        type_choices,
19✔
846
        something_of_kind,
19✔
847
        something_of_mode,
19✔
848
        something_of_type,
19✔
849
        something_of_type_options,
19✔
850
        schema_choices,
19✔
851
        something_of_schema_options,
19✔
852
};
19✔
853

19✔
854
export {
19✔
855
        SomethingOf,
19✔
856
};
19✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc