Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2eade6f

Browse files
Merge pull request #55 from swiftwasm/add-doc-comments
Add doc comments for public APIs (Part 1)
2 parents 51331c6 + 5f2eac9 commit 2eade6f

File tree

3 files changed

+153
-16
lines changed

3 files changed

+153
-16
lines changed

‎Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift‎

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
11
import _CJavaScriptKit
22

3+
/// `JSFunction` represents a function in JavaScript and supports new object instantiation.
4+
/// This type can be callable as a function using `callAsFunction`.
5+
///
6+
/// e.g.
7+
/// ```swift
8+
/// let alert: JSFunction = JSObject.global.alert.function!
9+
/// // Call `JSFunction` as a function
10+
/// alert("Hello, world")
11+
/// ```
12+
///
313
public class JSFunction: JSObject {
14+
15+
/// Call this function with given `arguments` and binding given `this` as context.
16+
/// - Parameters:
17+
/// - this: The value to be passed as the `this` parameter to this function.
18+
/// - arguments: Arguments to be passed to this function.
19+
/// - Returns: The result of this call.
420
@discardableResult
521
public func callAsFunction(this: JSObject? = nil, arguments: [JSValueConvertible]) -> JSValue {
622
let result = arguments.withRawJSValues { rawValues in
@@ -24,19 +40,22 @@ public class JSFunction: JSObject {
2440
return result.jsValue()
2541
}
2642

43+
/// A variadic arguments version of `callAsFunction`.
2744
@discardableResult
2845
public func callAsFunction(this: JSObject? = nil, _ arguments: JSValueConvertible...) -> JSValue {
2946
self(this: this, arguments: arguments)
3047
}
3148

32-
public func new(_ arguments: JSValueConvertible...) -> JSObject {
33-
new(arguments: arguments)
34-
}
35-
36-
// Guaranteed to return an object because either:
37-
// a) the constructor explicitly returns an object, or
38-
// b) the constructor returns nothing, which causes JS to return the `this` value, or
39-
// c) the constructor returns undefined, null or a non-object, in which case JS also returns `this`.
49+
/// Instantiate an object from this function as a constructor.
50+
///
51+
/// Guaranteed to return an object because either:
52+
///
53+
/// - a. the constructor explicitly returns an object, or
54+
/// - b. the constructor returns nothing, which causes JS to return the `this` value, or
55+
/// - c. the constructor returns undefined, null or a non-object, in which case JS also returns `this`.
56+
///
57+
/// - Parameter arguments: Arguments to be passed to this constructor function.
58+
/// - Returns: A new instance of this constructor.
4059
public func new(arguments: [JSValueConvertible]) -> JSObject {
4160
arguments.withRawJSValues { rawValues in
4261
rawValues.withUnsafeBufferPointer { bufferPointer in
@@ -52,6 +71,11 @@ public class JSFunction: JSObject {
5271
}
5372
}
5473

74+
/// A variadic arguments version of `new`.
75+
public func new(_ arguments: JSValueConvertible...) -> JSObject {
76+
new(arguments: arguments)
77+
}
78+
5579
@available(*, unavailable, message: "Please use JSClosure instead")
5680
public static func from(_: @escaping ([JSValue]) -> JSValue) -> JSFunction {
5781
fatalError("unavailable")
@@ -62,33 +86,59 @@ public class JSFunction: JSObject {
6286
}
6387
}
6488

89+
/// `JSClosure` represents a JavaScript function the body of which is written in Swift.
90+
/// This type can be passed as a callback handler to JavaScript functions.
91+
/// Note that the lifetime of `JSClosure` should be managed by users manually
92+
/// due to GC boundary between Swift and JavaScript.
93+
/// For further discussion, see also [swiftwasm/JavaScriptKit #33](https://github.com/swiftwasm/JavaScriptKit/pull/33)
94+
///
95+
/// e.g.
96+
/// ```swift
97+
/// let eventListenter = JSClosure { _ in
98+
/// ...
99+
/// return JSValue.undefined
100+
/// }
101+
///
102+
/// button.addEventListener!("click", JSValue.function(eventListenter))
103+
/// ...
104+
/// button.removeEventListener!("click", JSValue.function(eventListenter))
105+
/// eventListenter.release()
106+
/// ```
107+
///
65108
public class JSClosure: JSFunction {
66109
static var sharedFunctions: [JavaScriptHostFuncRef: ([JSValue]) -> JSValue] = [:]
67110

68111
private var hostFuncRef: JavaScriptHostFuncRef = 0
69112

70113
private var isReleased = false
71-
114+
115+
/// Instantiate a new `JSClosure` with given function body.
116+
/// - Parameter body: The body of this function.
72117
public init(_ body: @escaping ([JSValue]) -> JSValue) {
118+
// 1. Fill `id` as zero at first to access `self` to get `ObjectIdentifier`.
73119
super.init(id: 0)
74120
let objectId = ObjectIdentifier(self)
75121
let funcRef = JavaScriptHostFuncRef(bitPattern: Int32(objectId.hashValue))
122+
// 2. Retain the given body in static storage by `funcRef`.
76123
Self.sharedFunctions[funcRef] = body
77-
124+
// 3. Create a new JavaScript function which calls the given Swift function.
78125
var objectRef: JavaScriptObjectRef = 0
79126
_create_function(funcRef, &objectRef)
80127

81128
hostFuncRef = funcRef
82129
id = objectRef
83130
}
84-
131+
132+
/// A convenience initializer which assumes that the given body function returns `JSValue.undefined`
85133
convenience public init(_ body: @escaping ([JSValue]) -> ()) {
86134
self.init { (arguments: [JSValue]) -> JSValue in
87135
body(arguments)
88136
return .undefined
89137
}
90138
}
91-
139+
140+
/// Release this function resource.
141+
/// After calling `release`, calling this function from JavaScript will fail.
92142
public func release() {
93143
Self.sharedFunctions[hostFuncRef] = nil
94144
isReleased = true

‎Sources/JavaScriptKit/FundamentalObjects/JSObject.swift‎

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,36 @@
11
import _CJavaScriptKit
22

3+
/// `JSObject` represents an object in JavaScript and supports dynamic member lookup.
4+
/// Any member access like `object.foo` will dynamically request the JavaScript and Swift
5+
/// runtime bridge library for a member with the specified name in this object.
6+
///
7+
/// And this object supports to call a member method of the object.
8+
///
9+
/// e.g.
10+
/// ```swift
11+
/// let document = JSObject.global.document.object!
12+
/// let divElement = document.createElement!("div")
13+
/// ```
14+
///
15+
/// The lifetime of this object is managed by the JavaScript and Swift runtime bridge library with
16+
/// reference counting system.
317
@dynamicMemberLookup
418
public class JSObject: Equatable {
5-
internal var id: UInt32
6-
init(id: UInt32) {
19+
internal var id: JavaScriptObjectRef
20+
init(id: JavaScriptObjectRef) {
721
self.id = id
822
}
923

24+
/// Returns the `name` member method binding this object as `this` context.
25+
///
26+
/// e.g.
27+
/// ```swift
28+
/// let document = JSObject.global.document.object!
29+
/// let divElement = document.createElement!("div")
30+
/// ```
31+
///
32+
/// - Parameter name: The name of this object's member to access.
33+
/// - Returns: The `name` member method binding this object as `this` context.
1034
@_disfavoredOverload
1135
public subscript(dynamicMember name: String) -> ((JSValueConvertible...) -> JSValue)? {
1236
guard let function = self[name].function else { return nil }
@@ -15,30 +39,49 @@ public class JSObject: Equatable {
1539
}
1640
}
1741

42+
/// A convenience method of `subscript(_ name: String) -> JSValue`
43+
/// to access the member through Dynamic Member Lookup.
1844
public subscript(dynamicMember name: String) -> JSValue {
1945
get { self[name] }
2046
set { self[name] = newValue }
2147
}
2248

49+
/// Access the `name` member dynamically through JavaScript and Swift runtime bridge library.
50+
/// - Parameter name: The name of this object's member to access.
51+
/// - Returns: The value of the `name` member of this object.
2352
public subscript(_ name: String) -> JSValue {
2453
get { getJSValue(this: self, name: name) }
2554
set { setJSValue(this: self, name: name, value: newValue) }
2655
}
2756

57+
/// Access the `index` member dynamically through JavaScript and Swift runtime bridge library.
58+
/// - Parameter index: The index of this object's member to access.
59+
/// - Returns: The value of the `index` member of this object.
2860
public subscript(_ index: Int) -> JSValue {
2961
get { getJSValue(this: self, index: Int32(index)) }
3062
set { setJSValue(this: self, index: Int32(index), value: newValue) }
3163
}
3264

65+
/// Return `true` if this object is an instance of the `constructor`. Return `false`, if not.
66+
/// - Parameter constructor: The constructor function to check.
67+
/// - Returns: The result of `instanceof` in JavaScript environment.
3368
public func isInstanceOf(_ constructor: JSFunction) -> Bool {
3469
_instanceof(id, constructor.id)
3570
}
3671

3772
static let _JS_Predef_Value_Global: JavaScriptObjectRef = 0
73+
74+
/// A `JSObject` of the global scope object.
75+
/// This allows access to the global properties and global names by accessing the `JSObject` returned.
3876
public static let global = JSObject(id: _JS_Predef_Value_Global)
3977

4078
deinit { _release(id) }
4179

80+
/// Returns a Boolean value indicating whether two values point to same objects.
81+
///
82+
/// - Parameters:
83+
/// - lhs: A object to compare.
84+
/// - rhs: Another object to compare.
4285
public static func == (lhs: JSObject, rhs: JSObject) -> Bool {
4386
return lhs.id == rhs.id
4487
}

‎Sources/JavaScriptKit/JSValue.swift‎

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import _CJavaScriptKit
22

3+
/// `JSValue` represents a value in JavaScript.
34
public enum JSValue: Equatable {
45
case boolean(Bool)
56
case string(String)
@@ -9,45 +10,88 @@ public enum JSValue: Equatable {
910
case undefined
1011
case function(JSFunction)
1112

13+
/// Returns the `Bool` value of this JS value if its type is boolean.
14+
/// If not, returns `nil`.
1215
public var boolean: Bool? {
1316
switch self {
1417
case let .boolean(boolean): return boolean
1518
default: return nil
1619
}
1720
}
1821

22+
/// Returns the `String` value of this JS value if the type is string.
23+
/// If not, returns `nil`.
1924
public var string: String? {
2025
switch self {
2126
case let .string(string): return string
2227
default: return nil
2328
}
2429
}
2530

31+
/// Returns the `Double` value of this JS value if the type is number.
32+
/// If not, returns `nil`.
2633
public var number: Double? {
2734
switch self {
2835
case let .number(number): return number
2936
default: return nil
3037
}
3138
}
3239

40+
/// Returns the `JSObject` of this JS value if its type is object.
41+
/// If not, returns `nil`.
3342
public var object: JSObject? {
3443
switch self {
3544
case let .object(object): return object
3645
default: return nil
3746
}
3847
}
3948

40-
publicvarisNull:Bool{returnself==.null }
41-
publicvarisUndefined:Bool{returnself==.undefined }
49+
/// Returns the `JSFunction` of this JS value if its type is function.
50+
/// If not, returns `nil`.
4251
public var function: JSFunction? {
4352
switch self {
4453
case let .function(function): return function
4554
default: return nil
4655
}
4756
}
57+
58+
/// Returns the `true` if this JS value is null.
59+
/// If not, returns `false`.
60+
public var isNull: Bool { return self == .null }
61+
62+
/// Returns the `true` if this JS value is undefined.
63+
/// If not, returns `false`.
64+
public var isUndefined: Bool { return self == .undefined }
65+
4866
}
4967

5068
extension JSValue {
69+
70+
/// Deprecated: Please create `JSClosure` directly and manage its lifetime manually.
71+
///
72+
/// Migrate this usage
73+
///
74+
/// ```swift
75+
/// button.addEventListener!("click", JSValue.function { _ in
76+
/// ...
77+
/// return JSValue.undefined
78+
/// })
79+
/// ```
80+
///
81+
/// into below code.
82+
///
83+
/// ```swift
84+
/// let eventListenter = JSClosure { _ in
85+
/// ...
86+
/// return JSValue.undefined
87+
/// }
88+
///
89+
/// button.addEventListener!("click", JSValue.function(eventListenter))
90+
/// ...
91+
/// button.removeEventListener!("click", JSValue.function(eventListenter))
92+
/// eventListenter.release()
93+
/// ```
94+
@available(*, deprecated, message: "Please create JSClosure directly and manage its lifetime manually.")
5195
public static func function(_ body: @escaping ([JSValue]) -> JSValue) -> JSValue {
5296
.function(JSClosure(body))
5397
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /