diff --git a/Sources/JavaScriptKit/BasicObjects/JSArray.swift b/Sources/JavaScriptKit/BasicObjects/JSArray.swift index 2452c17e7..2d971daf7 100644 --- a/Sources/JavaScriptKit/BasicObjects/JSArray.swift +++ b/Sources/JavaScriptKit/BasicObjects/JSArray.swift @@ -1,10 +1,10 @@ /// A wrapper around [the JavaScript Array class](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array) /// that exposes its properties in a type-safe and Swifty way. public class JSArray: JSBridgedClass { - public static let constructor = JSObject.global.Array.function! + public static let constructor = JSObject.global.Array.function static func isArray(_ object: JSObject) -> Bool { - constructor.isArray!(object).boolean! + constructor!.isArray!(object).boolean! } public let jsObject: JSObject @@ -94,8 +94,8 @@ private func getObjectValuesLength(_ object: JSObject) -> Int { return Int(values.length.number!) } -extension JSValue { - public var array: JSArray? { +public extension JSValue { + var array: JSArray? { object.flatMap(JSArray.init) } } diff --git a/Sources/JavaScriptKit/BasicObjects/JSDate.swift b/Sources/JavaScriptKit/BasicObjects/JSDate.swift index 3f38f5aba..5a0fd25ee 100644 --- a/Sources/JavaScriptKit/BasicObjects/JSDate.swift +++ b/Sources/JavaScriptKit/BasicObjects/JSDate.swift @@ -1,32 +1,32 @@ -/** A wrapper around the [JavaScript Date -class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) that -exposes its properties in a type-safe way. This doesn't 100% match the JS API, for example -`getMonth`/`setMonth` etc accessor methods are converted to properties, but the rest of it matches -in the naming. Parts of the JavaScript `Date` API that are not consistent across browsers and JS -implementations are not exposed in a type-safe manner, you should access the underlying `jsObject` -property if you need those. -*/ +/** A wrapper around the [JavaScript Date + class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) that + exposes its properties in a type-safe way. This doesn't 100% match the JS API, for example + `getMonth`/`setMonth` etc accessor methods are converted to properties, but the rest of it matches + in the naming. Parts of the JavaScript `Date` API that are not consistent across browsers and JS + implementations are not exposed in a type-safe manner, you should access the underlying `jsObject` + property if you need those. + */ public final class JSDate: JSBridgedClass { /// The constructor function used to create new `Date` objects. - public static let constructor = JSObject.global.Date.function! + public static let constructor = JSObject.global.Date.function /// The underlying JavaScript `Date` object. public let jsObject: JSObject /** Creates a new instance of the JavaScript `Date` class with a given amount of milliseconds - that passed since midnight 01 January 1970 UTC. - */ + that passed since midnight 01 January 1970 UTC. + */ public init(millisecondsSinceEpoch: Double? = nil) { if let milliseconds = millisecondsSinceEpoch { - jsObject = Self.constructor.new(milliseconds) + jsObject = Self.constructor!.new(milliseconds) } else { - jsObject = Self.constructor.new() + jsObject = Self.constructor!.new() } } - /** According to the standard, `monthIndex` is zero-indexed, where `11` is December. `day` - represents a day of the month starting at `1`. - */ + /** According to the standard, `monthIndex` is zero-indexed, where `11` is December. `day` + represents a day of the month starting at `1`. + */ public init( year: Int, monthIndex: Int, @@ -36,7 +36,7 @@ public final class JSDate: JSBridgedClass { seconds: Int = 0, milliseconds: Int = 0 ) { - jsObject = Self.constructor.new(year, monthIndex, day, hours, minutes, seconds, milliseconds) + jsObject = Self.constructor!.new(year, monthIndex, day, hours, minutes, seconds, milliseconds) } public init(unsafelyWrapping jsObject: JSObject) { @@ -198,7 +198,7 @@ public final class JSDate: JSBridgedClass { Int(jsObject.getTimezoneOffset!().number!) } - /// Returns a string conforming to ISO 8601 that contains date and time, e.g. + /// Returns a string conforming to ISO 8601 that contains date and time, e.g. /// `"2020-09-15T08:56:54.811Z"`. public func toISOString() -> String { jsObject.toISOString!().string! @@ -214,25 +214,25 @@ public final class JSDate: JSBridgedClass { jsObject.toLocaleTimeString!().string! } - /** Returns a string formatted according to - [rfc7231](https://tools.ietf.org/html/rfc7231#section-7.1.1.1) and modified according to - [ecma-262](https://www.ecma-international.org/ecma-262/10.0/index.html#sec-date.prototype.toutcstring), - e.g. `Tue, 15 Sep 2020 09:04:40 GMT`. - */ + /** Returns a string formatted according to + [rfc7231](https://tools.ietf.org/html/rfc7231#section-7.1.1.1) and modified according to + [ecma-262](https://www.ecma-international.org/ecma-262/10.0/index.html#sec-date.prototype.toutcstring), + e.g. `Tue, 15 Sep 2020 09:04:40 GMT`. + */ public func toUTCString() -> String { jsObject.toUTCString!().string! } - /** Number of milliseconds since midnight 01 January 1970 UTC to the present moment ignoring - leap seconds. - */ + /** Number of milliseconds since midnight 01 January 1970 UTC to the present moment ignoring + leap seconds. + */ public static func now() -> Double { - constructor.now!().number! + constructor!.now!().number! } - /** Number of milliseconds since midnight 01 January 1970 UTC to the given date ignoring leap - seconds. - */ + /** Number of milliseconds since midnight 01 January 1970 UTC to the given date ignoring leap + seconds. + */ public func valueOf() -> Double { jsObject.valueOf!().number! } diff --git a/Sources/JavaScriptKit/BasicObjects/JSError.swift b/Sources/JavaScriptKit/BasicObjects/JSError.swift index cbdac8d6e..1d1526a47 100644 --- a/Sources/JavaScriptKit/BasicObjects/JSError.swift +++ b/Sources/JavaScriptKit/BasicObjects/JSError.swift @@ -1,17 +1,17 @@ -/** A wrapper around [the JavaScript Error -class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) that -exposes its properties in a type-safe way. -*/ +/** A wrapper around [the JavaScript Error + class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) that + exposes its properties in a type-safe way. + */ public final class JSError: Error, JSBridgedClass { /// The constructor function used to create new JavaScript `Error` objects. - public static let constructor = JSObject.global.Error.function! + public static let constructor = JSObject.global.Error.function /// The underlying JavaScript `Error` object. public let jsObject: JSObject /// Creates a new instance of the JavaScript `Error` class with a given message. public init(message: String) { - jsObject = Self.constructor.new([message]) + jsObject = Self.constructor!.new([message]) } public init(unsafelyWrapping jsObject: JSObject) { diff --git a/Sources/JavaScriptKit/BasicObjects/JSPromise.swift b/Sources/JavaScriptKit/BasicObjects/JSPromise.swift index 0aa44cadd..81a124447 100644 --- a/Sources/JavaScriptKit/BasicObjects/JSPromise.swift +++ b/Sources/JavaScriptKit/BasicObjects/JSPromise.swift @@ -1,14 +1,14 @@ /** A wrapper around [the JavaScript `Promise` class](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) -that exposes its functions in a type-safe and Swifty way. The `JSPromise` API is generic over both -`Success` and `Failure` types, which improves compatibility with other statically-typed APIs such -as Combine. If you don't know the exact type of your `Success` value, you should use `JSValue`, e.g. -`JSPromise`. In the rare case, where you can't guarantee that the error thrown -is of actual JavaScript `Error` type, you should use `JSPromise`. + that exposes its functions in a type-safe and Swifty way. The `JSPromise` API is generic over both + `Success` and `Failure` types, which improves compatibility with other statically-typed APIs such + as Combine. If you don't know the exact type of your `Success` value, you should use `JSValue`, e.g. + `JSPromise`. In the rare case, where you can't guarantee that the error thrown + is of actual JavaScript `Error` type, you should use `JSPromise`. -This doesn't 100% match the JavaScript API, as `then` overload with two callbacks is not available. -It's impossible to unify success and failure types from both callbacks in a single returned promise -without type erasure. You should chain `then` and `catch` in those cases to avoid type erasure. -*/ + This doesn't 100% match the JavaScript API, as `then` overload with two callbacks is not available. + It's impossible to unify success and failure types from both callbacks in a single returned promise + without type erasure. You should chain `then` and `catch` in those cases to avoid type erasure. + */ public final class JSPromise: JSBridgedClass { /// The underlying JavaScript `Promise` object. public let jsObject: JSObject @@ -18,35 +18,35 @@ public final class JSPromise: JSBridgedClass { .object(jsObject) } - public static var constructor: JSFunction { + public static var constructor: JSFunction? { JSObject.global.Promise.function! } /// This private initializer assumes that the passed object is a JavaScript `Promise` public init(unsafelyWrapping object: JSObject) { - self.jsObject = object + jsObject = object } /** Creates a new `JSPromise` instance from a given JavaScript `Promise` object. If `jsObject` - is not an instance of JavaScript `Promise`, this initializer will return `nil`. - */ + is not an instance of JavaScript `Promise`, this initializer will return `nil`. + */ public convenience init?(_ jsObject: JSObject) { self.init(from: jsObject) } /** Creates a new `JSPromise` instance from a given JavaScript `Promise` object. If `value` - is not an object and is not an instance of JavaScript `Promise`, this function will - return `nil`. - */ + is not an object and is not an instance of JavaScript `Promise`, this function will + return `nil`. + */ public static func construct(from value: JSValue) -> Self? { guard case let .object(jsObject) = value else { return nil } - return Self.init(jsObject) + return Self(jsObject) } /** Creates a new `JSPromise` instance from a given `resolver` closure. `resolver` takes - two closure that your code should call to either resolve or reject this `JSPromise` instance. - */ - public convenience init(resolver: @escaping (@escaping (Result) -> ()) -> ()) { + two closure that your code should call to either resolve or reject this `JSPromise` instance. + */ + public convenience init(resolver: @escaping (@escaping (Result) -> Void) -> Void) { let closure = JSOneshotClosure { arguments in // The arguments are always coming from the `Promise` constructor, so we should be // safe to assume their type here @@ -63,19 +63,19 @@ public final class JSPromise: JSBridgedClass { } return .undefined } - self.init(unsafelyWrapping: Self.constructor.new(closure)) + self.init(unsafelyWrapping: Self.constructor!.new(closure)) } public static func resolve(_ value: ConvertibleToJSValue) -> JSPromise { - self.init(unsafelyWrapping: Self.constructor.resolve!(value).object!) + self.init(unsafelyWrapping: Self.constructor!.resolve!(value).object!) } public static func reject(_ reason: ConvertibleToJSValue) -> JSPromise { - self.init(unsafelyWrapping: Self.constructor.reject!(reason).object!) + self.init(unsafelyWrapping: Self.constructor!.reject!(reason).object!) } /** Schedules the `success` closure to be invoked on sucessful completion of `self`. - */ + */ @discardableResult public func then(success: @escaping (JSValue) -> ConvertibleToJSValue) -> JSPromise { let closure = JSOneshotClosure { @@ -85,10 +85,12 @@ public final class JSPromise: JSBridgedClass { } /** Schedules the `success` closure to be invoked on sucessful completion of `self`. - */ + */ @discardableResult - public func then(success: @escaping (JSValue) -> ConvertibleToJSValue, - failure: @escaping (JSValue) -> ConvertibleToJSValue) -> JSPromise { + public func then( + success: @escaping (JSValue) -> ConvertibleToJSValue, + failure: @escaping (JSValue) -> ConvertibleToJSValue + ) -> JSPromise { let successClosure = JSOneshotClosure { success($0[0]).jsValue } @@ -99,7 +101,7 @@ public final class JSPromise: JSBridgedClass { } /** Schedules the `failure` closure to be invoked on rejected completion of `self`. - */ + */ @discardableResult public func `catch`(failure: @escaping (JSValue) -> ConvertibleToJSValue) -> JSPromise { let closure = JSOneshotClosure { @@ -108,11 +110,11 @@ public final class JSPromise: JSBridgedClass { return .init(unsafelyWrapping: jsObject.catch!(closure).object!) } - /** Schedules the `failure` closure to be invoked on either successful or rejected completion of - `self`. - */ + /** Schedules the `failure` closure to be invoked on either successful or rejected completion of + `self`. + */ @discardableResult - public func finally(successOrFailure: @escaping () -> ()) -> JSPromise { + public func finally(successOrFailure: @escaping () -> Void) -> JSPromise { let closure = JSOneshotClosure { _ in successOrFailure() return .undefined diff --git a/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift b/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift index 39ec2aa21..a32c22203 100644 --- a/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift +++ b/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift @@ -13,7 +13,7 @@ public protocol TypedArrayElement: ConvertibleToJSValue, ConstructibleFromJSValu /// A wrapper around all JavaScript [TypedArray](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) /// classes that exposes their properties in a type-safe way. public class JSTypedArray: JSBridgedClass, ExpressibleByArrayLiteral where Element: TypedArrayElement { - public class var constructor: JSFunction { Element.typedArrayClass } + public class var constructor: JSFunction? { Element.typedArrayClass } public var jsObject: JSObject public subscript(_ index: Int) -> Element { @@ -21,7 +21,7 @@ public class JSTypedArray: JSBridgedClass, ExpressibleByArrayLiteral wh return Element.construct(from: jsObject[index])! } set { - self.jsObject[index] = newValue.jsValue + jsObject[index] = newValue.jsValue } } @@ -30,22 +30,23 @@ public class JSTypedArray: JSBridgedClass, ExpressibleByArrayLiteral wh /// /// - Parameter length: The number of elements that will be allocated. public init(length: Int) { - jsObject = Self.constructor.new(length) + jsObject = Self.constructor!.new(length) } - required public init(unsafelyWrapping jsObject: JSObject) { + public required init(unsafelyWrapping jsObject: JSObject) { self.jsObject = jsObject } - required public convenience init(arrayLiteral elements: Element...) { + public required convenience init(arrayLiteral elements: Element...) { self.init(elements) } + /// Initialize a new instance of TypedArray in JavaScript environment with given elements. /// /// - Parameter array: The array that will be copied to create a new instance of TypedArray public convenience init(_ array: [Element]) { let jsArrayRef = array.withUnsafeBufferPointer { ptr in - _create_typed_array(Self.constructor.id, ptr.baseAddress!, Int32(array.count)) + _create_typed_array(Self.constructor!.id, ptr.baseAddress!, Int32(array.count)) } self.init(unsafelyWrapping: JSObject(id: jsArrayRef)) } @@ -80,7 +81,7 @@ public class JSTypedArray: JSBridgedClass, ExpressibleByArrayLiteral wh let rawBuffer = malloc(bytesLength)! defer { free(rawBuffer) } _load_typed_array(jsObject.id, rawBuffer.assumingMemoryBound(to: UInt8.self)) - let length = lengthInBytes / MemoryLayout.size + let length = lengthInBytes / MemoryLayout.size let boundPtr = rawBuffer.bindMemory(to: Element.self, capacity: length) let bufferPtr = UnsafeBufferPointer(start: boundPtr, count: length) let result = try body(bufferPtr) @@ -105,6 +106,7 @@ extension Int: TypedArrayElement { public static var typedArrayClass: JSFunction = valueForBitWidth(typeName: "Int", bitWidth: Int.bitWidth, when32: JSObject.global.Int32Array).function! } + extension UInt: TypedArrayElement { public static var typedArrayClass: JSFunction = valueForBitWidth(typeName: "UInt", bitWidth: Int.bitWidth, when32: JSObject.global.Uint32Array).function! @@ -113,17 +115,19 @@ extension UInt: TypedArrayElement { extension Int8: TypedArrayElement { public static var typedArrayClass = JSObject.global.Int8Array.function! } + extension UInt8: TypedArrayElement { public static var typedArrayClass = JSObject.global.Uint8Array.function! } public class JSUInt8ClampedArray: JSTypedArray { - public class override var constructor: JSFunction { JSObject.global.Uint8ClampedArray.function! } + override public class var constructor: JSFunction? { JSObject.global.Uint8ClampedArray.function! } } extension Int16: TypedArrayElement { public static var typedArrayClass = JSObject.global.Int16Array.function! } + extension UInt16: TypedArrayElement { public static var typedArrayClass = JSObject.global.Uint16Array.function! } @@ -131,6 +135,7 @@ extension UInt16: TypedArrayElement { extension Int32: TypedArrayElement { public static var typedArrayClass = JSObject.global.Int32Array.function! } + extension UInt32: TypedArrayElement { public static var typedArrayClass = JSObject.global.Uint32Array.function! } @@ -138,6 +143,7 @@ extension UInt32: TypedArrayElement { extension Float32: TypedArrayElement { public static var typedArrayClass = JSObject.global.Float32Array.function! } + extension Float64: TypedArrayElement { public static var typedArrayClass = JSObject.global.Float64Array.function! } diff --git a/Sources/JavaScriptKit/JSBridgedType.swift b/Sources/JavaScriptKit/JSBridgedType.swift index 235d78331..dcc0a3857 100644 --- a/Sources/JavaScriptKit/JSBridgedType.swift +++ b/Sources/JavaScriptKit/JSBridgedType.swift @@ -5,18 +5,18 @@ public protocol JSBridgedType: JSValueCompatible, CustomStringConvertible { init?(from value: JSValue) } -extension JSBridgedType { - public static func construct(from value: JSValue) -> Self? { - Self.init(from: value) +public extension JSBridgedType { + static func construct(from value: JSValue) -> Self? { + Self(from: value) } - public var description: String { jsValue.description } + var description: String { jsValue.description } } /// Conform to this protocol when your Swift class wraps a JavaScript class. public protocol JSBridgedClass: JSBridgedType { /// The constructor function for the JavaScript class - static var constructor: JSFunction { get } + static var constructor: JSFunction? { get } /// The JavaScript object wrapped by this instance. /// You may assume that `jsObject instanceof Self.constructor == true` @@ -27,16 +27,16 @@ public protocol JSBridgedClass: JSBridgedType { init(unsafelyWrapping jsObject: JSObject) } -extension JSBridgedClass { - public var jsValue: JSValue { jsObject.jsValue } +public extension JSBridgedClass { + var jsValue: JSValue { jsObject.jsValue } - public init?(from value: JSValue) { + init?(from value: JSValue) { guard let object = value.object else { return nil } self.init(from: object) } - public init?(from object: JSObject) { - guard object.isInstanceOf(Self.constructor) else { return nil } + init?(from object: JSObject) { + guard let constructor = Self.constructor, object.isInstanceOf(constructor) else { return nil } self.init(unsafelyWrapping: object) } }