Skip to content

Commit 809db58

Browse files
committed
Gracefully handle unavailable JSBridgedClass
1 parent e022311 commit 809db58

File tree

6 files changed

+96
-89
lines changed

6 files changed

+96
-89
lines changed

Sources/JavaScriptKit/BasicObjects/JSArray.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/// A wrapper around [the JavaScript Array class](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)
22
/// that exposes its properties in a type-safe and Swifty way.
33
public class JSArray: JSBridgedClass {
4-
public static let constructor = JSObject.global.Array.function!
4+
public static let constructor = JSObject.global.Array.function
55

66
static func isArray(_ object: JSObject) -> Bool {
7-
constructor.isArray!(object).boolean!
7+
constructor!.isArray!(object).boolean!
88
}
99

1010
public let jsObject: JSObject
@@ -94,8 +94,8 @@ private func getObjectValuesLength(_ object: JSObject) -> Int {
9494
return Int(values.length.number!)
9595
}
9696

97-
extension JSValue {
98-
public var array: JSArray? {
97+
public extension JSValue {
98+
var array: JSArray? {
9999
object.flatMap(JSArray.init)
100100
}
101101
}

Sources/JavaScriptKit/BasicObjects/JSDate.swift

+30-30
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
1-
/** A wrapper around the [JavaScript Date
2-
class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) that
3-
exposes its properties in a type-safe way. This doesn't 100% match the JS API, for example
4-
`getMonth`/`setMonth` etc accessor methods are converted to properties, but the rest of it matches
5-
in the naming. Parts of the JavaScript `Date` API that are not consistent across browsers and JS
6-
implementations are not exposed in a type-safe manner, you should access the underlying `jsObject`
7-
property if you need those.
8-
*/
1+
/** A wrapper around the [JavaScript Date
2+
class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) that
3+
exposes its properties in a type-safe way. This doesn't 100% match the JS API, for example
4+
`getMonth`/`setMonth` etc accessor methods are converted to properties, but the rest of it matches
5+
in the naming. Parts of the JavaScript `Date` API that are not consistent across browsers and JS
6+
implementations are not exposed in a type-safe manner, you should access the underlying `jsObject`
7+
property if you need those.
8+
*/
99
public final class JSDate: JSBridgedClass {
1010
/// The constructor function used to create new `Date` objects.
11-
public static let constructor = JSObject.global.Date.function!
11+
public static let constructor = JSObject.global.Date.function
1212

1313
/// The underlying JavaScript `Date` object.
1414
public let jsObject: JSObject
1515

1616
/** Creates a new instance of the JavaScript `Date` class with a given amount of milliseconds
17-
that passed since midnight 01 January 1970 UTC.
18-
*/
17+
that passed since midnight 01 January 1970 UTC.
18+
*/
1919
public init(millisecondsSinceEpoch: Double? = nil) {
2020
if let milliseconds = millisecondsSinceEpoch {
21-
jsObject = Self.constructor.new(milliseconds)
21+
jsObject = Self.constructor!.new(milliseconds)
2222
} else {
23-
jsObject = Self.constructor.new()
23+
jsObject = Self.constructor!.new()
2424
}
2525
}
2626

27-
/** According to the standard, `monthIndex` is zero-indexed, where `11` is December. `day`
28-
represents a day of the month starting at `1`.
29-
*/
27+
/** According to the standard, `monthIndex` is zero-indexed, where `11` is December. `day`
28+
represents a day of the month starting at `1`.
29+
*/
3030
public init(
3131
year: Int,
3232
monthIndex: Int,
@@ -36,7 +36,7 @@ public final class JSDate: JSBridgedClass {
3636
seconds: Int = 0,
3737
milliseconds: Int = 0
3838
) {
39-
jsObject = Self.constructor.new(year, monthIndex, day, hours, minutes, seconds, milliseconds)
39+
jsObject = Self.constructor!.new(year, monthIndex, day, hours, minutes, seconds, milliseconds)
4040
}
4141

4242
public init(unsafelyWrapping jsObject: JSObject) {
@@ -198,7 +198,7 @@ public final class JSDate: JSBridgedClass {
198198
Int(jsObject.getTimezoneOffset!().number!)
199199
}
200200

201-
/// Returns a string conforming to ISO 8601 that contains date and time, e.g.
201+
/// Returns a string conforming to ISO 8601 that contains date and time, e.g.
202202
/// `"2020-09-15T08:56:54.811Z"`.
203203
public func toISOString() -> String {
204204
jsObject.toISOString!().string!
@@ -214,25 +214,25 @@ public final class JSDate: JSBridgedClass {
214214
jsObject.toLocaleTimeString!().string!
215215
}
216216

217-
/** Returns a string formatted according to
218-
[rfc7231](https://tools.ietf.org/html/rfc7231#section-7.1.1.1) and modified according to
219-
[ecma-262](https://www.ecma-international.org/ecma-262/10.0/index.html#sec-date.prototype.toutcstring),
220-
e.g. `Tue, 15 Sep 2020 09:04:40 GMT`.
221-
*/
217+
/** Returns a string formatted according to
218+
[rfc7231](https://tools.ietf.org/html/rfc7231#section-7.1.1.1) and modified according to
219+
[ecma-262](https://www.ecma-international.org/ecma-262/10.0/index.html#sec-date.prototype.toutcstring),
220+
e.g. `Tue, 15 Sep 2020 09:04:40 GMT`.
221+
*/
222222
public func toUTCString() -> String {
223223
jsObject.toUTCString!().string!
224224
}
225225

226-
/** Number of milliseconds since midnight 01 January 1970 UTC to the present moment ignoring
227-
leap seconds.
228-
*/
226+
/** Number of milliseconds since midnight 01 January 1970 UTC to the present moment ignoring
227+
leap seconds.
228+
*/
229229
public static func now() -> Double {
230-
constructor.now!().number!
230+
constructor!.now!().number!
231231
}
232232

233-
/** Number of milliseconds since midnight 01 January 1970 UTC to the given date ignoring leap
234-
seconds.
235-
*/
233+
/** Number of milliseconds since midnight 01 January 1970 UTC to the given date ignoring leap
234+
seconds.
235+
*/
236236
public func valueOf() -> Double {
237237
jsObject.valueOf!().number!
238238
}

Sources/JavaScriptKit/BasicObjects/JSError.swift

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
/** A wrapper around [the JavaScript Error
2-
class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) that
3-
exposes its properties in a type-safe way.
4-
*/
1+
/** A wrapper around [the JavaScript Error
2+
class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) that
3+
exposes its properties in a type-safe way.
4+
*/
55
public final class JSError: Error, JSBridgedClass {
66
/// The constructor function used to create new JavaScript `Error` objects.
7-
public static let constructor = JSObject.global.Error.function!
7+
public static let constructor = JSObject.global.Error.function
88

99
/// The underlying JavaScript `Error` object.
1010
public let jsObject: JSObject
1111

1212
/// Creates a new instance of the JavaScript `Error` class with a given message.
1313
public init(message: String) {
14-
jsObject = Self.constructor.new([message])
14+
jsObject = Self.constructor!.new([message])
1515
}
1616

1717
public init(unsafelyWrapping jsObject: JSObject) {

Sources/JavaScriptKit/BasicObjects/JSPromise.swift

+32-31
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
/** A wrapper around [the JavaScript `Promise` class](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)
2-
that exposes its functions in a type-safe and Swifty way. The `JSPromise` API is generic over both
3-
`Success` and `Failure` types, which improves compatibility with other statically-typed APIs such
4-
as Combine. If you don't know the exact type of your `Success` value, you should use `JSValue`, e.g.
5-
`JSPromise<JSValue, JSError>`. In the rare case, where you can't guarantee that the error thrown
6-
is of actual JavaScript `Error` type, you should use `JSPromise<JSValue, JSValue>`.
2+
that exposes its functions in a type-safe and Swifty way. The `JSPromise` API is generic over both
3+
`Success` and `Failure` types, which improves compatibility with other statically-typed APIs such
4+
as Combine. If you don't know the exact type of your `Success` value, you should use `JSValue`, e.g.
5+
`JSPromise<JSValue, JSError>`. In the rare case, where you can't guarantee that the error thrown
6+
is of actual JavaScript `Error` type, you should use `JSPromise<JSValue, JSValue>`.
77

8-
This doesn't 100% match the JavaScript API, as `then` overload with two callbacks is not available.
9-
It's impossible to unify success and failure types from both callbacks in a single returned promise
10-
without type erasure. You should chain `then` and `catch` in those cases to avoid type erasure.
11-
*/
8+
This doesn't 100% match the JavaScript API, as `then` overload with two callbacks is not available.
9+
It's impossible to unify success and failure types from both callbacks in a single returned promise
10+
without type erasure. You should chain `then` and `catch` in those cases to avoid type erasure.
11+
*/
1212
public final class JSPromise: JSBridgedClass {
1313
/// The underlying JavaScript `Promise` object.
1414
public let jsObject: JSObject
@@ -18,35 +18,35 @@ public final class JSPromise: JSBridgedClass {
1818
.object(jsObject)
1919
}
2020

21-
public static var constructor: JSFunction {
21+
public static var constructor: JSFunction? {
2222
JSObject.global.Promise.function!
2323
}
2424

2525
/// This private initializer assumes that the passed object is a JavaScript `Promise`
2626
public init(unsafelyWrapping object: JSObject) {
27-
self.jsObject = object
27+
jsObject = object
2828
}
2929

3030
/** Creates a new `JSPromise` instance from a given JavaScript `Promise` object. If `jsObject`
31-
is not an instance of JavaScript `Promise`, this initializer will return `nil`.
32-
*/
31+
is not an instance of JavaScript `Promise`, this initializer will return `nil`.
32+
*/
3333
public convenience init?(_ jsObject: JSObject) {
3434
self.init(from: jsObject)
3535
}
3636

3737
/** Creates a new `JSPromise` instance from a given JavaScript `Promise` object. If `value`
38-
is not an object and is not an instance of JavaScript `Promise`, this function will
39-
return `nil`.
40-
*/
38+
is not an object and is not an instance of JavaScript `Promise`, this function will
39+
return `nil`.
40+
*/
4141
public static func construct(from value: JSValue) -> Self? {
4242
guard case let .object(jsObject) = value else { return nil }
43-
return Self.init(jsObject)
43+
return Self(jsObject)
4444
}
4545

4646
/** Creates a new `JSPromise` instance from a given `resolver` closure. `resolver` takes
47-
two closure that your code should call to either resolve or reject this `JSPromise` instance.
48-
*/
49-
public convenience init(resolver: @escaping (@escaping (Result<JSValue, JSValue>) -> ()) -> ()) {
47+
two closure that your code should call to either resolve or reject this `JSPromise` instance.
48+
*/
49+
public convenience init(resolver: @escaping (@escaping (Result<JSValue, JSValue>) -> Void) -> Void) {
5050
let closure = JSOneshotClosure { arguments in
5151
// The arguments are always coming from the `Promise` constructor, so we should be
5252
// safe to assume their type here
@@ -63,19 +63,19 @@ public final class JSPromise: JSBridgedClass {
6363
}
6464
return .undefined
6565
}
66-
self.init(unsafelyWrapping: Self.constructor.new(closure))
66+
self.init(unsafelyWrapping: Self.constructor!.new(closure))
6767
}
6868

6969
public static func resolve(_ value: ConvertibleToJSValue) -> JSPromise {
70-
self.init(unsafelyWrapping: Self.constructor.resolve!(value).object!)
70+
self.init(unsafelyWrapping: Self.constructor!.resolve!(value).object!)
7171
}
7272

7373
public static func reject(_ reason: ConvertibleToJSValue) -> JSPromise {
74-
self.init(unsafelyWrapping: Self.constructor.reject!(reason).object!)
74+
self.init(unsafelyWrapping: Self.constructor!.reject!(reason).object!)
7575
}
7676

7777
/** Schedules the `success` closure to be invoked on sucessful completion of `self`.
78-
*/
78+
*/
7979
@discardableResult
8080
public func then(success: @escaping (JSValue) -> ConvertibleToJSValue) -> JSPromise {
8181
let closure = JSOneshotClosure {
@@ -85,10 +85,11 @@ public final class JSPromise: JSBridgedClass {
8585
}
8686

8787
/** Schedules the `success` closure to be invoked on sucessful completion of `self`.
88-
*/
88+
*/
8989
@discardableResult
9090
public func then(success: @escaping (JSValue) -> ConvertibleToJSValue,
91-
failure: @escaping (JSValue) -> ConvertibleToJSValue) -> JSPromise {
91+
failure: @escaping (JSValue) -> ConvertibleToJSValue) -> JSPromise
92+
{
9293
let successClosure = JSOneshotClosure {
9394
success($0[0]).jsValue
9495
}
@@ -99,7 +100,7 @@ public final class JSPromise: JSBridgedClass {
99100
}
100101

101102
/** Schedules the `failure` closure to be invoked on rejected completion of `self`.
102-
*/
103+
*/
103104
@discardableResult
104105
public func `catch`(failure: @escaping (JSValue) -> ConvertibleToJSValue) -> JSPromise {
105106
let closure = JSOneshotClosure {
@@ -108,11 +109,11 @@ public final class JSPromise: JSBridgedClass {
108109
return .init(unsafelyWrapping: jsObject.catch!(closure).object!)
109110
}
110111

111-
/** Schedules the `failure` closure to be invoked on either successful or rejected completion of
112-
`self`.
113-
*/
112+
/** Schedules the `failure` closure to be invoked on either successful or rejected completion of
113+
`self`.
114+
*/
114115
@discardableResult
115-
public func finally(successOrFailure: @escaping () -> ()) -> JSPromise {
116+
public func finally(successOrFailure: @escaping () -> Void) -> JSPromise {
116117
let closure = JSOneshotClosure { _ in
117118
successOrFailure()
118119
return .undefined

Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift

+14-8
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ public protocol TypedArrayElement: ConvertibleToJSValue, ConstructibleFromJSValu
1313
/// A wrapper around all JavaScript [TypedArray](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/TypedArray)
1414
/// classes that exposes their properties in a type-safe way.
1515
public class JSTypedArray<Element>: JSBridgedClass, ExpressibleByArrayLiteral where Element: TypedArrayElement {
16-
public class var constructor: JSFunction { Element.typedArrayClass }
16+
public class var constructor: JSFunction? { Element.typedArrayClass }
1717
public var jsObject: JSObject
1818

1919
public subscript(_ index: Int) -> Element {
2020
get {
2121
return Element.construct(from: jsObject[index])!
2222
}
2323
set {
24-
self.jsObject[index] = newValue.jsValue
24+
jsObject[index] = newValue.jsValue
2525
}
2626
}
2727

@@ -30,22 +30,23 @@ public class JSTypedArray<Element>: JSBridgedClass, ExpressibleByArrayLiteral wh
3030
///
3131
/// - Parameter length: The number of elements that will be allocated.
3232
public init(length: Int) {
33-
jsObject = Self.constructor.new(length)
33+
jsObject = Self.constructor!.new(length)
3434
}
3535

36-
required public init(unsafelyWrapping jsObject: JSObject) {
36+
public required init(unsafelyWrapping jsObject: JSObject) {
3737
self.jsObject = jsObject
3838
}
3939

40-
required public convenience init(arrayLiteral elements: Element...) {
40+
public required convenience init(arrayLiteral elements: Element...) {
4141
self.init(elements)
4242
}
43+
4344
/// Initialize a new instance of TypedArray in JavaScript environment with given elements.
4445
///
4546
/// - Parameter array: The array that will be copied to create a new instance of TypedArray
4647
public convenience init(_ array: [Element]) {
4748
let jsArrayRef = array.withUnsafeBufferPointer { ptr in
48-
_create_typed_array(Self.constructor.id, ptr.baseAddress!, Int32(array.count))
49+
_create_typed_array(Self.constructor!.id, ptr.baseAddress!, Int32(array.count))
4950
}
5051
self.init(unsafelyWrapping: JSObject(id: jsArrayRef))
5152
}
@@ -80,7 +81,7 @@ public class JSTypedArray<Element>: JSBridgedClass, ExpressibleByArrayLiteral wh
8081
let rawBuffer = malloc(bytesLength)!
8182
defer { free(rawBuffer) }
8283
_load_typed_array(jsObject.id, rawBuffer.assumingMemoryBound(to: UInt8.self))
83-
let length = lengthInBytes / MemoryLayout<Element>.size
84+
let length = lengthInBytes / MemoryLayout<Element>.size
8485
let boundPtr = rawBuffer.bindMemory(to: Element.self, capacity: length)
8586
let bufferPtr = UnsafeBufferPointer<Element>(start: boundPtr, count: length)
8687
let result = try body(bufferPtr)
@@ -105,6 +106,7 @@ extension Int: TypedArrayElement {
105106
public static var typedArrayClass: JSFunction =
106107
valueForBitWidth(typeName: "Int", bitWidth: Int.bitWidth, when32: JSObject.global.Int32Array).function!
107108
}
109+
108110
extension UInt: TypedArrayElement {
109111
public static var typedArrayClass: JSFunction =
110112
valueForBitWidth(typeName: "UInt", bitWidth: Int.bitWidth, when32: JSObject.global.Uint32Array).function!
@@ -113,31 +115,35 @@ extension UInt: TypedArrayElement {
113115
extension Int8: TypedArrayElement {
114116
public static var typedArrayClass = JSObject.global.Int8Array.function!
115117
}
118+
116119
extension UInt8: TypedArrayElement {
117120
public static var typedArrayClass = JSObject.global.Uint8Array.function!
118121
}
119122

120123
public class JSUInt8ClampedArray: JSTypedArray<UInt8> {
121-
public class override var constructor: JSFunction { JSObject.global.Uint8ClampedArray.function! }
124+
override public class var constructor: JSFunction? { JSObject.global.Uint8ClampedArray.function! }
122125
}
123126

124127
extension Int16: TypedArrayElement {
125128
public static var typedArrayClass = JSObject.global.Int16Array.function!
126129
}
130+
127131
extension UInt16: TypedArrayElement {
128132
public static var typedArrayClass = JSObject.global.Uint16Array.function!
129133
}
130134

131135
extension Int32: TypedArrayElement {
132136
public static var typedArrayClass = JSObject.global.Int32Array.function!
133137
}
138+
134139
extension UInt32: TypedArrayElement {
135140
public static var typedArrayClass = JSObject.global.Uint32Array.function!
136141
}
137142

138143
extension Float32: TypedArrayElement {
139144
public static var typedArrayClass = JSObject.global.Float32Array.function!
140145
}
146+
141147
extension Float64: TypedArrayElement {
142148
public static var typedArrayClass = JSObject.global.Float64Array.function!
143149
}

0 commit comments

Comments
 (0)