@@ -28,28 +28,70 @@ THE SOFTWARE.
2828
2929// deno-fmt-ignore-file
3030
31- import { Guard } from '../../guard/index.ts'
32- import { type TIntersect , type TProperties } from '../../type/index.ts'
31+ import { Guard , } from '../../guard/index.ts'
32+ import { type TIntersect , type TProperties , type TSchema , IsObject , IsOptional } from '../../type/index.ts'
3333import { FromType } from './from-type.ts'
3434import { Callback } from './callback.ts'
3535
36+ // ------------------------------------------------------------------
37+ // ProcessIntersectSchemas
38+ // ------------------------------------------------------------------
39+ // Processes intersection schemas while tracking which properties have been
40+ // handled to prevent duplicate codec execution. When the same property appears
41+ // in multiple schemas within an intersection, only the first occurrence is
42+ // processed to avoid running codecs multiple times.
43+ function ProcessIntersectSchemas (
44+ direction : string ,
45+ context : TProperties ,
46+ schemas : TSchema [ ] ,
47+ value : unknown
48+ ) : unknown {
49+ const nonProcessedKeys = new Set < string > ( )
50+
51+ // make sure we don't process optional undefined values
52+ for ( const schema of schemas ) {
53+ if ( ! IsObject ( schema ) || ! Guard . IsObjectNotArray ( value ) ) continue ;
54+ for ( const key of Guard . Keys ( schema . properties ) ) {
55+ if ( nonProcessedKeys . has ( key ) ) continue
56+ if ( ! Guard . IsUndefined ( value [ key ] ) || ! IsOptional ( schema . properties [ key ] ) ) {
57+ nonProcessedKeys . add ( key )
58+ }
59+ }
60+ }
61+
62+ for ( const schema of schemas ) {
63+ if ( IsObject ( schema ) ) {
64+ // For object schemas, manually process properties that haven't been seen yet
65+ if ( ! Guard . IsObjectNotArray ( value ) ) continue
66+
67+ for ( const key of Guard . Keys ( schema . properties ) ) {
68+ if ( nonProcessedKeys . has ( key ) && Guard . HasPropertyKey ( value , key ) ) {
69+ // Process this property through its codec
70+ value [ key ] = FromType ( direction , context , schema . properties [ key ] , value [ key ] )
71+ nonProcessedKeys . delete ( key )
72+ }
73+ }
74+ } else {
75+ // For non-object schemas, process the entire value
76+ value = FromType ( direction , context , schema , value )
77+ }
78+ }
79+
80+ return value
81+ }
3682// ------------------------------------------------------------------
3783// Decode
3884// ------------------------------------------------------------------
3985function Decode ( direction : string , context : TProperties , type : TIntersect , value : unknown ) : unknown {
40- for ( const schema of type . allOf ) {
41- value = FromType ( direction , context , schema , value )
42- }
86+ value = ProcessIntersectSchemas ( direction , context , type . allOf , value )
4387 return Callback ( direction , context , type , value )
4488}
4589// ------------------------------------------------------------------
4690// Encode
4791// ------------------------------------------------------------------
4892function Encode ( direction : string , context : TProperties , type : TIntersect , value : unknown ) : unknown {
4993 let exterior = Callback ( direction , context , type , value )
50- for ( const schema of type . allOf ) {
51- exterior = FromType ( direction , context , schema , exterior )
52- }
94+ exterior = ProcessIntersectSchemas ( direction , context , type . allOf , exterior )
5395 return exterior
5496}
5597export function FromIntersect ( direction : string , context : TProperties , type : TIntersect , value : unknown ) : unknown {
0 commit comments