11import type { SuperStruct } from '$lib/superStruct.js' ;
22import type { JSONSchema } from './index.js' ;
33import { schemaInfo , type SchemaInfo } from './schemaInfo.js' ;
4+ import { merge as deepMerge } from 'ts-deepmerge' ;
45
56export type InputConstraint = Partial < {
67 pattern : string ; // RegExp
@@ -21,14 +22,12 @@ export function constraints<T extends Record<string, unknown>>(
2122}
2223
2324function merge < T extends Record < string , unknown > > (
24- constraints : ( InputConstraints < T > | InputConstraint | undefined ) [ ]
25+ ... constraints : ( InputConstraints < T > | InputConstraint | undefined ) [ ]
2526) : ReturnType < typeof _constraints > {
26- let output = { } ;
27- for ( const constraint of constraints ) {
28- if ( ! constraint ) continue ;
29- output = { ...output , ...constraint } ;
30- }
31- return output ;
27+ const filtered = constraints . filter ( ( c ) => ! ! c ) ;
28+ if ( ! filtered . length ) return undefined ;
29+ if ( filtered . length == 1 ) return filtered [ 0 ] ;
30+ return deepMerge ( ...( filtered as Record < string , unknown > [ ] ) ) ;
3231}
3332
3433function _constraints < T extends Record < string , unknown > > (
@@ -37,34 +36,34 @@ function _constraints<T extends Record<string, unknown>>(
3736) : InputConstraints < T > | InputConstraint | undefined {
3837 if ( ! info ) return undefined ;
3938
39+ let output : Record < string , unknown > | undefined = undefined ;
40+
4041 // Union
41- if ( info . union ) {
42+ if ( info . union && info . union . length ) {
4243 const infos = info . union . map ( ( s ) => schemaInfo ( s , info . isOptional , path ) ) ;
4344 const merged = infos . map ( ( i ) => _constraints ( i , path ) ) ;
44- const output = merge ( merged ) ;
45+ output = merge ( output , ...merged ) ;
46+
4547 // Delete required if any part of the union is optional
4648 if (
4749 output &&
4850 ( info . isNullable || info . isOptional || infos . some ( ( i ) => i ?. isNullable || i ?. isOptional ) )
4951 ) {
5052 delete output . required ;
5153 }
52- return output && Object . values ( output ) . length ? output : undefined ;
5354 }
5455
5556 // Arrays
5657 if ( info . array ) {
57- if ( info . array . length == 1 ) {
58- //console.log('Array constraint', schema, path);
59- return _constraints ( schemaInfo ( info . array [ 0 ] , info . isOptional , path ) , path ) ;
60- }
61-
62- return merge ( info . array . map ( ( i ) => _constraints ( schemaInfo ( i , info . isOptional , path ) , path ) ) ) ;
58+ output = merge (
59+ output ,
60+ ...info . array . map ( ( i ) => _constraints ( schemaInfo ( i , info . isOptional , path ) , path ) )
61+ ) ;
6362 }
6463
6564 // Objects
6665 if ( info . properties ) {
67- const output : Record < string , unknown > = { } ;
66+ const obj = { } as Record < string , unknown > ;
6867 for ( const [ key , prop ] of Object . entries ( info . properties ) ) {
6968 const propInfo = schemaInfo (
7069 prop ,
@@ -74,13 +73,13 @@ function _constraints<T extends Record<string, unknown>>(
7473 const propConstraint = _constraints ( propInfo , [ ...path , key ] ) ;
7574
7675 if ( typeof propConstraint === 'object' && Object . values ( propConstraint ) . length > 0 ) {
77- output [ key ] = propConstraint ;
76+ obj [ key ] = propConstraint ;
7877 }
7978 }
80- return output ;
79+ output = merge ( output , obj ) ;
8180 }
8281
83- return constraint ( info ) ;
82+ return output ?? constraint ( info ) ;
8483}
8584
8685function constraint ( info : SchemaInfo ) : InputConstraint | undefined {
0 commit comments