diff --git a/wire/sync/sync.test.ts b/wire/sync/sync.test.ts index 7197e8b949c..2cdefadb02d 100644 --- a/wire/sync/sync.test.ts +++ b/wire/sync/sync.test.ts @@ -12,9 +12,60 @@ namespace $ { return $mol_wire_sync(this).a() } } - + type Check = $mol_type_assert, string> }, + + async 'test method from host'( $ ) { + let count = 0 + class A { + static a() { + return $mol_wire_sync(this).b() + } + + static b() { return Promise.resolve(++count) } + } + + + $mol_assert_equal(await $mol_wire_async(A).a(), 1, count) + + }, + + async 'test function'( $ ) { + let count = 0 + class A { + static a() { + return $mol_wire_sync(this.b)() + } + + static b() { return Promise.resolve(++count) } + } + + + $mol_assert_equal(await $mol_wire_async(A).a(), 1, count) + + }, + + async 'test construct itself'( $ ) { + class A { + static instances = [] as A[] + + static a() { + const a = new ($mol_wire_sync(A))() + this.instances.push( a ) + $mol_wire_sync(this).b() + } + + static b() { return Promise.resolve() } + } + + await $mol_wire_async(A).a() + $mol_assert_equal(A.instances.length, 2) + $mol_assert_equal(A.instances[0] instanceof A) + + $mol_assert_equal(A.instances[0], A.instances[1]) + + } }) } diff --git a/wire/sync/sync.ts b/wire/sync/sync.ts index 90a5a328eb2..550a7ff5384 100644 --- a/wire/sync/sync.ts +++ b/wire/sync/sync.ts @@ -1,5 +1,19 @@ namespace $ { - + const factories = new WeakMap() + + function factory( + val: new (...args: Args) => Result + ) { + let make = factories.get(val) as null | ((...args: Args) => Result) + + if ( make ) return make + + make = $mol_func_name_from((...args: Args) => new val(...args), val) + factories.set(val, make) + + return make + } + /** * Convert asynchronous (promise-based) API to synchronous by wrapping function and method calls in a fiber. * @see https://mol.hyoo.ru/#!section=docs/=1fcpsq_1wh0h2 @@ -9,21 +23,24 @@ namespace $ { get( obj, field ) { - const val = (obj as any)[ field ] + let val = (obj as any)[ field ] if( typeof val !== 'function' ) return val - - const temp = $mol_wire_task.getter( val ) - return function $mol_wire_sync( this: Host, ... args: any[] ) { + const temp = $mol_wire_task.getter(val) + + return function $mol_wire_sync( this: Host, ... args: unknown[] ) { const fiber = temp( obj, args ) return fiber.sync() } - }, - + + construct(obj, args) { + const temp = $mol_wire_task.getter(factory(obj as (new ( ... args: unknown[] )=> unknown))) + return temp( obj, args ).sync() as object + }, + apply( obj, self, args ) { - const temp = $mol_wire_task.getter( obj as ( ... args: any[] )=> any ) - const fiber = temp( self, args ) - return fiber.sync() + const temp = $mol_wire_task.getter(obj as ( ... args: any[] )=> any) + return temp(self, args).sync() }, } ) as unknown as ObjectOrFunctionResultAwaited @@ -33,12 +50,16 @@ namespace $ { ? (...args: Args) => Awaited : Some + type ConstructorResultAwaited = Some extends new (...args: infer Args) => infer Res + ? new (...args: Args) => Res + : {} + type MethodsResultAwaited = { [K in keyof Host]: FunctionResultAwaited } type ObjectOrFunctionResultAwaited = ( Some extends (...args: any) => unknown ? FunctionResultAwaited : {} - ) & ( Some extends Object ? MethodsResultAwaited : Some ) + ) & ( Some extends Object ? MethodsResultAwaited & ConstructorResultAwaited : Some ) }