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

SignpostMarv / JSON-Schema-TypeScript-CodeGen / 18644002448

20 Oct 2025 06:21AM UTC coverage: 99.06% (-0.9%) from 100.0%
18644002448

push

github

SignpostMarv
negotiate external schemas

516 of 518 branches covered (99.61%)

Branch coverage included in aggregate %.

16 of 96 new or added lines in 2 files covered. (16.67%)

1 existing line in 1 file now uncovered.

8228 of 8309 relevant lines covered (99.03%)

599.12 hits per line

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

93.45
/src/JSONSchema/Object.ts
1
import type {
19✔
2
        IndexSignatureDeclaration,
19✔
3
        ObjectLiteralExpression,
19✔
4
        PropertySignature,
19✔
5
        TypeNode,
19✔
6
} from 'typescript';
19✔
7
import {
19✔
8
        SyntaxKind,
19✔
9
} from 'typescript';
19✔
10

19✔
11
import type {
19✔
12
        SchemaDefinitionDefinition,
19✔
13
        SchemaDefinitionDefinitionWith$defs,
19✔
14
        TypeDefinitionSchema,
19✔
15
        TypeOptions,
19✔
16
} from './Type.ts';
19✔
17
import {
19✔
18
        $defs_schema,
19✔
19
        Type,
19✔
20
} from './Type.ts';
19✔
21

19✔
22
import type {
19✔
23
        ExternalRef,
19✔
24
        LocalRef,
19✔
25
        pattern_either,
19✔
26
} from './Ref.ts';
19✔
27

19✔
28
import {
19✔
29
        $ref,
19✔
30
} from './Ref.ts';
19✔
31

19✔
32
import type {
19✔
33
        unknown_type,
19✔
34
} from './Unknown.ts';
19✔
35

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

19✔
43
import type {
19✔
44
        IntersectionTypeNode,
19✔
45
        TypeLiteralNode,
19✔
46
        TypeReferenceNode,
19✔
47
// eslint-disable-next-line imports/no-relative-parent-imports
19✔
48
} from '../typescript/types.ts';
19✔
49

19✔
50
import type {
19✔
51
        adjust_name_callback,
19✔
52
// eslint-disable-next-line imports/no-relative-parent-imports
19✔
53
} from '../coercions.ts';
19✔
54
import {
19✔
55
        adjust_name_default,
19✔
56
// eslint-disable-next-line imports/no-relative-parent-imports
19✔
57
} from '../coercions.ts';
19✔
58

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

19✔
64
import type {
19✔
65
        SchemaParser,
19✔
66
// eslint-disable-next-line imports/no-relative-parent-imports
19✔
67
} from '../SchemaParser.ts';
19✔
68

19✔
69
type object_properties_mode = (
19✔
70
        | 'neither'
19✔
71
        | 'both'
19✔
72
        | 'properties'
19✔
73
        | 'pattern'
19✔
74
);
19✔
75

19✔
76
type object_type<
19✔
77
        PropertiesMode extends object_properties_mode,
19✔
78
        Defs extends SchemaObject,
19✔
79
        Required extends readonly [string, ...string[]],
19✔
80
        Properties extends ObjectOfSchemas,
19✔
81
        PatternProperties extends ObjectOfSchemas,
19✔
82
> = (
19✔
83
        & {
19✔
84
                $defs?: Defs,
19✔
85
                $ref?: LocalRef|ExternalRef,
19✔
86
                type: 'object',
19✔
87
                required?: Required,
19✔
88
                unevaluatedProperties?: boolean,
19✔
89
        }
19✔
90
        & Omit<
19✔
91
                {
19✔
92
                        properties: Properties,
19✔
93
                        patternProperties: PatternProperties,
19✔
94
                },
19✔
95
                {
19✔
96
                        both: '',
19✔
97
                        neither: 'properties'|'patternProperties',
19✔
98
                        properties: 'patternProperties',
19✔
99
                        pattern: 'properties',
19✔
100
                }[PropertiesMode]
19✔
101
        >
19✔
102
);
19✔
103

19✔
104
type object_schema_required<
19✔
105
        PropertiesMode extends object_properties_mode,
19✔
106
> = (
19✔
107
        & readonly [string, ...string[]]
19✔
108
        & [
19✔
109
                'type',
19✔
110
                ...{
19✔
111
                        neither: readonly string[],
19✔
112
                        both: readonly ['properties', 'patternProperties'],
19✔
113
                        properties: readonly ['properties'],
19✔
114
                        pattern: readonly ['patternProperties'],
19✔
115
                }[PropertiesMode],
19✔
116
        ]
19✔
117
);
19✔
118

19✔
119
type object_schema<
19✔
120
        PropertiesMode extends object_properties_mode,
19✔
121
> = SchemaDefinitionDefinitionWith$defs<
19✔
122
        object_schema_required<PropertiesMode>,
