Skip to content

Commit a733efb

Browse files
committed
Merge remote-tracking branch 'upstream/main' into asyncify
2 parents 2def067 + ebd9ca0 commit a733efb

File tree

7 files changed

+194
-172
lines changed

7 files changed

+194
-172
lines changed

CHANGELOG.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,34 @@
1+
# 0.10.0 (21 January 2021)
2+
3+
This release contains multiple breaking changes in preparation for enabling `async`/`await`, when
4+
this feature is available in a stable SwiftWasm release. Namely:
5+
6+
* `JSClosure.init(_ body: @escaping ([JSValue]) -> ())` overload is deprecated to simplify type
7+
checking. Its presence requires explicit type signatures at the place of use. It will be removed
8+
in a future version of JavaScriptKit.
9+
* `JSClosure` is no longer a subclass of `JSFunction`. These classes are not related enough to keep
10+
them in the same class hierarchy.
11+
As a result, you can no longer call `JSClosure` objects directly from Swift.
12+
* Introduced `JSOneshotClosure` for closures that are going to be called only once. You don't need
13+
to manage references to these closures manually, as opposed to `JSClosure`.
14+
However, they can only be called a single time from the JS side. Subsequent invocation attempts will raise a fatal error on the Swift side.
15+
* Removed generic parameters on `JSPromise`, now both success and failure values are always assumed
16+
to be of `JSValue` type. This also significantly simplifies type checking and allows callers to
17+
fully control type casting if needed.
18+
19+
**Closed issues:**
20+
21+
- DOMKit? ([#21](https://github.com/swiftwasm/JavaScriptKit/issues/21))
22+
23+
**Merged pull requests:**
24+
25+
- Simplify `JSPromise` API ([#115](https://github.com/swiftwasm/JavaScriptKit/pull/115)) via [@kateinoigakukun](https://github.com/kateinoigakukun)
26+
- Create `FUNDING.yml` ([#117](https://github.com/swiftwasm/JavaScriptKit/pull/117)) via [@MaxDesiatov](https://github.com/MaxDesiatov)
27+
- Major API change on `JSClosure` ([#113](https://github.com/swiftwasm/JavaScriptKit/pull/113)) via [@kateinoigakukun](https://github.com/kateinoigakukun)
28+
- Update `package.json` to lockfileVersion 2 ([#114](https://github.com/swiftwasm/JavaScriptKit/pull/114)) via [@kateinoigakukun](https://github.com/kateinoigakukun)
29+
- Bump `ini` from 1.3.5 to 1.3.8 in `/Example` ([#111](https://github.com/swiftwasm/JavaScriptKit/pull/111)) via [@dependabot[bot]](https://github.com/dependabot[bot])
30+
- Update doc comment in `JSTypedArray.swift` ([#110](https://github.com/swiftwasm/JavaScriptKit/pull/110)) via [@MaxDesiatov](https://github.com/MaxDesiatov)
31+
132
# 0.9.0 (27 November 2020)
233

334
This release introduces support for catching `JSError` instances in Swift from throwing JavaScript

IntegrationTests/TestSuites/Sources/PrimaryTests/UnitTestUtils.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,32 @@ func expectNotNil<T>(_ value: T?, file: StaticString = #file, line: UInt = #line
101101
throw MessageError("Expect a non-nil value", file: file, line: line, column: column)
102102
}
103103
}
104+
105+
class Expectation {
106+
private(set) var isFulfilled: Bool = false
107+
private let label: String
108+
private let expectedFulfillmentCount: Int
109+
private var fulfillmentCount: Int = 0
110+
111+
init(label: String, expectedFulfillmentCount: Int = 1) {
112+
self.label = label
113+
self.expectedFulfillmentCount = expectedFulfillmentCount
114+
}
115+
116+
func fulfill() {
117+
assert(!isFulfilled, "Too many fulfillment (label: \(label)): expectedFulfillmentCount is \(expectedFulfillmentCount)")
118+
fulfillmentCount += 1
119+
if fulfillmentCount == expectedFulfillmentCount {
120+
isFulfilled = true
121+
}
122+
}
123+
124+
static func wait(_ expectations: [Expectation]) {
125+
var timer: JSTimer!
126+
timer = JSTimer(millisecondsDelay: 5.0, isRepeating: true) {
127+
guard expectations.allSatisfy(\.isFulfilled) else { return }
128+
assert(timer != nil)
129+
timer = nil
130+
}
131+
}
132+
}

IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -528,22 +528,80 @@ try test("Timer") {
528528
}
529529

530530
var timer: JSTimer?
531-
var promise: JSPromise<(), Never>?
531+
var expectations: [Expectation] = []
532532

533533
try test("Promise") {
534+
535+
let p1 = JSPromise.resolve(JSValue.null)
536+
let exp1 = Expectation(label: "Promise.then testcase", expectedFulfillmentCount: 4)
537+
p1.then { value in
538+
try! expectEqual(value, .null)
539+
exp1.fulfill()
540+
return JSValue.number(1.0)
541+
}
542+
.then { value in
543+
try! expectEqual(value, .number(1.0))
544+
exp1.fulfill()
545+
return JSPromise.resolve(JSValue.boolean(true))
546+
}
547+
.then { value in
548+
try! expectEqual(value, .boolean(true))
549+
exp1.fulfill()
550+
return JSValue.undefined
551+
}
552+
.catch { _ -> JSValue in
553+
fatalError("Not fired due to no throw")
554+
}
555+
.finally { exp1.fulfill() }
556+
557+
let exp2 = Expectation(label: "Promise.catch testcase", expectedFulfillmentCount: 4)
558+
let p2 = JSPromise.reject(JSValue.boolean(false))
559+
p2.then { _ -> JSValue in
560+
fatalError("Not fired due to no success")
561+
}
562+
.catch { reason in
563+
try! expectEqual(reason, .boolean(false))
564+
exp2.fulfill()
565+
return JSValue.boolean(true)
566+
}
567+
.then { value in
568+
try! expectEqual(value, .boolean(true))
569+
exp2.fulfill()
570+
return JSPromise.reject(JSValue.number(2.0))
571+
}
572+
.catch { reason in
573+
try! expectEqual(reason, .number(2.0))
574+
exp2.fulfill()
575+
return JSValue.undefined
576+
}
577+
.finally { exp2.fulfill() }
578+
579+
534580
let start = JSDate().valueOf()
535581
let timeoutMilliseconds = 5.0
582+
let exp3 = Expectation(label: "Promise and Timer testcae", expectedFulfillmentCount: 2)
536583

537-
promise = JSPromise { resolve in
584+
let p3 = JSPromise { resolve in
538585
timer = JSTimer(millisecondsDelay: timeoutMilliseconds) {
539-
resolve()
586+
exp3.fulfill()
587+
resolve(.success(.undefined))
540588
}
541589
}
542590

543-
promise!.then {
591+
p3.then { _ in
544592
// verify that at least `timeoutMilliseconds` passed since the timer started
545593
try! expectEqual(start + timeoutMilliseconds <= JSDate().valueOf(), true)
594+
exp3.fulfill()
595+
return JSValue.undefined
546596
}
597+
598+
let exp4 = Expectation(label: "Promise lifetime")
599+
// Ensure that users don't need to manage JSPromise lifetime
600+
JSPromise.resolve(JSValue.boolean(true)).then { _ in
601+
exp4.fulfill()
602+
return JSValue.undefined
603+
}
604+
expectations += [exp1, exp2, exp3, exp4]
547605
}
548606

549607
try test("Error") {
@@ -620,3 +678,5 @@ try test("Exception") {
620678
let errorObject3 = JSError(from: ageError as! JSValue)
621679
try expectNotNil(errorObject3)
622680
}
681+
682+
Expectation.wait(expectations)

0 commit comments

Comments
 (0)