Skip to content

Commit cdbac17

Browse files
Merge pull request #312 from swiftwasm/maxd/jsdictionary
Make `JSObject` conform to `ExpressibleByDictionaryLiteral`
2 parents 334f297 + ec0bbe6 commit cdbac17

File tree

10 files changed

+65
-1
lines changed

10 files changed

+65
-1
lines changed

Runtime/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,8 @@ export class SwiftRuntime {
517517
return this.memory.retain(array.slice());
518518
},
519519

520+
swjs_create_object: () => { return this.memory.retain({}); },
521+
520522
swjs_load_typed_array: (ref: ref, buffer: pointer) => {
521523
const memory = this.memory;
522524
const typedArray = memory.getObject(ref);

Runtime/src/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ export interface ImportedFunctions {
102102
elementsPtr: pointer,
103103
length: number
104104
): number;
105+
swjs_create_object(): number;
105106
swjs_load_typed_array(ref: ref, buffer: pointer): void;
106107
swjs_release(ref: number): void;
107108
swjs_release_remote(tid: number, ref: number): void;

Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift

+10
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ public class JSOneshotClosure: JSObject, JSClosureProtocol {
3535
)
3636
}
3737

38+
@available(*, unavailable, message: "JSOneshotClosure does not support dictionary literal initialization")
39+
public required init(dictionaryLiteral elements: (String, JSValue)...) {
40+
fatalError("JSOneshotClosure does not support dictionary literal initialization")
41+
}
42+
3843
#if compiler(>=5.5) && !hasFeature(Embedded)
3944
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
4045
public static func async(_ body: sending @escaping (sending [JSValue]) async throws -> JSValue) -> JSOneshotClosure
@@ -122,6 +127,11 @@ public class JSClosure: JSFunction, JSClosureProtocol {
122127
Self.sharedClosures.wrappedValue[hostFuncRef] = (self, body)
123128
}
124129

130+
@available(*, unavailable, message: "JSClosure does not support dictionary literal initialization")
131+
public required init(dictionaryLiteral elements: (String, JSValue)...) {
132+
fatalError("JSClosure does not support dictionary literal initialization")
133+
}
134+
125135
#if compiler(>=5.5) && !hasFeature(Embedded)
126136
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
127137
public static func async(_ body: @Sendable @escaping (sending [JSValue]) async throws -> JSValue) -> JSClosure {

Sources/JavaScriptKit/FundamentalObjects/JSObject.swift

+14-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import _CJavaScriptKit
1515
/// The lifetime of this object is managed by the JavaScript and Swift runtime bridge library with
1616
/// reference counting system.
1717
@dynamicMemberLookup
18-
public class JSObject: Equatable {
18+
public class JSObject: Equatable, ExpressibleByDictionaryLiteral {
1919
internal static var constructor: JSFunction { _constructor.wrappedValue }
2020
private static let _constructor = LazyThreadLocal(initialize: { JSObject.global.Object.function! })
2121

@@ -38,6 +38,19 @@ public class JSObject: Equatable {
3838
#endif
3939
}
4040

41+
/// Creates an empty JavaScript object.
42+
public convenience init() {
43+
self.init(id: swjs_create_object())
44+
}
45+
46+
/// Creates a new object with the key-value pairs in the dictionary literal.
47+
///
48+
/// - Parameter elements: A variadic list of key-value pairs where all keys are strings
49+
public convenience required init(dictionaryLiteral elements: (String, JSValue)...) {
50+
self.init()
51+
for (key, value) in elements { self[key] = value }
52+
}
53+
4154
/// Asserts that the object is being accessed from the owner thread.
4255
///
4356
/// - Parameter hint: A string to provide additional context for debugging.

Sources/JavaScriptKit/FundamentalObjects/JSSymbol.swift

+5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ public class JSSymbol: JSObject {
2424
super.init(id: id)
2525
}
2626

27+
@available(*, unavailable, message: "JSSymbol does not support dictionary literal initialization")
28+
public required init(dictionaryLiteral elements: (String, JSValue)...) {
29+
fatalError("JSSymbol does not support dictionary literal initialization")
30+
}
31+
2732
public static func `for`(key: JSString) -> JSSymbol {
2833
Symbol.for!(key).symbol!
2934
}

Sources/JavaScriptKit/Runtime/index.d.ts

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/JavaScriptKit/Runtime/index.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/JavaScriptKit/Runtime/index.mjs

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/_CJavaScriptKit/include/_CJavaScriptKit.h

+2
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,8 @@ IMPORT_JS_FUNCTION(swjs_terminate_worker_thread, void, (int tid))
314314

315315
IMPORT_JS_FUNCTION(swjs_get_worker_thread_id, int, (void))
316316

317+
IMPORT_JS_FUNCTION(swjs_create_object, JavaScriptObjectRef, (void))
318+
317319
int swjs_get_worker_thread_id_cached(void);
318320

319321
/// Requests sending a JavaScript object to another worker thread.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import JavaScriptKit
2+
import XCTest
3+
4+
final class JSObjectTests: XCTestCase {
5+
func testEmptyObject() {
6+
let object = JSObject()
7+
let keys = JSObject.global.Object.function!.keys.function!(object)
8+
XCTAssertEqual(keys.array?.count, 0)
9+
}
10+
11+
func testInitWithDictionaryLiteral() {
12+
let object: JSObject = [
13+
"key1": 1,
14+
"key2": "value2",
15+
"key3": .boolean(true),
16+
"key4": .object(JSObject()),
17+
"key5": [1, 2, 3].jsValue,
18+
"key6": ["key": "value"].jsValue,
19+
]
20+
XCTAssertEqual(object.key1, .number(1))
21+
XCTAssertEqual(object.key2, "value2")
22+
XCTAssertEqual(object.key3, .boolean(true))
23+
let getKeys = JSObject.global.Object.function!.keys.function!
24+
XCTAssertEqual(getKeys(object.key4).array?.count, 0)
25+
XCTAssertEqual(object.key5.array.map(Array.init), [1, 2, 3])
26+
XCTAssertEqual(object.key6.object?.key, "value")
27+
}
28+
}

0 commit comments

Comments
 (0)