19✔
123
        (
19✔
124
                & {
19✔
125
                        type: {
19✔
126
                                type: 'string',
19✔
127
                                const: 'object',
19✔
128
                        },
19✔
129
                        required: {
19✔
130
                                type: 'array',
19✔
131
                                minItems: 1,
19✔
132
                                items: {
19✔
133
                                        type: 'string',
19✔
134
                                        minLength: 1,
19✔
135
                                },
19✔
136
                        },
19✔
137
                        $ref: {
19✔
138
                                type: 'string',
19✔
139
                                pattern: pattern_either,
19✔
140
                        },
19✔
141
                        unevaluatedProperties: {
19✔
142
                                type: 'boolean',
19✔
143
                        },
19✔
144
                }
19✔
145
                & OmitIf<
19✔
146
                        {
19✔
147
                                properties: {
19✔
148
                                        type: 'object',
19✔
149
                                        minProperties: 1,
19✔
150
                                        additionalProperties: {
19✔
151
                                                type: 'object',
19✔
152
                                        },
19✔
153
                                },
19✔
154
                        },
19✔
155
                        'properties',
19✔
156
                        {
19✔
157
                                neither: 'without',
19✔
158
                                both: 'with',
19✔
159
                                properties: 'with',
19✔
160
                                pattern: 'without',
19✔
161
                        }[PropertiesMode]
19✔
162
                >
19✔
163
                & OmitIf<
19✔
164
                        {
19✔
165
                                patternProperties: {
19✔
166
                                        type: 'object',
19✔
167
                                        minProperties: 1,
19✔
168
                                        additionalProperties: {
19✔
169
                                                type: 'object',
19✔
170
                                        },
19✔
171
                                },
19✔
172
                        },
19✔
173
                        'patternProperties',
19✔
174
                        {
19✔
175
                                neither: 'without',
19✔
176
                                both: 'with',
19✔
177
                                properties: 'without',
19✔
178
                                pattern: 'with',
19✔
179
                        }[PropertiesMode]
19✔
180
                >
19✔
181
        )
19✔
182
>;
19✔
183

19✔
184
type object_TypeLiteralNode<
19✔
185
        PropertiesMode extends object_properties_mode,
19✔
186
> = {
19✔
187
        ['neither']: TypeLiteralNode<
19✔
188
                IndexSignatureDeclaration
19✔
189
        >,
19✔
190
        ['both']: IntersectionTypeNode<[
19✔
191
                TypeLiteralNode<PropertySignature>,
19✔
192
                TypeLiteralNode<IndexSignatureDeclaration>,
19✔
193
        ]>,
19✔
194
        ['properties']: TypeLiteralNode<PropertySignature>,
19✔
195
        ['pattern']: TypeLiteralNode<
19✔
196
                IndexSignatureDeclaration
19✔
197
        >,
19✔
198
}[PropertiesMode];
19✔
199

19✔
200
type ObjectUncertain_options<
19✔
201
        SchemaDefinition extends (
19✔
202
                SchemaDefinitionDefinition
19✔
203
        ) = (
19✔
204
                SchemaDefinitionDefinition
19✔
205
        ),
19✔
206
        TypeDefinition extends TypeDefinitionSchema = TypeDefinitionSchema,
19✔
207
> = (
19✔
208
        & Omit<
19✔
209
                TypeOptions<SchemaDefinition, TypeDefinition>,
19✔
210
                (
19✔
211
                        | 'schema_definition'
19✔
212
                        | 'type_definition'
19✔
213
                )
19✔
214
        >
19✔
215
);
19✔
216

19✔
217
class ObjectUnspecified<
19✔
218
        T extends {[key: string]: unknown},
19✔
219
        PropertiesMode extends object_properties_mode,
19✔
220
        Defs extends SchemaObject = SchemaObject,
19✔
221
        Required extends (
19✔
222
                readonly [string, ...string[]]
19✔
223
        ) = (
19✔
224
                readonly [string, ...string[]]
19✔
225
        ),
19✔
226
        Properties extends ObjectOfSchemas = ObjectOfSchemas,
19✔
227
        PatternProperties extends ObjectOfSchemas = ObjectOfSchemas,
19✔
228
> extends
19✔
229
        Type<
19✔
230
                T,
19✔
231
                object_type<
19✔
232
                        PropertiesMode,
19✔
233
                        Defs,
19✔
234
                        Required,
19✔
235
                        Properties,
19✔
236
                        PatternProperties
19✔
237
                >,
19✔
238
                {
19✔
239
                        properties_mode: PropertiesMode,
19✔
240
                        $defs?: Defs,
19✔
241
                        required?: Required,
19✔
242
                        properties?: Properties,
19✔
243
                        patternProperties?: PatternProperties,
19✔
244
                },
19✔
245
                object_schema<
19✔
246
                        PropertiesMode
19✔
247
                >,
19✔
248
                {
19✔
249
                        properties_mode: PropertiesMode,
19✔
250
                },
19✔
251
                (
19✔
252
                        | object_TypeLiteralNode<PropertiesMode>
19✔
253
                        | IntersectionTypeNode<[
19✔
254
                                TypeReferenceNode,
19✔
255
                                object_TypeLiteralNode<PropertiesMode>,
19✔
256
                        ]>
19✔
257
                ),
19✔
258
                ObjectLiteralExpression
