@@ -9,7 +9,7 @@ This doesn't 100% match the JavaScript API, as `then` overload with two callback
99It's impossible to unify success and failure types from both callbacks in a single returned promise
1010without type erasure. You should chain `then` and `catch` in those cases to avoid type erasure.
1111*/
12- public final class JSPromise < Success , Failure > : ConvertibleToJSValue , ConstructibleFromJSValue {
12+ public final class JSPromise : JSBridgedClass {
1313 /// The underlying JavaScript `Promise` object.
1414 public let jsObject : JSObject
1515
@@ -18,17 +18,20 @@ public final class JSPromise<Success, Failure>: ConvertibleToJSValue, Constructi
1818 . object( jsObject)
1919 }
2020
21+ public static var constructor : JSFunction {
22+ JSObject . global. Promise. function!
23+ }
24+
2125 /// This private initializer assumes that the passed object is a JavaScript `Promise`
22- private init ( unsafe object: JSObject ) {
26+ public init ( unsafelyWrapping object: JSObject ) {
2327 self . jsObject = object
2428 }
2529
2630 /** Creates a new `JSPromise` instance from a given JavaScript `Promise` object. If `jsObject`
2731 is not an instance of JavaScript `Promise`, this initializer will return `nil`.
2832 */
29- public init ? ( _ jsObject: JSObject ) {
30- guard jsObject. isInstanceOf ( JSObject . global. Promise. function!) else { return nil }
31- self . jsObject = jsObject
33+ public convenience init ? ( _ jsObject: JSObject ) {
34+ self . init ( from: jsObject)
3235 }
3336
3437 /** Creates a new `JSPromise` instance from a given JavaScript `Promise` object. If `value`
@@ -40,73 +43,10 @@ public final class JSPromise<Success, Failure>: ConvertibleToJSValue, Constructi
4043 return Self . init ( jsObject)
4144 }
4245
43- /** Schedules the `success` closure to be invoked on sucessful completion of `self`.
44- */
45- public func then( success: @escaping ( ) -> ( ) ) {
46- let closure = JSOneshotClosure { _ in
47- success ( )
48- return . undefined
49- }
50- _ = jsObject. then!( closure)
51- }
52-
53- /** Schedules the `failure` closure to be invoked on either successful or rejected completion of
54- `self`.
55- */
56- public func finally( successOrFailure: @escaping ( ) -> ( ) ) -> Self {
57- let closure = JSOneshotClosure { _ in
58- successOrFailure ( )
59- return . undefined
60- }
61- return . init( unsafe: jsObject. finally!( closure) . object!)
62- }
63- }
64-
65- extension JSPromise where Success == ( ) , Failure == Never {
66- /** Creates a new `JSPromise` instance from a given `resolver` closure. `resolver` takes
67- a closure that your code should call to resolve this `JSPromise` instance.
68- */
69- public convenience init ( resolver: @escaping ( @escaping ( ) -> ( ) ) -> ( ) ) {
70- let closure = JSOneshotClosure { arguments in
71- // The arguments are always coming from the `Promise` constructor, so we should be
72- // safe to assume their type here
73- resolver { arguments [ 0 ] . function!( ) }
74- return . undefined
75- }
76- self . init ( unsafe: JSObject . global. Promise. function!. new ( closure) )
77- }
78- }
79-
80- extension JSPromise where Failure: ConvertibleToJSValue {
81- /** Creates a new `JSPromise` instance from a given `resolver` closure. `resolver` takes
46+ /** Creates a new `JSPromise` instance from a given `resolver` closure. `resolver` takes
8247 two closure that your code should call to either resolve or reject this `JSPromise` instance.
8348 */
84- public convenience init ( resolver: @escaping ( @escaping ( Result < Success , JSError > ) -> ( ) ) -> ( ) ) {
85- let closure = JSOneshotClosure { arguments in
86- // The arguments are always coming from the `Promise` constructor, so we should be
87- // safe to assume their type here
88- let resolve = arguments [ 0 ] . function!
89- let reject = arguments [ 1 ] . function!
90-
91- resolver {
92- switch $0 {
93- case . success:
94- resolve ( )
95- case let . failure( error) :
96- reject ( error. jsValue ( ) )
97- }
98- }
99- return . undefined
100- }
101- self . init ( unsafe: JSObject . global. Promise. function!. new ( closure) )
102- }
103- }
104-
105- extension JSPromise where Success: ConvertibleToJSValue , Failure: JSError {
106- /** Creates a new `JSPromise` instance from a given `resolver` closure. `resolver` takes
107- a closure that your code should call to either resolve or reject this `JSPromise` instance.
108- */
109- public convenience init ( resolver: @escaping ( @escaping ( Result < Success , JSError > ) -> ( ) ) -> ( ) ) {
49+ public convenience init ( resolver: @escaping ( @escaping ( Result < JSValue , JSValue > ) -> ( ) ) -> ( ) ) {
11050 let closure = JSOneshotClosure { arguments in
11151 // The arguments are always coming from the `Promise` constructor, so we should be
11252 // safe to assume their type here
@@ -116,123 +56,67 @@ extension JSPromise where Success: ConvertibleToJSValue, Failure: JSError {
11656 resolver {
11757 switch $0 {
11858 case let . success( success) :
119- resolve ( success. jsValue ( ) )
59+ resolve ( success)
12060 case let . failure( error) :
121- reject ( error. jsValue ( ) )
61+ reject ( error)
12262 }
12363 }
12464 return . undefined
12565 }
126- self . init ( unsafe : JSObject . global . Promise . function! . new ( closure) )
66+ self . init ( unsafelyWrapping : Self . constructor . new ( closure) )
12767 }
128- }
12968
130- extension JSPromise where Success: ConstructibleFromJSValue {
131- /** Schedules the `success` closure to be invoked on sucessful completion of `self`.
132- */
133- public func then(
134- success: @escaping ( Success ) -> ( ) ,
135- file: StaticString = #file,
136- line: Int = #line
137- ) {
138- let closure = JSOneshotClosure { arguments in
139- guard let result = Success . construct ( from: arguments [ 0 ] ) else {
140- fatalError ( " \( file) : \( line) : failed to unwrap success value for `then` callback " )
141- }
142- success ( result)
143- return . undefined
144- }
145- _ = jsObject. then!( closure)
69+ public static func resolve( _ value: ConvertibleToJSValue ) -> JSPromise {
70+ self . init ( unsafelyWrapping: Self . constructor. resolve!( value) . object!)
14671 }
14772
148- /** Returns a new promise created from chaining the current `self` promise with the `success`
149- closure invoked on sucessful completion of `self`. The returned promise will have a new
150- `Success` type equal to the return type of `success`.
151- */
152- public func then< ResultType: ConvertibleToJSValue > (
153- success: @escaping ( Success ) -> ResultType ,
154- file: StaticString = #file,
155- line: Int = #line
156- ) -> JSPromise < ResultType , Failure > {
157- let closure = JSOneshotClosure { arguments -> JSValue in
158- guard let result = Success . construct ( from: arguments [ 0 ] ) else {
159- fatalError ( " \( file) : \( line) : failed to unwrap success value for `then` callback " )
160- }
161- return success ( result) . jsValue ( )
162- }
163- return . init( unsafe: jsObject. then!( closure) . object!)
73+ public static func reject( _ reason: ConvertibleToJSValue ) -> JSPromise {
74+ self . init ( unsafelyWrapping: Self . constructor. reject!( reason) . object!)
16475 }
16576
166- /** Returns a new promise created from chaining the current `self` promise with the `success`
167- closure invoked on sucessful completion of `self`. The returned promise will have a new type
168- equal to the return type of `success`.
77+ /** Schedules the `success` closure to be invoked on sucessful completion of `self`.
16978 */
170- public func then< ResultSuccess: ConvertibleToJSValue , ResultFailure: ConstructibleFromJSValue > (
171- success: @escaping ( Success ) -> JSPromise < ResultSuccess , ResultFailure > ,
172- file: StaticString = #file,
173- line: Int = #line
174- ) -> JSPromise < ResultSuccess , ResultFailure > {
175- let closure = JSOneshotClosure { arguments -> JSValue in
176- guard let result = Success . construct ( from: arguments [ 0 ] ) else {
177- fatalError ( " \( file) : \( line) : failed to unwrap success value for `then` callback " )
178- }
179- return success ( result) . jsValue ( )
79+ @discardableResult
80+ public func then( success: @escaping ( JSValue ) -> ConvertibleToJSValue ) -> JSPromise {
81+ let closure = JSOneshotClosure {
82+ return success ( $0 [ 0 ] ) . jsValue ( )
18083 }
181- return . init ( unsafe : jsObject. then!( closure) . object!)
84+ return JSPromise ( unsafelyWrapping : jsObject. then!( closure) . object!)
18285 }
183- }
18486
185- extension JSPromise where Failure: ConstructibleFromJSValue {
186- /** Returns a new promise created from chaining the current `self` promise with the `failure`
187- closure invoked on rejected completion of `self`. The returned promise will have a new `Success`
188- type equal to the return type of the callback, while the `Failure` type becomes `Never`.
87+ /** Schedules the `success` closure to be invoked on sucessful completion of `self`.
18988 */
190- public func `catch`< ResultSuccess: ConvertibleToJSValue > (
191- failure: @escaping ( Failure ) -> ResultSuccess ,
192- file: StaticString = #file,
193- line: Int = #line
194- ) -> JSPromise < ResultSuccess , Never > {
195- let closure = JSOneshotClosure { arguments -> JSValue in
196- guard let error = Failure . construct ( from: arguments [ 0 ] ) else {
197- fatalError ( " \( file) : \( line) : failed to unwrap error value for `catch` callback " )
198- }
199- return failure ( error) . jsValue ( )
89+ @discardableResult
90+ public func then( success: @escaping ( JSValue ) -> ConvertibleToJSValue ,
91+ failure: @escaping ( JSValue ) -> ConvertibleToJSValue ) -> JSPromise {
92+ let successClosure = JSOneshotClosure {
93+ return success ( $0 [ 0 ] ) . jsValue ( )
20094 }
201- return . init( unsafe: jsObject. then!( JSValue . undefined, closure) . object!)
95+ let failureClosure = JSOneshotClosure {
96+ return failure ( $0 [ 0 ] ) . jsValue ( )
97+ }
98+ return JSPromise ( unsafelyWrapping: jsObject. then!( successClosure, failureClosure) . object!)
20299 }
203100
204101 /** Schedules the `failure` closure to be invoked on rejected completion of `self`.
205102 */
206- public func `catch`(
207- failure: @escaping ( Failure ) -> ( ) ,
208- file: StaticString = #file,
209- line: Int = #line
210- ) {
211- let closure = JSOneshotClosure { arguments in
212- guard let error = Failure . construct ( from: arguments [ 0 ] ) else {
213- fatalError ( " \( file) : \( line) : failed to unwrap error value for `catch` callback " )
214- }
215- failure ( error)
216- return . undefined
103+ @discardableResult
104+ public func `catch`( failure: @escaping ( JSValue ) -> ConvertibleToJSValue ) -> JSPromise {
105+ let closure = JSOneshotClosure {
106+ return failure ( $0 [ 0 ] ) . jsValue ( )
217107 }
218- _ = jsObject. then! ( JSValue . undefined , closure)
108+ return . init ( unsafelyWrapping : jsObject. catch! ( closure) . object! )
219109 }
220110
221- /** Returns a new promise created from chaining the current `self` promise with the `failure`
222- closure invoked on rejected completion of `self`. The returned promise will have a new type
223- equal to the return type of `success`.
111+ /** Schedules the `failure` closure to be invoked on either successful or rejected completion of
112+ `self`.
224113 */
225- public func `catch`< ResultSuccess: ConvertibleToJSValue , ResultFailure: ConstructibleFromJSValue > (
226- failure: @escaping ( Failure ) -> JSPromise < ResultSuccess , ResultFailure > ,
227- file: StaticString = #file,
228- line: Int = #line
229- ) -> JSPromise < ResultSuccess , ResultFailure > {
230- let closure = JSOneshotClosure { arguments -> JSValue in
231- guard let error = Failure . construct ( from: arguments [ 0 ] ) else {
232- fatalError ( " \( file) : \( line) : failed to unwrap error value for `catch` callback " )
233- }
234- return failure ( error) . jsValue ( )
114+ @discardableResult
115+ public func finally( successOrFailure: @escaping ( ) -> ( ) ) -> JSPromise {
116+ let closure = JSOneshotClosure { _ in
117+ successOrFailure ( )
118+ return . undefined
235119 }
236- return . init( unsafe : jsObject. then! ( JSValue . undefined , closure) . object!)
120+ return . init( unsafelyWrapping : jsObject. finally! ( closure) . object!)
237121 }
238122}
0 commit comments