@@ -247,49 +247,6 @@ const defaultMethods = {
247247 xor : ( [ a , b ] ) => a ^ b ,
248248 // Why "executeInLoop"? Because if it needs to execute to get an array, I do not want to execute the arguments,
249249 // Both for performance and safety reasons.
250- '??' : {
251- [ Sync ] : ( data , buildState ) => isSyncDeep ( data , buildState . engine , buildState ) ,
252- method : ( arr , _1 , _2 , engine ) => {
253- // See "executeInLoop" above
254- const executeInLoop = Array . isArray ( arr )
255- if ( ! executeInLoop ) arr = engine . run ( arr , _1 , { above : _2 } )
256-
257- let item
258- for ( let i = 0 ; i < arr . length ; i ++ ) {
259- item = executeInLoop ? engine . run ( arr [ i ] , _1 , { above : _2 } ) : arr [ i ]
260- if ( downgrade ( item ) !== null && item !== undefined ) return item
261- }
262-
263- if ( item === undefined ) return null
264- return item
265- } ,
266- asyncMethod : async ( arr , _1 , _2 , engine ) => {
267- // See "executeInLoop" above
268- const executeInLoop = Array . isArray ( arr )
269- if ( ! executeInLoop ) arr = await engine . run ( arr , _1 , { above : _2 } )
270-
271- let item
272- for ( let i = 0 ; i < arr . length ; i ++ ) {
273- item = executeInLoop ? await engine . run ( arr [ i ] , _1 , { above : _2 } ) : arr [ i ]
274- if ( downgrade ( item ) !== null && item !== undefined ) return item
275- }
276-
277- if ( item === undefined ) return null
278- return item
279- } ,
280- deterministic : ( data , buildState ) => isDeterministic ( data , buildState . engine , buildState ) ,
281- compile : ( data , buildState ) => {
282- if ( ! chainingSupported ) return false
283- if ( Array . isArray ( data ) && data . length ) {
284- return `(${ data . map ( ( i , x ) => {
285- if ( Array . isArray ( i ) || ! i || typeof i !== 'object' || x === data . length - 1 ) return buildString ( i , buildState )
286- return 'downgrade(' + buildString ( i , buildState ) + ')'
287- } ) . join ( ' ?? ' ) } )`
288- }
289- return `(${ buildString ( data , buildState ) } ).reduce((a,b) => downgrade(a) ?? b, null)`
290- } ,
291- traverse : false
292- } ,
293250 or : {
294251 [ Sync ] : ( data , buildState ) => isSyncDeep ( data , buildState . engine , buildState ) ,
295252 method : ( arr , _1 , _2 , engine ) => {
@@ -326,6 +283,8 @@ const defaultMethods = {
326283 } ,
327284 traverse : false
328285 } ,
286+ '??' : defineCoalesce ( ) ,
287+ try : defineCoalesce ( downgrade ) ,
329288 and : {
330289 [ Sync ] : ( data , buildState ) => isSyncDeep ( data , buildState . engine , buildState ) ,
331290 method : ( arr , _1 , _2 , engine ) => {
@@ -719,6 +678,60 @@ const defaultMethods = {
719678 }
720679}
721680
681+ /**
682+ * Defines separate coalesce methods
683+ */
684+ function defineCoalesce ( func ) {
685+ let downgrade
686+ if ( func ) downgrade = func
687+ else downgrade = ( a ) => a
688+
689+ return {
690+ [ Sync ] : ( data , buildState ) => isSyncDeep ( data , buildState . engine , buildState ) ,
691+ method : ( arr , _1 , _2 , engine ) => {
692+ // See "executeInLoop" above
693+ const executeInLoop = Array . isArray ( arr )
694+ if ( ! executeInLoop ) arr = engine . run ( arr , _1 , { above : _2 } )
695+
696+ let item
697+ for ( let i = 0 ; i < arr . length ; i ++ ) {
698+ item = executeInLoop ? engine . run ( arr [ i ] , _1 , { above : _2 } ) : arr [ i ]
699+ if ( downgrade ( item ) !== null && item !== undefined ) return item
700+ }
701+
702+ if ( item === undefined ) return null
703+ return item
704+ } ,
705+ asyncMethod : async ( arr , _1 , _2 , engine ) => {
706+ // See "executeInLoop" above
707+ const executeInLoop = Array . isArray ( arr )
708+ if ( ! executeInLoop ) arr = await engine . run ( arr , _1 , { above : _2 } )
709+
710+ let item
711+ for ( let i = 0 ; i < arr . length ; i ++ ) {
712+ item = executeInLoop ? await engine . run ( arr [ i ] , _1 , { above : _2 } ) : arr [ i ]
713+ if ( downgrade ( item ) !== null && item !== undefined ) return item
714+ }
715+
716+ if ( item === undefined ) return null
717+ return item
718+ } ,
719+ deterministic : ( data , buildState ) => isDeterministic ( data , buildState . engine , buildState ) ,
720+ compile : ( data , buildState ) => {
721+ if ( ! chainingSupported ) return false
722+ const funcCall = func ? 'downgrade' : ''
723+ if ( Array . isArray ( data ) && data . length ) {
724+ return `(${ data . map ( ( i , x ) => {
725+ if ( Array . isArray ( i ) || ! i || typeof i !== 'object' || x === data . length - 1 ) return buildString ( i , buildState )
726+ return `${ funcCall } (` + buildString ( i , buildState ) + ')'
727+ } ) . join ( ' ?? ' ) } )`
728+ }
729+ return `(${ buildString ( data , buildState ) } ).reduce((a,b) => ${ funcCall } (a) ?? b, null)`
730+ } ,
731+ traverse : false
732+ }
733+ }
734+
722735function createArrayIterativeMethod ( name , useTruthy = false ) {
723736 return {
724737 deterministic : ( data , buildState ) => {
0 commit comments