19✔
259
        > {
19✔
260
        #adjust_name: adjust_name_callback;
19✔
261

817✔
262
        readonly properties_mode: PropertiesMode;
19✔
263

19✔
264
        constructor(
19✔
265
                options: {
817✔
266
                        adjust_name?: adjust_name_callback,
817✔
267
                        properties_mode: PropertiesMode,
817✔
268
                        $defs?: Defs,
817✔
269
                        required?: Required,
817✔
270
                        properties?: Properties,
817✔
271
                        patternProperties?: PatternProperties,
817✔
272
                },
817✔
273
                {
817✔
274
                        ajv,
817✔
275
                }: ObjectUncertain_options<
817✔
276
                        object_schema<
817✔
277
                                PropertiesMode
817✔
278
                        >,
817✔
279
                        object_type<
817✔
280
                                PropertiesMode,
817✔
281
                                Defs,
817✔
282
                                Required,
817✔
283
                                Properties,
817✔
284
                                PatternProperties
817✔
285
                        >
817✔
286
                >,
817✔
287
        ) {
817✔
288
                super({
817✔
289
                        ajv,
817✔
290
                        type_definition: options,
817✔
291
                        schema_definition: options,
817✔
292
                });
817✔
293

817✔
294
                this.#adjust_name = options?.adjust_name || adjust_name_default;
817✔
295
                this.properties_mode = options.properties_mode;
817✔
296
        }
817✔
297

19✔
298
        generate_typescript_data(
19✔
299
                data: T,
50✔
300
                schema_parser: SchemaParser,
50✔
301
                schema: object_type<
50✔
302
                        PropertiesMode,
50✔
303
                        Defs,
50✔
304
                        Required,
50✔
305
                        Properties,
50✔
306
                        PatternProperties
50✔
307
                >,
50✔
308
        ): ObjectLiteralExpression {
50✔
309
                return ObjectUnspecified.#createObjectLiteralExpression(
50✔
310
                        this.properties_mode,
50✔
311
                        data,
50✔
312
                        schema,
50✔
313
                        schema_parser,
50✔
314
                        this.#adjust_name,
50✔
315
                );
50✔
316
        }
50✔
317

19✔
318
        async generate_typescript_type(
19✔
319
                {
26✔
320
                        schema,
26✔
321
                        schema_parser,
26✔
322
                }: {
26✔
323
                        schema: object_type<
26✔
324
                                PropertiesMode,
26✔
325
                                Defs,
26✔
326
                                Required,
26✔
327
                                Properties,
26✔
328
                                PatternProperties
26✔
329
                        >,
26✔
330
                        schema_parser: SchemaParser,
26✔
331
                },
26✔
332
        ): Promise<(
26✔
333
                | object_TypeLiteralNode<PropertiesMode>
26✔
334
                | IntersectionTypeNode<[
26✔
335
                        TypeReferenceNode,
26✔
336
                        object_TypeLiteralNode<PropertiesMode>,
26✔
337
                ]>
26✔
338
        )> {
26✔
339
                let object_type: (
26✔
340
                        | Promise<object_TypeLiteralNode<PropertiesMode>>
26✔
341
                        | IntersectionTypeNode<[
26✔
342
                                TypeReferenceNode,
26✔
343
                                object_TypeLiteralNode<PropertiesMode>,
26✔
344
                        ]>
26✔
345
                ) = ObjectUnspecified.#createTypeNode(
26✔
346
                        this.properties_mode,
26✔
347
                        schema,
26✔
348
                        schema_parser,
26✔
349
                );
26✔
350

26✔
351
                if ('string' === typeof schema?.$ref) {
26✔
352
                        const $ref_instance = schema_parser.parse_by_type({
3✔
353
                                $ref: schema.$ref,
3✔
354
                        }, (maybe): maybe is $ref => $ref.is_a(maybe));
3✔
355

3✔
356
                        object_type = factory.createIntersectionTypeNode([
3✔
357
                                await $ref_instance.generate_typescript_type({
3✔
358
                                        schema: {
3✔
359
                                                $ref: schema.$ref,
3✔
360
                                        },
3✔
361
                                }),
3✔
362
                                await object_type,
3✔
363
                        ]);
3✔
364
                }
3✔
365

26✔
366
                return object_type;
26✔
367
        }
26✔
368

19✔
369
        static generate_schema_definition<
19✔
370
                PropertiesMode extends object_properties_mode,
821✔
371
        >({
821✔
372
                properties_mode,
821✔
373
        }: {
821✔
374
                properties_mode: PropertiesMode,
821✔
375
        }): Readonly<object_schema<
821✔
376
                PropertiesMode
821✔
377
        >> {
821✔
378
                const required_for_partial = (
821✔
379
                        this.#generate_schema_definition_required(
821✔
380
                                properties_mode,
821✔
381
                        )
821✔
382
                );
821✔
383

821✔
384
                const properties_for_partial: Partial<
821✔
385
                        object_schema<'both'>['properties']
821✔
386
                > = {
821✔
387
                        ...$defs_schema.properties,
821✔
388
                        type: {
821✔
389
                                type: 'string',
821✔
390
                                const: 'object',
821✔
391
                        },
821✔
392
                        $ref: {
821✔
393
                                type: 'string',
821✔
394
                                pattern: '^(.+)?#\\/\\$defs\\/(.+)$',
821✔
395
                        },
821✔
396
                        unevaluatedProperties: {
821✔
397
                                type: 'boolean',
821✔
398
                        },
821✔
399
                };
821✔
400

821✔
401
                properties_for_partial.required = {
821✔
402
                        type: 'array',
821✔
403
                        minItems: 1,
821✔
404
                        items: {
821✔
405
                                type: 'string',
821✔
406
                                minLength: 1,
821✔
407
                        },
821✔
408
                };
821✔
409

821✔
410
                if ('pattern' !== properties_mode && 'neither' !== properties_mode) {
821✔
411
                        const properties: (
417✔
412
                                object_schema<
417✔
413
                                        'properties'
417✔
414
                                >['properties']['properties']
417✔
415
                        ) = {
417✔
416
                                type: 'object',
417✔
417
                                minProperties: 1,
417✔
418
                                additionalProperties: {
417✔
419
                                        type: 'object',
417✔
420
                                },
417✔
421
                        };
417✔
422
                        properties_for_partial.properties = properties;
417✔
423
                }
417✔
424
                if (
821✔
425
                        'properties' !== properties_mode
821✔
426
                        && 'neither' !== properties_mode
821✔
427
                ) {
821✔
428
                        const properties: (
404✔
429
                                object_schema<
404✔
430
                                        'pattern'
404✔
431
                                >['properties']['patternProperties']
404✔
432
                        ) = {
404✔
433
                                type: 'object',
404✔
434
                                minProperties: 1,
404✔
435
                                additionalProperties: {
404✔
436
                                        type: 'object',
404✔
437
                                },
404✔
438
                        };
404✔
439
                        properties_for_partial.patternProperties = properties;
404✔
440
                }
404✔
441

821✔
442
                const unpartial_properties: object_schema<
821✔
443
                        PropertiesMode
821✔
444
                >['properties'] = properties_for_partial as object_schema<
821✔
445
                        PropertiesMode
821✔
446
                >['properties'];
821✔
447

821✔
448
                const partial_required: object_schema<
821✔
449
                        PropertiesMode
821✔
450
                >['required'] = required_for_partial;
821✔
451
                const partial_properties: object_schema<
821✔
452
                        PropertiesMode
821✔
453
                >['properties'] = unpartial_properties;
821✔
454

821✔
455
                const result: object_schema<
821✔
456
                        PropertiesMode
821✔
457
                > = {
821✔
458
                        type: 'object',
821✔
459
                        required: partial_required,
821✔
460
                        additionalProperties: false,
821✔
461
                        properties: partial_properties,
821✔
462
                } as object_schema<
821✔
463
                        PropertiesMode
821✔
464
                >;
821✔
465

821✔
466
                return Object.freeze(result);
821✔
467
        }
821✔
468

19✔
469
        static #generate_schema_definition_required<
19✔
470
                PropertiesMode extends object_properties_mode,
821✔
471
        >(
821✔
472
                properties_mode: PropertiesMode,
821✔
473
        ): object_schema<
821✔
474
                PropertiesMode
821✔
475
        >['required'] {
821✔
476
                const values_for_properties_mode: {
821✔
477
                        neither: readonly string[],
821✔
478
                        both: readonly ['properties', 'patternProperties'],
821✔
479
                        properties: readonly ['properties'],
821✔
480
                        pattern: readonly ['patternProperties'],
821✔
481
                }[PropertiesMode] = {
821✔
482
                        neither: [] as readonly string[],
821✔
483
                        both: ['properties', 'patternProperties'] as const,
821✔
484
                        properties: ['properties'] as const,
821✔
485
                        pattern: ['patternProperties'] as const,
821✔
486
                }[properties_mode];
821✔
487

821✔
488
                const required: object_schema<
821✔
489
                        PropertiesMode
821✔
490
                >['required'] = [
821✔
491
                        ...['type'],
821✔
492
                        ...values_for_properties_mode,
821✔
493
                ] as object_schema<
821✔
494
                        PropertiesMode
821✔
495
                >['required'];
821✔
496

821✔
497
                return required;
821✔
498
        }
821✔
499

19✔
500
        static generate_type_definition<
19✔
501
                PropertiesMode extends object_properties_mode,
817✔
502
                Defs extends SchemaObject,
817✔
503
                Required extends readonly [string, ...string[]],
817✔
504
                Properties extends ObjectOfSchemas,
817✔
505
                PatternProperties extends ObjectOfSchemas,
817✔
506
        >({
817✔
507
                properties_mode,
817✔
508
                $defs,
817✔
509
                required,
817✔
510
                properties,
817✔
511
                patternProperties,
817✔
512
        }: {
817✔
513
                properties_mode: PropertiesMode,
817✔
514
                $defs?: Defs,
817✔
515
                required?: Required,
817✔
516
                properties?: Properties,
817✔
517
                patternProperties?: PatternProperties,
817✔
518
        }): Readonly<object_type<
817✔
519
                PropertiesMode,
817✔
520
                Defs,
817✔
521
                Required,
817✔
522
                Properties,
817✔
523
                PatternProperties
817✔
524
        >> {
817✔
525
                const partial: Partial<object_type<
817✔
526
                        'both',
817✔
527
                        Defs,
817✔
528
                        Required,
817✔
529
                        Properties,
817✔
530
                        PatternProperties
817✔
531
                >> = {
817✔
532
                        type: 'object',
817✔
533
                };
817✔
534

817✔
535
                if ($defs) {
817✔
536
                        partial.$defs = $defs;
8✔
537
                }
8✔
538

817✔
539
                if (required) {
817✔
540
                        partial.required = required;
4✔
541
                }
4✔
542

817✔
543
                if ('both' === properties_mode || 'properties' === properties_mode) {
817✔
544
                        partial.properties = properties;
415✔
545
                }
415✔
546

817✔
547
                if (
817✔
548
                        'both' === properties_mode
817✔
549
                        || 'pattern' === properties_mode
817✔
550
                ) {
817✔
551
                        partial.patternProperties = patternProperties;
402✔
552
                }
402✔
553

817✔
554
                const frozen = Object.freeze(partial as object_type<
817✔
555
                        PropertiesMode,
817✔
556
                        Defs,
817✔
557
                        Required,
817✔
558
                        Properties,
817✔
559
                        PatternProperties
817✔
560
                >);
817✔
561

817✔
562
                return frozen;
817✔
563
        }
817✔
564

19✔
565
        static #is_schema_with_some_type_of_properties<
19✔
566
                Defs extends SchemaObject,
26✔
567
                Required extends readonly [string, ...string[]],
26✔
568
                Properties extends ObjectOfSchemas,
26✔
569
                PatternProperties extends ObjectOfSchemas,
26✔
570
        >(
26✔
571
                schema: object_type<
26✔
572
                        object_properties_mode,
26✔
573
                        Defs,
26✔
574
                        Required,
26✔
575
                        Properties,
26✔
576
                        PatternProperties
26✔
577
                >,
26✔
578
        ): schema is object_type<
26✔
579
                'both'|'properties'|'pattern',
26✔
580
                Defs,
26✔
581
                Required,
26✔
582
                Properties,
26✔
583
                PatternProperties
26✔
584
        > {
26✔
585
                return ('properties' in schema) || ('patternProperties' in schema);
26✔
586
        }
26✔
587

19✔
588
        static #is_schema_with_properties<
19✔
589
                Defs extends SchemaObject,
220✔
590
                Required extends readonly [string, ...string[]],
220✔
591
                Properties extends ObjectOfSchemas,
220✔
592
                PatternProperties extends ObjectOfSchemas,
220✔
593
        >(
220✔
594
                schema: object_type<
220✔
595
                        object_properties_mode,
220✔
596
                        Defs,
220✔
597
                        Required,
220✔
598
                        Properties,
220✔
599
                        PatternProperties
220✔
600
                >,
220✔
601
        ): schema is object_type<
220✔
602
                'both' | 'properties',
220✔
603
                Defs,
220✔
604
                Required,
220✔
605
                Properties,
220✔
606
                PatternProperties
220✔
607
        > {
220✔
608
                return 'properties' in schema;
220✔
609
        }
220✔
610

19✔
611
        static #is_schema_with_pattern_properties<
19✔
612
                Defs extends SchemaObject,
65✔
613
                Required extends readonly [string, ...string[]],
65✔
614
                Properties extends ObjectOfSchemas,
65✔
615
                PatternProperties extends ObjectOfSchemas,
65✔
616
        >(
65✔
617
                schema: object_type<
65✔
618
                        object_properties_mode,
65✔
619
                        Defs,
65✔
620
                        Required,
65✔
621
                        Properties,
65✔
622
                        PatternProperties
65✔
623
                >,
65✔
624
        ): schema is object_type<
65✔
625
                'both'|'pattern',
65✔
626
                Defs,
65✔
627
                Required,
65✔
628
                Properties,
65✔
629
                PatternProperties
65✔
630
        > {
65✔
631
                return 'patternProperties' in schema;
65✔
632
        }
65✔
633

19✔
634
        static #is_schema_with_required<
19✔
635
                Required extends readonly [string, ...string[]],
21✔
636
        >(
21✔
637
                schema: object_type<
21✔
638
                        object_properties_mode,
21✔
639
                        SchemaObject,
21✔
640
                        Required,
21✔
641
                        ObjectOfSchemas,
21✔
642
                        ObjectOfSchemas
21✔
643
                >,
21✔
644
        ): schema is object_type<
21✔
645
                object_properties_mode,
21✔
646
                SchemaObject,
21✔
647
                Required,
21✔
648
                ObjectOfSchemas,
21✔
649
                ObjectOfSchemas
21✔
650
        > & {required: Required} {
21✔
651
                return 'required' in schema;
21✔
652
        }
21✔
653

19✔
654
        static #convert<
19✔
655
                T,
77✔
656
                PropertiesMode extends object_properties_mode,
77✔
657
                Defs extends SchemaObject,
77✔
658
                Required extends readonly [string, ...string[]],
77✔
659
                Properties extends ObjectOfSchemas,
77✔
660
                PatternProperties extends ObjectOfSchemas,
77✔
661
        >(
77✔
662
                properties_mode: PropertiesMode,
77✔
663
                value: unknown,
77✔
664
                property: string,
77✔
665
                schema: object_type<
77✔
666
                        PropertiesMode,
77✔
667
                        Defs,
77✔
668
                        Required,
77✔
669
                        Properties,
77✔
670
                        PatternProperties
77✔
671
                >,
77✔
672
                schema_parser: SchemaParser,
77✔
673
        ) {
77✔
674
                const sub_schema = this.#sub_schema_for_property(
77✔
675
                        schema_parser,
77✔
676
                        properties_mode,
77✔
677
                        property,
77✔
678
                        schema,
77✔
679
                        {},
77✔
680
                );
77✔
681

77✔
682
                let maybe_modified = ObjectUnspecified.maybe_add_$defs(
77✔
683
                        schema,
77✔
684
                        sub_schema,
77✔
685
                );
77✔
686

77✔
687
                const ajv = schema_parser.share_ajv((ajv) => ajv);
77✔
688
                const validator = ajv.compile<T>(maybe_modified);
77✔
689

77✔
690
                if (!(validator(value))) {
77✔
691
                        throw new TypeError('Supplied value not supported by property!');
22✔
692
                }
22✔
693

54✔
694
                if (0 === Object.keys(sub_schema).length) {
77✔
695
                        maybe_modified = {
4✔
696
                                type: 'object',
4✔
697
                                additionalProperties: false,
4✔
698
                                maxProperties: 0,
4✔
699
                        };
4✔
700
                }
4✔
701

54✔
702
                return schema_parser.parse(
54✔
703
                        maybe_modified,
54✔
704
                ).generate_typescript_data(
54✔
705
                        value,
54✔
706
                        schema_parser,
54✔
707
                        maybe_modified,
54✔
708
                );
54✔
709
        }
77✔
710

19✔
711
        static #createObjectLiteralExpression<
19✔
712
                T extends {[key: string]: unknown},
50✔
713
                PropertiesMode extends object_properties_mode,
