1- export interface QuansyncInputObject < Args extends any [ ] , Return > {
1+ export interface QuansyncInputObject < Return , Args extends any [ ] > {
22 name ?: string
33 sync : ( ...args : Args ) => Return
44 async : ( ...args : Args ) => Promise < Return >
55}
6- export type QuansyncInputGenerator < Args extends any [ ] , Return >
6+
7+ export type QuansyncInputGenerator < Return , Args extends any [ ] >
78 = ( ( ...args : Args ) => QuansyncGenerator < Return > )
89
9- export type QuansyncInput < Args extends any [ ] , Return > =
10- | QuansyncInputObject < Args , Return >
11- | QuansyncInputGenerator < Args , Return >
10+ export type QuansyncInput < Return , Args extends any [ ] > =
11+ | QuansyncInputObject < Return , Args >
12+ | QuansyncInputGenerator < Return , Args >
1213
1314export interface QuansyncYield < R > {
1415 name ?: string
@@ -17,58 +18,75 @@ export interface QuansyncYield<R> {
1718 __isQuansync : true
1819}
1920
20- export type UnwrapQuansyncReturn < T > = T extends QuansyncYield < infer R > ? R : T
21+ export type UnwrapQuansyncReturn < T > = T extends QuansyncYield < infer R > ? Awaited < R > : Awaited < T >
2122
2223export type QuansyncGenerator < Return = any , Yield = unknown > =
2324 Generator < Yield , Return , UnwrapQuansyncReturn < Yield > >
2425
2526/**
2627 * "Superposition" function that can be consumed in both sync and async contexts.
2728 */
28- export type QuansyncFn < Args extends any [ ] = [ ] , Return = any > =
29+ export type QuansyncFn < Return = any , Args extends any [ ] = [ ] > =
2930 ( ( ...args : Args ) => QuansyncGenerator < Return > )
3031 & {
3132 sync : ( ...args : Args ) => Return
3233 async : ( ...args : Args ) => Promise < Return >
3334 }
3435
36+ const ERROR_PROMISE_IN_SYNC = '[Quansync] Yielded an unexpected promise in sync context'
37+
38+ function isThenable < T > ( value : any ) : value is Promise < T > {
39+ return value && typeof value === 'object' && typeof value . then === 'function'
40+ }
41+
3542export function isQuansyncYield < T > ( value : any | QuansyncYield < T > ) : value is QuansyncYield < T > {
3643 return typeof value === 'object' && value !== null && '__isQuansync' in value
3744}
3845
39- function fromObject < Args extends any [ ] , Return > (
40- options : QuansyncInputObject < Args , Return > ,
41- ) : QuansyncFn < Args , Return > {
46+ function fromObject < Return , Args extends any [ ] > (
47+ options : QuansyncInputObject < Return , Args > ,
48+ ) : QuansyncFn < Return , Args > {
4249 const generator = function * ( ...args : Args ) : QuansyncGenerator < Return , any > {
4350 return yield {
4451 name : options . name ,
45- sync : ( ) => options . sync ( ...args ) ,
46- async : ( ) => options . async ( ...args ) ,
52+ sync : ( options . sync as any ) . bind ( null , ...args ) ,
53+ async : ( options . async as any ) . bind ( null , ...args ) ,
4754 __isQuansync : true ,
4855 }
49- } as unknown as QuansyncFn < Args , Return >
56+ } as unknown as QuansyncFn < Return , Args >
5057
5158 generator . sync = options . sync
5259 generator . async = options . async
5360
5461 return generator
5562}
5663
64+ function fromPromise < T > ( promise : Promise < T > | T ) : QuansyncFn < T , [ ] > {
65+ return fromObject ( {
66+ async : ( ) => Promise . resolve ( promise ) ,
67+ sync : ( ) => {
68+ if ( isThenable ( promise ) )
69+ throw new Error ( ERROR_PROMISE_IN_SYNC )
70+ return promise
71+ } ,
72+ } )
73+ }
74+
5775function unwrapSync ( value : any ) : any {
58- return isQuansyncYield ( value )
59- ? value . sync ( )
60- : value
76+ if ( isQuansyncYield ( value ) )
77+ return value . sync ( )
78+ if ( isThenable ( value ) )
79+ throw new Error ( ERROR_PROMISE_IN_SYNC )
80+ return value
6181}
6282
6383function unwrapAsync ( value : any ) : Promise < any > {
64- return isQuansyncYield ( value )
65- ? value . async ( )
66- : value
84+ return isQuansyncYield ( value ) ? value . async ( ) : value
6785}
6886
69- function fromGenerator < Args extends any [ ] , Return > (
70- generator : QuansyncInputGenerator < Args , Return > ,
71- ) : QuansyncFn < Args , Return > {
87+ function fromGenerator < Return , Args extends any [ ] > (
88+ generator : QuansyncInputGenerator < Return , Args > ,
89+ ) : QuansyncFn < Return , Args > {
7290 function sync ( ...args : Args ) : Return {
7391 const iterator = generator ( ...args )
7492 let current = iterator . next ( )
@@ -84,7 +102,7 @@ function fromGenerator<Args extends any[], Return>(
84102 while ( ! current . done ) {
85103 current = iterator . next ( await unwrapAsync ( current . value ) )
86104 }
87- return await unwrapAsync ( current . value )
105+ return unwrapAsync ( current . value )
88106 }
89107
90108 return fromObject ( {
@@ -97,11 +115,20 @@ function fromGenerator<Args extends any[], Return>(
97115/**
98116 * Creates a new Quansync function, a "superposition" between async and sync.
99117 */
100- export function quansync < Args extends any [ ] , Return > (
101- options : QuansyncInput < Args , Return > ,
102- ) : QuansyncFn < Args , Return > {
118+ export function quansync < Return , Args extends any [ ] = [ ] > (
119+ options : QuansyncInput < Return , Args > | Promise < Return > ,
120+ ) : QuansyncFn < Return , Args > {
121+ if ( isThenable ( options ) )
122+ return fromPromise < Return > ( options )
103123 if ( typeof options === 'function' )
104124 return fromGenerator ( options )
105125 else
106126 return fromObject ( options )
107127}
128+
129+ /**
130+ * Converts a promise to a Quansync generator.
131+ */
132+ export function promiseToGenerator < T > ( promise : Promise < T > | T ) : QuansyncGenerator < T > {
133+ return fromPromise ( promise as Promise < T > ) ( )
134+ }
0 commit comments