From 4eda06ff1da571e873d10fadabeff8446efd0db7 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 14 Sep 2020 22:07:36 +0100 Subject: [PATCH 1/4] Make `ref` private on `JSDate` No idea why I made it `public` in the first place... --- Sources/JavaScriptKit/BasicObjects/JSDate.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/JavaScriptKit/BasicObjects/JSDate.swift b/Sources/JavaScriptKit/BasicObjects/JSDate.swift index dc5653212..b470136f9 100644 --- a/Sources/JavaScriptKit/BasicObjects/JSDate.swift +++ b/Sources/JavaScriptKit/BasicObjects/JSDate.swift @@ -1,6 +1,6 @@ public final class JSDate { private static let constructor = JSObject.global.Date.function! - public let ref: JSObject + private let ref: JSObject public init(millisecondsSinceEpoch: Double? = nil) { if let milliseconds = millisecondsSinceEpoch { From 9d7057a54bd3c8b678e14f27854d5a3a7637844a Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 15 Sep 2020 10:09:11 +0100 Subject: [PATCH 2/4] Make `jsObject` public, add doc comments --- .../JavaScriptKit/BasicObjects/JSDate.swift | 137 +++++++++++------- .../JavaScriptKit/BasicObjects/JSError.swift | 6 +- 2 files changed, 84 insertions(+), 59 deletions(-) diff --git a/Sources/JavaScriptKit/BasicObjects/JSDate.swift b/Sources/JavaScriptKit/BasicObjects/JSDate.swift index b470136f9..e871c4ce6 100644 --- a/Sources/JavaScriptKit/BasicObjects/JSDate.swift +++ b/Sources/JavaScriptKit/BasicObjects/JSDate.swift @@ -1,12 +1,26 @@ +/** A wrapper around the [JavaScript Date +class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) 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 { + /// The constructor function used to create new `Date` objects. private static let constructor = JSObject.global.Date.function! - private let ref: JSObject + /// 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. + */ public init(millisecondsSinceEpoch: Double? = nil) { if let milliseconds = millisecondsSinceEpoch { - ref = Self.constructor.new(milliseconds) + jsObject = Self.constructor.new(milliseconds) } else { - ref = Self.constructor.new() + jsObject = Self.constructor.new() } } @@ -22,199 +36,210 @@ public final class JSDate { seconds: Int = 0, milliseconds: Int = 0 ) { - ref = Self.constructor.new(year, monthIndex, day, hours, minutes, seconds, milliseconds) + jsObject = Self.constructor.new(year, monthIndex, day, hours, minutes, seconds, milliseconds) } /// Year of this date in local time zone. public var fullYear: Int { get { - Int(ref.getFullYear!().number!) + Int(jsObject.getFullYear!().number!) } set { - _ = ref.setFullYear!(newValue) + _ = jsObject.setFullYear!(newValue) } } - /// Month of this date in `0–11` range in local time zone + /// Month of this date in `0–11` range in local time zone. public var month: Int { get { - Int(ref.getMonth!().number!) + Int(jsObject.getMonth!().number!) } set { - _ = ref.setMonth!(newValue) + _ = jsObject.setMonth!(newValue) } } /// The day of the month in `1..31` range in local time zone. public var date: Int { get { - Int(ref.getDate!().number!) + Int(jsObject.getDate!().number!) } set { - _ = ref.setDate!(newValue) + _ = jsObject.setDate!(newValue) } } /// The day of the week in `0..6` range in local time zone. public var day: Int { - Int(ref.getDay!().number!) + Int(jsObject.getDay!().number!) } /// The amount of hours in this day from `0..23` range in local time zone. public var hours: Int { get { - Int(ref.getHours!().number!) + Int(jsObject.getHours!().number!) } set { - _ = ref.setHours!(newValue) + _ = jsObject.setHours!(newValue) } } /// The amount of minutes in this hours from `0..59` range in local time zone. public var minutes: Int { get { - Int(ref.getMinutes!().number!) + Int(jsObject.getMinutes!().number!) } set { - _ = ref.setMinutes!(newValue) + _ = jsObject.setMinutes!(newValue) } } /// The amount of seconds in this minute from `0..59` range in local time zone. public var seconds: Int { get { - Int(ref.getSeconds!().number!) + Int(jsObject.getSeconds!().number!) } set { - _ = ref.setSeconds!(newValue) + _ = jsObject.setSeconds!(newValue) } } /// The amount of milliseconds in this second `0..999` range in local time zone. public var milliseconds: Int { get { - Int(ref.getMilliseconds!().number!) + Int(jsObject.getMilliseconds!().number!) } set { - _ = ref.setMilliseconds!(newValue) + _ = jsObject.setMilliseconds!(newValue) } } - /// Year of this date in the UTC time zone + /// Year of this date in the UTC time zone. public var utcFullYear: Int { get { - Int(ref.getUTCFullYear!().number!) + Int(jsObject.getUTCFullYear!().number!) } set { - _ = ref.setUTCFullYear!(newValue) + _ = jsObject.setUTCFullYear!(newValue) } } - /// Month of this date in `0–11` range in the UTC time zone + /// Month of this date in `0–11` range in the UTC time zone. public var utcMonth: Int { get { - Int(ref.getUTCMonth!().number!) + Int(jsObject.getUTCMonth!().number!) } set { - _ = ref.setUTCMonth!(newValue) + _ = jsObject.setUTCMonth!(newValue) } } - /// The day of the month in `1..31` range in the UTC time zone + /// The day of the month in `1..31` range in the UTC time zone. public var utcDate: Int { get { - Int(ref.getUTCDate!().number!) + Int(jsObject.getUTCDate!().number!) } set { - _ = ref.setUTCDate!(newValue) + _ = jsObject.setUTCDate!(newValue) } } - /// The day of the week in `0..6` range in the UTC time zone + /// The day of the week in `0..6` range in the UTC time zone. public var utcDay: Int { - Int(ref.getUTCDay!().number!) + Int(jsObject.getUTCDay!().number!) } - /// The amount of hours in this day from `0..23` range in the UTC time zone + /// The amount of hours in this day from `0..23` range in the UTC time zone. public var utcHours: Int { get { - Int(ref.getUTCHours!().number!) + Int(jsObject.getUTCHours!().number!) } set { - _ = ref.setUTCHours!(newValue) + _ = jsObject.setUTCHours!(newValue) } } - /// The amount of minutes in this hours from `0..59` range in the UTC time zone + /// The amount of minutes in this hours from `0..59` range in the UTC time zone. public var utcMinutes: Int { get { - Int(ref.getUTCMinutes!().number!) + Int(jsObject.getUTCMinutes!().number!) } set { - _ = ref.setUTCMinutes!(newValue) + _ = jsObject.setUTCMinutes!(newValue) } } - /// The amount of seconds in this minute from `0..59` range in the UTC time zone + /// The amount of seconds in this minute from `0..59` range in the UTC time zone. public var utcSeconds: Int { get { - Int(ref.getUTCSeconds!().number!) + Int(jsObject.getUTCSeconds!().number!) } set { - _ = ref.setUTCSeconds!(newValue) + _ = jsObject.setUTCSeconds!(newValue) } } - /// The amount of milliseconds in this second `0..999` range in the UTC time zone + /// The amount of milliseconds in this second `0..999` range in the UTC time zone. public var utcMilliseconds: Int { get { - Int(ref.getUTCMilliseconds!().number!) + Int(jsObject.getUTCMilliseconds!().number!) } set { - _ = ref.setUTCMilliseconds!(newValue) + _ = jsObject.setUTCMilliseconds!(newValue) } } - /// Offset in minutes between the local time zone and UTC + /// Offset in minutes between the local time zone and UTC. public var timezoneOffset: Int { - Int(ref.getTimezoneOffset!().number!) + Int(jsObject.getTimezoneOffset!().number!) } + /// Returns a string conforming to ISO 8601 that contains date and time, e.g. + /// `"2020-09-15T08:56:54.811Z"`. public func toISOString() -> String { - ref.toISOString!().string! + jsObject.toISOString!().string! } + /// Returns a string with date parts in a format defined by user's locale, e.g. `"9/15/2020"`. public func toLocaleDateString() -> String { - ref.toLocaleDateString!().string! + jsObject.toLocaleDateString!().string! } + /// Returns a string with time parts in a format defined by user's locale, e.g. `"10:04:14"`. public func toLocaleTimeString() -> String { - ref.toLocaleTimeString!().string! + 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`. + */ public func toUTCString() -> String { - ref.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! } - /// 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 { - ref.valueOf!().number! + jsObject.valueOf!().number! } } extension JSDate: Comparable { - public static func ==(lhs: JSDate, rhs: JSDate) -> Bool { + public static func == (lhs: JSDate, rhs: JSDate) -> Bool { return lhs.valueOf() == rhs.valueOf() } - public static func <(lhs: JSDate, rhs: JSDate) -> Bool { + public static func < (lhs: JSDate, rhs: JSDate) -> Bool { return lhs.valueOf() < rhs.valueOf() } } diff --git a/Sources/JavaScriptKit/BasicObjects/JSError.swift b/Sources/JavaScriptKit/BasicObjects/JSError.swift index fe779cc61..4dff7585b 100644 --- a/Sources/JavaScriptKit/BasicObjects/JSError.swift +++ b/Sources/JavaScriptKit/BasicObjects/JSError.swift @@ -3,12 +3,12 @@ class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_ exposes its properties in a type-safe way. */ public final class JSError: Error { - /// The underlying JavaScript `Error` object. - public let jsObject: JSObject - /// The constructor function used to create new `Error` objects. private 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]) From 5c0cead4e182640ba186fd8b3e31645c886105c1 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 15 Sep 2020 13:01:45 +0100 Subject: [PATCH 3/4] Refine `JSTimer` doc comment --- Sources/JavaScriptKit/BasicObjects/JSTimer.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/JavaScriptKit/BasicObjects/JSTimer.swift b/Sources/JavaScriptKit/BasicObjects/JSTimer.swift index 1ba7b8e42..78d50811e 100644 --- a/Sources/JavaScriptKit/BasicObjects/JSTimer.swift +++ b/Sources/JavaScriptKit/BasicObjects/JSTimer.swift @@ -1,8 +1,8 @@ -/** This timer type hides [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval) +/** This timer is an abstraction over [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval) / [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearInterval) and [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout) / [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout) -pairs of calls for you. It intentionally doesn't match the JavaScript API, as a special care is +JavaScript functions. It intentionally doesn't match the JavaScript API, as a special care is needed to hold a reference to the timer closure and to call `JSClosure.release()` on it when the timer is deallocated. As a user, you have to hold a reference to a `JSTimer` instance for it to stay valid. The `JSTimer` API is also intentionally trivial, the timer is started right away, and the From b9115a547171ba33e089f77bbf41c8cee7050158 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 15 Sep 2020 13:06:11 +0100 Subject: [PATCH 4/4] Refine `JSTimer` doc comment wording --- Sources/JavaScriptKit/BasicObjects/JSTimer.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/JavaScriptKit/BasicObjects/JSTimer.swift b/Sources/JavaScriptKit/BasicObjects/JSTimer.swift index 78d50811e..aced20b6b 100644 --- a/Sources/JavaScriptKit/BasicObjects/JSTimer.swift +++ b/Sources/JavaScriptKit/BasicObjects/JSTimer.swift @@ -6,9 +6,9 @@ JavaScript functions. It intentionally doesn't match the JavaScript API, as a sp needed to hold a reference to the timer closure and to call `JSClosure.release()` on it when the timer is deallocated. As a user, you have to hold a reference to a `JSTimer` instance for it to stay valid. The `JSTimer` API is also intentionally trivial, the timer is started right away, and the -only way to invalidate the timer is to bring the reference count of the `JSTimer` instance to zero, -either by storing the timer in an optional property and assigning `nil` to it or by deallocating the -object that owns it for invalidation. +only way to invalidate the timer is to bring the reference count of the `JSTimer` instance to zero. +For invalidation you should either store the timer in an optional property and assign `nil` to it, +or deallocate the object that owns the timer. */ public final class JSTimer { /// Indicates whether this timer instance calls its callback repeatedly at a given delay.