50✔
714
                Defs extends SchemaObject,
50✔
715
                Required extends readonly [string, ...string[]],
50✔
716
                Properties extends ObjectOfSchemas,
50✔
717
                PatternProperties extends ObjectOfSchemas,
50✔
718
        >(
50✔
719
                properties_mode: PropertiesMode,
50✔
720
                data: T,
50✔
721
                schema: object_type<
50✔
722
                        PropertiesMode,
50✔
723
                        Defs,
50✔
724
                        Required,
50✔
725
                        Properties,
50✔
726
                        PatternProperties
50✔
727
                >,
50✔
728
                schema_parser: SchemaParser,
50✔
729
                adjust_name: adjust_name_callback,
50✔
730
        ): ObjectLiteralExpression {
50✔
731
                return factory.createObjectLiteralExpression(
50✔
732
                        Object.entries(
50✔
733
                                data,
50✔
734
                        ).map(([
50✔
735
                                property,
77✔
736
                                value,
77✔
737
                        ]) => {
77✔
738
                                const type = this.#convert(
77✔
739
                                        properties_mode,
77✔
740
                                        value,
77✔
741
                                        property,
77✔
742
                                        schema,
77✔
743
                                        schema_parser,
77✔
744
                                );
77✔
745

77✔
746
                                return factory.createPropertyAssignment(
77✔
747
                                        adjust_name(property),
77✔
748
                                        type,
77✔
749
                                );
77✔
750
                        }),
50✔
751
                );
50✔
752
        }
50✔
753

19✔
754
        static async #createTypeNode<
19✔
755
                PropertiesMode extends object_properties_mode,
26✔
756
                Defs extends SchemaObject,
26✔
757
                Required extends readonly [string, ...string[]],
26✔
758
                Properties extends ObjectOfSchemas,
26✔
759
                PatternProperties extends ObjectOfSchemas,
26✔
760
        >(
26✔
761
                properties_mode: PropertiesMode,
26✔
762
                schema: object_type<
26✔
763
                        PropertiesMode,
26✔
764
                        Defs,
26✔
765
                        Required,
26✔
766
                        Properties,
26✔
767
                        PatternProperties
26✔
768
                >,
26✔
769
                schema_parser: SchemaParser,
26✔
770
        ): Promise<object_TypeLiteralNode<PropertiesMode>> {
26✔
771
                if (!this.#is_schema_with_some_type_of_properties(schema)) {
26✔
772
                        return factory.createTypeLiteralNode([
2✔
773
                                factory.createIndexSignature(
2✔
774
                                        undefined,
2✔
775
                                        [
2✔
776
                                                factory.createParameterDeclaration(
2✔
777
                                                        undefined,
2✔
778
                                                        undefined,
2✔
779
                                                        factory.createIdentifier('key'),
2✔
780
                                                        undefined,
2✔
781
                                                        factory.createToken(SyntaxKind.StringKeyword),
2✔
782
                                                ),
2✔
783
                                        ],
2✔
784
                                        factory.createToken(SyntaxKind.UnknownKeyword),
2✔
785
                                ),
2✔
786
                        ]) as object_TypeLiteralNode<PropertiesMode>;
2✔
787
                }
2✔
788

24✔
789
                let properties: PropertySignature[] = [];
24✔
790
                let patterned: [TypeNode, ...TypeNode[]]|never[] = [];
24✔
791

24✔
792
                if (this.#is_schema_with_properties(schema)) {
26✔
793
                        properties = await Promise.all(Object.keys(
20✔
794
                                schema.properties,
20✔
795
                        ).map(async (
20✔
796
                                property,
21✔
797
                        ): Promise<PropertySignature> => factory.createPropertySignature(
21✔
798
                                undefined,
21✔
799
                                (
21✔
800
                                        /[?[\] ]/.test(property)
21✔
801
                                                ? factory.createComputedPropertyName(
21✔
802
                                                        factory.createStringLiteral(property),
2✔
803
                                                )
2✔
804
                                                : property
21✔
805
                                ),
21✔
806
                                (
21✔
807
                                        (
21✔
808
                                                this.#is_schema_with_required(schema)
21✔
809
                                                && schema.required.includes(property)
21✔
810
                                        )
21✔
811
                                                ? undefined
21✔
812
                                                : factory.createToken(SyntaxKind.QuestionToken)
21✔
813
                                ),
21✔
814
                                await this.#generate_type(
21✔
815
                                        properties_mode,
21✔
816
                                        property,
21✔
817
                                        schema,
21✔
818
                                        schema_parser,
21✔
819
                                ),
21✔
820
                        )));
20✔
821
                }
20✔
822

24✔
823
                if (this.#is_schema_with_pattern_properties(schema)) {
26✔
824
                        patterned = await Promise.all(
6✔
825
                                (
6✔
826
                                        Object.values(
6✔
827
                                                schema.patternProperties,
6✔
828
                                        )
6✔
829
                                ).map(
6✔
830
                                        (sub_schema) => {
6✔
831
                                                return schema_parser.parse(
10✔
832
                                                        ObjectUnspecified.maybe_add_$defs(
10✔
833
                                                                schema,
10✔
834
                                                                sub_schema,
10✔
835
                                                        ),
10✔
836
                                                ).generate_typescript_type({
10✔
837
                                                        data: sub_schema,
10✔
838
                                                        schema: sub_schema,
10✔
839
                                                        schema_parser,
10✔
840
                                                });
10✔
841
                                        },
6✔
842
                                ),
6✔
843
                        );
6✔
844
                }
6✔
845

