Skip to content

Cleanup unused code, fix event handlers crash #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Build and test

on:
pull_request:
push:
branches: [main]

jobs:
macos_test:
runs-on: macos-11.0

steps:
- uses: actions/checkout@v2
- name: Run the test suite on macOS
shell: bash
run: |
set -ex
sudo xcode-select --switch /Applications/Xcode_12.3.app/Contents/Developer/

brew install swiftwasm/tap/carton

carton test --environment defaultBrowser
32 changes: 11 additions & 21 deletions Sources/DOMKit/ECMAScript/Support.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,34 +38,19 @@ public class ReadableStream: JSBridgedClass {
}
}

@propertyWrapper public struct ClosureHandler<ArgumentType: JSValueCompatible, ReturnType: JSValueCompatible> {

@propertyWrapper public final class OptionalClosureHandler<ArgumentType, ReturnType>
where ArgumentType: JSValueCompatible, ReturnType: JSValueCompatible {
let jsObject: JSObject
let name: String
var closure: JSClosure?

public init(jsObject: JSObject, name: String) {
self.jsObject = jsObject
self.name = name
}

public var wrappedValue: (ArgumentType) -> ReturnType {
get {
{ arg in jsObject[name]!(arg).fromJSValue()! }
}
set {
jsObject[name] = JSClosure { newValue($0[0].fromJSValue()!).jsValue() }.jsValue()
}
}
}

@propertyWrapper public struct OptionalClosureHandler<ArgumentType: JSValueCompatible, ReturnType: JSValueCompatible> {

let jsObject: JSObject
let name: String

public init(jsObject: JSObject, name: String) {
self.jsObject = jsObject
self.name = name
deinit {
closure?.release()
}

public var wrappedValue: ((ArgumentType) -> ReturnType)? {
Expand All @@ -76,8 +61,13 @@ public class ReadableStream: JSBridgedClass {
return { function($0.jsValue()).fromJSValue()! }
}
set {
if let closure = closure {
closure.release()
}
if let newValue = newValue {
jsObject[name] = JSClosure { newValue($0[0].fromJSValue()!).jsValue() }.jsValue()
let closure = JSClosure { newValue($0[0].fromJSValue()!).jsValue() }
jsObject[name] = closure.jsValue()
self.closure = closure
} else {
jsObject[name] = .null
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/DOMKit/WebIDL/AddEventListenerOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public struct AddEventListenerOptions: ExpressibleByDictionaryLiteral, JSBridged

private let dictionary: [String: JSValue]

public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) {
public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) {
public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

Expand Down
16 changes: 0 additions & 16 deletions Sources/DOMKit/WebIDL/AnyDocumentAndElementEventHandlers.swift

This file was deleted.

16 changes: 0 additions & 16 deletions Sources/DOMKit/WebIDL/AnyGlobalEventHandlers.swift

This file was deleted.

56 changes: 55 additions & 1 deletion Sources/DOMKit/WebIDL/ArrayBufferView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,58 @@

import JavaScriptKit

public typealias ArrayBufferView = Int8ArrayOrInt16ArrayOrInt32ArrayOrUint8ArrayOrUint16ArrayOrUint32ArrayOrUint8ClampedArrayOrFloat32ArrayOrFloat64ArrayOrDataView
public enum ArrayBufferView: JSBridgedType {
case int8Array(JSTypedArray<Int8>)
case int16Array(JSTypedArray<Int16>)
case int32Array(JSTypedArray<Int32>)
case uint8Array(JSTypedArray<UInt8>)
case uint16Array(JSTypedArray<UInt16>)
case uint32Array(JSTypedArray<UInt32>)
case uint8ClampedArray(JSTypedArray<UInt8>)
case float32Array(JSTypedArray<Float>)
case float64Array(JSTypedArray<Double>)
case dataView(DataView)

public init?(from value: JSValue) {
if let decoded: JSTypedArray<Int8> = value.fromJSValue() {
self = .int8Array(decoded)
} else if let decoded: JSTypedArray<Int16> = value.fromJSValue() {
self = .int16Array(decoded)
} else if let decoded: JSTypedArray<Int32> = value.fromJSValue() {
self = .int32Array(decoded)
} else if let decoded: JSTypedArray<UInt8> = value.fromJSValue() {
self = .uint8Array(decoded)
} else if let decoded: JSTypedArray<UInt16> = value.fromJSValue() {
self = .uint16Array(decoded)
} else if let decoded: JSTypedArray<UInt32> = value.fromJSValue() {
self = .uint32Array(decoded)
} else if let decoded: JSTypedArray<UInt8> = value.fromJSValue() {
self = .uint8ClampedArray(decoded)
} else if let decoded: JSTypedArray<Float> = value.fromJSValue() {
self = .float32Array(decoded)
} else if let decoded: JSTypedArray<Double> = value.fromJSValue() {
self = .float64Array(decoded)
} else if let decoded: DataView = value.fromJSValue() {
self = .dataView(decoded)
} else {
return nil
}
}

public var value: JSValue { jsValue() }

public func jsValue() -> JSValue {
switch self {
case let .int8Array(v): return v.jsValue()
case let .int16Array(v): return v.jsValue()
case let .int32Array(v): return v.jsValue()
case let .uint8Array(v): return v.jsValue()
case let .uint16Array(v): return v.jsValue()
case let .uint32Array(v): return v.jsValue()
case let .uint8ClampedArray(v): return v.jsValue()
case let .float32Array(v): return v.jsValue()
case let .float64Array(v): return v.jsValue()
case let .dataView(v): return v.jsValue()
}
}
}
4 changes: 2 additions & 2 deletions Sources/DOMKit/WebIDL/AssignedNodesOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public struct AssignedNodesOptions: ExpressibleByDictionaryLiteral, JSBridgedTyp

private let dictionary: [String: JSValue]

public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) {
public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) {
public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/DOMKit/WebIDL/BlobPropertyBag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public struct BlobPropertyBag: ExpressibleByDictionaryLiteral, JSBridgedType {

private let dictionary: [String: JSValue]

public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) {
public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) {
public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/DOMKit/WebIDL/CustomEventInit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public struct CustomEventInit: ExpressibleByDictionaryLiteral, JSBridgedType {

private let dictionary: [String: JSValue]

public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) {
public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) {
public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/DOMKit/WebIDL/ElementCreationOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public struct ElementCreationOptions: ExpressibleByDictionaryLiteral, JSBridgedT

private let dictionary: [String: JSValue]

public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) {
public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) {
public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/DOMKit/WebIDL/EndingType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import JavaScriptKit

public enum EndingType: String, JSValueCodable {
public enum EndingType: String, JSValueCompatible {
public static func construct(from jsValue: JSValue) -> EndingType? {
if let string = jsValue.string,
let value = EndingType(rawValue: string)
Expand Down
4 changes: 2 additions & 2 deletions Sources/DOMKit/WebIDL/EventInit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public struct EventInit: ExpressibleByDictionaryLiteral, JSBridgedType {

private let dictionary: [String: JSValue]

public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) {
public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) {
public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/DOMKit/WebIDL/EventListener.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
import JavaScriptKit

public protocol EventListener: JSBridgedType {
func handleEvent(event: Event) -> Void
func handleEvent(event: Event)
}
4 changes: 2 additions & 2 deletions Sources/DOMKit/WebIDL/EventListenerOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public struct EventListenerOptions: ExpressibleByDictionaryLiteral, JSBridgedTyp

private let dictionary: [String: JSValue]

public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) {
public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) {
public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

Expand Down
61 changes: 55 additions & 6 deletions Sources/DOMKit/WebIDL/EventTarget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@
import JavaScriptKit

public class EventTarget: JSBridgedClass {
public struct Token {
var type: String
var index: Int
}
public class var constructor: JSFunction { JSObject.global.EventTarget.function! }

var eventListeners = [String: [JSClosure]]()

public let jsObject: JSObject

public required init(unsafelyWrapping jsObject: JSObject) {
Expand All @@ -18,20 +24,63 @@ public class EventTarget: JSBridgedClass {
self.init(unsafelyWrapping: EventTarget.constructor.new())
}

public func addEventListener<EventListenerType: EventListener>(type: String, callback: EventListenerType?, options: AddEventListenerOptionsOrBool = [:]) -> Void {
deinit {
for (_, listeners) in eventListeners {
for closure in listeners {
closure.release()
}
}
}

public func addEventListener<EventListenerType: EventListener>(
type: String,
options: AddEventListenerOptionsOrBool = [:],
callback: EventListenerType) {
_ = jsObject.addEventListener!(type.jsValue(), callback.jsValue(), options.jsValue())
}

public func addEventListener(type: String, callback: ((Event) -> Void)?, options: AddEventListenerOptionsOrBool = [:]) {
_ = jsObject.addEventListener!(type.jsValue(), callback == nil ? nil : JSClosure { callback!($0[0].fromJSValue()!) }, options.jsValue())
public func addEventListener(
type: String,
options: AddEventListenerOptionsOrBool = [:],
callback: @escaping (Event) -> ()
) -> Token {
let closure = JSClosure { callback($0[0].fromJSValue()!) }
let token: Token
let listeners: [JSClosure]
if var existingListeners = eventListeners[type] {
token = Token(type: type, index: existingListeners.count)
existingListeners.append(closure)
listeners = existingListeners
} else {
token = Token(type: type, index: 0)
listeners = [closure]
}
eventListeners[type] = listeners

_ = jsObject.addEventListener!(type.jsValue(), closure, options.jsValue())

return token
}

public func removeEventListener<EventListenerType: EventListener>(type: String, callback: EventListenerType?, options: EventListenerOptionsOrBool = [:]) -> Void {
public func removeEventListener<EventListenerType: EventListener>(
type: String,
options: EventListenerOptionsOrBool = [:],
callback: EventListenerType
) {
_ = jsObject.removeEventListener!(type.jsValue(), callback.jsValue(), options.jsValue())
}

public func removeEventListener(type: String, callback: ((Event) -> Void)?, options: EventListenerOptionsOrBool = [:]) {
_ = jsObject.removeEventListener!(type.jsValue(), callback == nil ? nil : JSClosure { callback!($0[0].fromJSValue()!) }, options.jsValue())
public func removeEventListener(
type: String,
token: Token,
options: EventListenerOptionsOrBool = [:]
) {
guard var listeners = eventListeners[type] else { return }

let closure = listeners[token.index]
_ = jsObject.removeEventListener!(type.jsValue(), closure, options.jsValue())
listeners.remove(at: token.index)
closure.release()
}

public func dispatchEvent(event: Event) -> Bool {
Expand Down
4 changes: 2 additions & 2 deletions Sources/DOMKit/WebIDL/FilePropertyBag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public struct FilePropertyBag: ExpressibleByDictionaryLiteral, JSBridgedType {

private let dictionary: [String: JSValue]

public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) {
public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) {
public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/DOMKit/WebIDL/FocusOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public struct FocusOptions: ExpressibleByDictionaryLiteral, JSBridgedType {

private let dictionary: [String: JSValue]

public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) {
public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) {
public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) {
dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) })
}

Expand Down
Loading