@@ -30,71 +30,23 @@ THE SOFTWARE.
3030
3131import { IsDefault } from '../../schema/types/index.ts'
3232
33- import { type TProperties , type TSchema , type TUnion , Union , IsLiteral , IsObject , IsRef } from '../../type/index.ts'
33+ import { type TProperties , type TUnion , Union } from '../../type/index.ts'
3434import { Flatten } from '../../type/engine/evaluate/index.ts'
35- import { Guard } from '../../guard/index.ts'
3635import { Check } from '../check/index.ts'
3736import { Clone } from '../clone/index.ts'
3837import { Create } from '../create/index.ts'
39- import { RepairError } from './error.ts'
4038import { FromType } from './from-type.ts'
4139
42- // ------------------------------------------------------------------
43- // Deref
44- // ------------------------------------------------------------------
45- function Deref ( context : TProperties , type : TSchema , value : unknown ) : TSchema {
46- return IsRef ( type )
47- ? Guard . HasPropertyKey ( context , type . $ref )
48- ? Deref ( context , context [ type . $ref ] , value )
49- : ( ( ) => { throw new RepairError ( context , type , value , 'Unable to Deref target on Union repair' ) } ) ( )
50- : type
51- }
40+ import { UnionScoreSelect } from '../shared/union-score-select.ts'
5241
53- // ------------------------------------------------------------------
54- // The following will score a schema against a value. For objects,
55- // the score is the tally of points awarded for each property of
56- // the value. Property points are (1.0 / propertyCount) to prevent
57- // large property counts biasing results. Properties that match
58- // literal values are maximally awarded as literals are typically
59- // used as union discriminator fields.
60- // ------------------------------------------------------------------
61- function ScoreVariant ( context : TProperties , type : TSchema , value : unknown ) : number {
62- // scoring is only possible for object types.
63- if ( ! ( IsObject ( type ) && Guard . IsObject ( value ) ) ) return 0
64-
65- const keys = Guard . Keys ( value )
66- const entries = Guard . Entries ( type . properties )
67- return entries . reduce ( ( result , [ key , schema ] ) => {
68- const literal = IsLiteral ( schema ) && Guard . IsEqual ( schema . const , value [ key ] ) ? 100 : 0
69- const checks = Check ( context , schema , value [ key ] ) ? 10 : 0
70- const exists = keys . includes ( key ) ? 1 : 0
71- return result + ( literal + checks + exists )
72- } , 0 )
73- }
74- // ------------------------------------------------------------------
75- // SelectVariant
76- // ------------------------------------------------------------------
77- function SelectVariant ( context : TProperties , type : TUnion , value : unknown ) : TSchema {
78- const schemas = type . anyOf . map ( ( schema ) => Deref ( context , schema , value ) )
79- let [ select , best ] = [ schemas [ 0 ] , 0 ]
80- for ( const schema of schemas ) {
81- const score = ScoreVariant ( context , schema , value )
82- if ( score > best ) {
83- select = schema
84- best = score
85- }
86- }
87- return select
88- }
8942// ------------------------------------------------------------------
9043// RepairUnion
9144// ------------------------------------------------------------------
9245function RepairUnion ( context : TProperties , type : TUnion , value : unknown ) : unknown {
9346 const union = Union ( Flatten ( type . anyOf ) )
94- const schema = SelectVariant ( context , union , value )
47+ const schema = UnionScoreSelect ( context , union , value )
9548 return FromType ( context , schema , value )
9649}
97-
9850export function FromUnion ( context : TProperties , type : TUnion , value : unknown ) : unknown {
9951 if ( Check ( context , type , value ) ) return Clone ( value )
10052 if ( IsDefault ( type ) ) return Create ( context , type )
0 commit comments