24✔
846
                let result: object_TypeLiteralNode<
24✔
847
                        Exclude<
24✔
848
                                object_properties_mode,
24✔
849
                                'neither'
24✔
850
                        >
24✔
851
                >;
24✔
852

24✔
853
                if (properties.length > 0 && patterned.length > 0) {
26✔
854
                        result = factory.createIntersectionTypeNode([
2✔
855
                                factory.createTypeLiteralNode(properties),
2✔
856
                                this.#patterned_literal_node(
2✔
857
                                        patterned as [TypeNode, ...TypeNode[]],
2✔
858
                                ),
2✔
859
                        ]);
2✔
860
                } else if (properties.length > 0) {
26✔
861
                        result = factory.createTypeLiteralNode(properties);
18✔
862
                } else {
22✔
863
                        result = this.#patterned_literal_node(
4✔
864
                                patterned as [TypeNode, ...TypeNode[]],
4✔
865
                        );
4✔
866
                }
4✔
867

24✔
868
                return result as object_TypeLiteralNode<PropertiesMode>;
24✔
869
        }
26✔
870

19✔
871
        static async #generate_type<
19✔
872
                PropertiesMode extends object_properties_mode,
21✔
873
                Defs extends SchemaObject,
21✔
874
                Required extends readonly [string, ...string[]],
21✔
875
                Properties extends ObjectOfSchemas,
21✔
876
                PatternProperties extends ObjectOfSchemas,
21✔
877
        >(
21✔
878
                properties_mode: PropertiesMode,
21✔
879
                property: string,
21✔
880
                schema: object_type<
21✔
881
                        PropertiesMode,
21✔
882
                        Defs,
21✔
883
                        Required,
21✔
884
                        Properties,
21✔
885
                        PatternProperties
21✔
886
                >,
21✔
887
                schema_parser: SchemaParser,
21✔
888
        ) {
21✔
889
                const sub_schema = this.#sub_schema_for_property(
21✔
890
                        schema_parser,
21✔
891
                        properties_mode,
21✔
892
                        property,
21✔
893
                        schema,
21✔
894
                        {},
21✔
895
                );
21✔
896

21✔
897
                let matched: (
21✔
898
                        | undefined
21✔
899
                        | Type<unknown>
21✔
900
                ) = schema_parser.maybe_parse_by_type<
21✔
901
                        $ref
21✔
902
                >(
21✔
903
                        sub_schema,
21✔
904
                        (
21✔
905
                                maybe: unknown,
98✔
906
                        ): maybe is $ref => {
98✔
907
                                return $ref.is_a(maybe);
98✔
908
                        },
21✔
909
                );
21✔
910

21✔
911
                if (undefined === matched) {
21✔
912
                        matched = schema_parser.parse(sub_schema);
11✔
913
                } else {
21✔
914
                        return matched.generate_typescript_type({
10✔
915
                                data: sub_schema,
10✔
916
                                schema: sub_schema,
10✔
917
                                schema_parser,
10✔
918
                        });
10✔
919
                }
10✔
920

11✔
921
                return matched.generate_typescript_type({
11✔
922
                        schema: sub_schema,
11✔
923
                        schema_parser,
11✔
924
                });
11✔
925
        }
21✔
926

19✔
927
        static #patterned_literal_node(
19✔
928
                value: [TypeNode, ...TypeNode[]],
6✔
929
        ): TypeLiteralNode<IndexSignatureDeclaration> {
6✔
930
                return factory.createTypeLiteralNode([
6✔
931
                        factory.createIndexSignature(
6✔
932
                                undefined,
6✔
933
                                [
6✔
934
                                        factory.createParameterDeclaration(
6✔
935
                                                undefined,
6✔
936
                                                undefined,
6✔
937
                                                'key',
6✔
938
                                                undefined,
6✔
939
                                                factory.createKeywordTypeNode(
6✔
940
                                                        SyntaxKind.StringKeyword,
6✔
941
                                                ),
6✔
942
                                                undefined,
6✔
943
                                        ),
6✔
944
                                ],
6✔
945
                                1 === value.length
6✔
946
                                        ? value[0]
6✔
947
                                        : factory.createUnionTypeNode(
6✔
948
                                                value as [TypeNode, TypeNode, ...TypeNode[]],
4✔
949
                                        ),
6✔
950
                        ),
6✔
951
                ]);
6✔
952
        }
6✔
953

19✔
954
        static #sub_schema_for_property<
19✔
955
                PropertiesMode extends object_properties_mode,
98✔
956
                Defs extends SchemaObject,
98✔
957
                Required extends readonly [string, ...string[]],
98✔
958
                Properties extends ObjectOfSchemas,
98✔
959
                PatternProperties extends ObjectOfSchemas,
98✔
960
        >(
98✔
961
                schema_parser: SchemaParser,
98✔
962
                properties_mode: PropertiesMode,
98✔
963
                property: string,
98✔
964
                schema: object_type<
98✔
965
                        PropertiesMode,
98✔
966
                        Defs,
98✔
967
                        Required,
98✔
968
                        Properties,
98✔
969
                        PatternProperties
98✔
970
                >,
98✔
971
                fallback_if_neither: Record<string, never>|unknown_type,
98✔
972
        ): SchemaObject {
98✔
973
                if (
98✔
974
                        this.#is_schema_with_properties(schema)
98✔
975
                        && !(property in schema.properties)
98✔
976
                        && 'string' === typeof schema?.$ref
98✔
977
                        && !schema.$ref.startsWith('#/$defs/')
98!
978
                ) {
98!
NEW
979
                        let checking_schema: (
×
NEW
980
                                | SchemaObject
×
NEW
981
                                | undefined
×
NEW
982
                        ) = schema;
×
NEW
983

×
NEW
984
                        while (
×
NEW
985
                                undefined !== checking_schema
×
NEW
986
                                && !(property in checking_schema.properties)
×
NEW
987
                                && 'string' === typeof checking_schema.$ref
×
NEW
988
                        ) {
×
NEW
989
                                if (!checking_schema.$ref.startsWith('#/$defs/')) {
×
NEW
990
                                        const [
×
NEW
991
                                                other_schema_id,
×
NEW
992
                                                other_schema_ref_id,
×
NEW
993
                                        ] = checking_schema.$ref.split(
×
NEW
994
                                                '#/$defs/',
×
NEW
995
                                        ) as [string, string];
×
NEW
996

×
NEW
997
                                        const other_schema = schema_parser.get_schema(
×
NEW
998
                                                other_schema_id,
×
NEW
999
                                        );
×
NEW
1000

×
NEW
1001
                                        if (
×
NEW
1002
                                                other_schema
×
NEW
1003
                                                && '$defs' in other_schema
×
NEW
1004
                                                && undefined !== other_schema.$defs
×
NEW
1005
                                                && other_schema_ref_id in other_schema.$defs
×
NEW
1006
                                        ) {
×
NEW
1007
                                                checking_schema = this.maybe_add_$defs(
×
NEW
1008
                                                        other_schema,
×
NEW
1009
                                                        other_schema.$defs[other_schema_ref_id],
×
NEW
1010
                                                );
×
NEW
1011
                                        } else {
×
NEW
1012
                                                checking_schema = undefined;
×
NEW
1013
                                        }
×
NEW
1014
                                } else {
×
NEW
1015
                                        const $ref_id = checking_schema.$ref.split('#/$defs/')[1];
×
NEW
1016

×
NEW
1017
                                        if (
×
NEW
1018
                                                '$defs' in checking_schema
×
NEW
1019
                                                && undefined !== checking_schema.$defs
×
NEW
1020
                                                && $ref_id in checking_schema.$defs
×
NEW
1021
                                        ) {
×
NEW
1022
                                                checking_schema = this.maybe_add_$defs(
×
NEW
1023
                                                        checking_schema,
×
NEW
1024
                                                        checking_schema.$defs[$ref_id],
×
NEW
1025
                                                );
×
NEW
1026
                                        } else {
×
NEW
1027
                                                checking_schema = undefined;
×
NEW
1028
                                        }
×
NEW
1029
                                }
×
NEW
1030
                        }
×
NEW
1031

×
NEW
1032
                        if (checking_schema !== undefined) {
×
NEW
1033
                                const maybe_type = schema_parser.parse_by_type<
×
NEW
1034
                                        ObjectUnspecified<
×
NEW
1035
                                                {[key: string]: unknown},
×
NEW
1036
                                                'properties'
×
NEW
1037
                                        >
×
NEW
1038
                                >(
×
NEW
1039
                                        checking_schema,
×
NEW
1040
                                        (maybe): maybe is ObjectUnspecified<
×
NEW
1041
                                                {[key: string]: unknown},
×
NEW
1042
                                                'properties'
×
NEW
1043
                                        > => ObjectUnspecified.is_a<ObjectUnspecified<
×
NEW
1044
                                                {[key: string]: unknown},
×
NEW
1045
                                                'properties'
×
NEW
1046
                                        >>(maybe) && 'properties' === maybe.properties_mode,
×
NEW
1047
                                );
×
NEW
1048

×
NEW
1049
                                if (maybe_type && maybe_type.check_type(checking_schema)) {
×
NEW
1050
                                        schema = checking_schema as typeof schema;
×
NEW
1051
                                }
×
NEW
1052
                        }
×
NEW
1053
                }
×
1054

98✔
1055
                if (
98✔
1056
                        this.#is_schema_with_properties(schema)
98✔
1057
                        && property in schema.properties
98✔
1058
                        && undefined !== schema.properties[property]
98✔
1059
                ) {
98✔
1060
                        return schema.properties[property];
57✔
1061
                }
57✔
1062

41✔
1063
                if (
41✔
1064
                        this.#is_schema_with_pattern_properties(schema)
41✔
1065
                ) {
95✔
1066
                        const matching = Object.keys(
36✔
1067
                                schema.patternProperties,
36✔
1068
                        ).find((maybe) => {
36✔
1069
                                return (
52✔
1070
                                        (new RegExp(maybe)).test(property)
52✔
1071
                                        && undefined !== schema.patternProperties[maybe]
52✔
1072
                                );
52✔
1073
                        });
36✔
1074

36✔
1075
                        if (matching) {
36✔
1076
                                return schema.patternProperties[matching];
36✔
1077
                        }
36✔
1078
                }
36✔
1079

5✔
1080
                if ('neither' === properties_mode) {
95✔
1081
                        return fallback_if_neither;
4✔
1082
                }
4✔
1083

1✔
1084
                throw new TypeError(
1✔
1085
                        `Property "${property}" has no match on the specified schema!`,
1✔
1086
                );
1✔
1087
        }
98✔
1088
}
19✔
1089

19✔
1090
export type {
19✔
1091
        object_properties_mode,
19✔
1092
        object_type,
19✔
1093
        object_schema,
19✔
1094
        object_TypeLiteralNode,
19✔
1095
};
19✔
1096

19✔
1097
export {
19✔
1098
        ObjectUnspecified,
19✔
1099
};
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