-
-
Notifications
You must be signed in to change notification settings - Fork 65
Added wrapper types and Codable support #8
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
Changes from all commits
b9fb002
ff13814
94c7dbb
4714de8
b5c8fa3
1a44d94
c88b849
128a862
2f0eae8
b75da55
3f47ae9
cde8d76
4fb0f75
66dd688
e14b6ac
e4f4025
ea55aa5
e002eb8
195b5e2
f1be2de
7eb4587
b1a06cb
235a4fe
31e87ef
8d5a12b
23d930b
4356521
4ed88b3
fdef8c2
a3093b9
cfc85ce
9fbb5e7
8f05e88
c976028
6a1528f
699a1f0
830a969
bb9e31c
d56d684
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,3 +5,6 @@ node_modules | |
| /Packages | ||
| /*.xcodeproj | ||
| xcuserdata/ | ||
|
|
||
| *.resolved | ||
| .swiftpm | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,17 +1,59 @@ | ||
| import SwiftFoundation | ||
| import JavaScriptKit | ||
|
|
||
| let alert = JSObjectRef.global.alert.function! | ||
| let document = JSObjectRef.global.document.object! | ||
|
|
||
| let divElement = document.createElement!("div").object! | ||
| divElement.innerText = "Hello, world" | ||
| divElement.innerText = "Swift Bluetooth Web App" | ||
| let body = document.body.object! | ||
| _ = body.appendChild!(divElement) | ||
|
|
||
| let buttonElement = document.createElement!("button").object! | ||
| buttonElement.innerText = "Click me!" | ||
| buttonElement.onclick = .function { _ in | ||
| alert("Swift is running on browser!") | ||
| } | ||
| let date = Date() | ||
| JSConsole.info("Date:", date) | ||
| JSConsole.log(date.description) | ||
|
|
||
| _ = body.appendChild!(buttonElement) | ||
| if let bluetooth = JSBluetooth.shared { | ||
| bluetooth.isAvailable.then { | ||
| JSConsole.assert($0, "Bluetooth not available") | ||
| }.catch { (error: JSError) in | ||
| JSConsole.debug(#file, #function, #line) | ||
| JSConsole.error(error) | ||
| } | ||
| let buttonElement = document.createElement!("button").object! | ||
| buttonElement.innerText = "Scan for Bluetooth devices" | ||
| buttonElement.onclick = .function { _ in | ||
| JSConsole.info("Swift is running on browser!") | ||
| JSConsole.debug("\(#file) \(#function) \(#line)") | ||
| alert("Swift is running on browser!") | ||
| JSConsole.log("Requesting any Bluetooth Device...") | ||
| bluetooth.requestDevice().then { (device: JSBluetoothDevice) -> (JSPromise<JSBluetoothRemoteGATTServer>) in | ||
| JSConsole.info(device) | ||
| JSConsole.debug("\(#file) \(#function) \(#line) \(device)") | ||
| alert("Got device \(device)") | ||
| JSConsole.log("Connecting to GATT Server...") | ||
| return device.gatt.connect() | ||
| }.then { (server: JSBluetoothRemoteGATTServer) -> (JSPromise<JSBluetoothRemoteGATTService>) in | ||
| JSConsole.info(server) | ||
| JSConsole.debug("\(#file) \(#function) \(#line) \(server)") | ||
| alert("Connected") | ||
| JSConsole.log("Getting Device Information Service...") | ||
| return server.getPrimaryService("device_information") | ||
| }.then { (service: JSBluetoothRemoteGATTService) -> () in | ||
| JSConsole.info(service) | ||
| JSConsole.debug("\(#file) \(#function) \(#line) isPrimary \(service.isPrimary) uuid \(service.uuid)") | ||
| }.catch { (error: JSError) in | ||
| JSConsole.debug(#file, #function, #line) | ||
| JSConsole.error(error) | ||
| alert("Error: \(error.message)") | ||
| } | ||
| JSConsole.debug("\(#file) \(#function) \(#line)") | ||
| return .undefined | ||
| } | ||
| _ = body.appendChild!(buttonElement) | ||
| } else { | ||
| JSConsole.error("Cannot access Bluetooth API") | ||
| let divElement = document.createElement!("div").object! | ||
| divElement.innerText = "Bluetooth Web API not enabled" | ||
| _ = body.appendChild!(divElement) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| // swift-tools-version:5.2 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This library doesn't support Swift 5.2 compatible toolchain. 🤔 |
||
|
|
||
| import PackageDescription | ||
|
|
||
| let package = Package( | ||
| name: "JavaScriptKit", | ||
| products: [ | ||
| .library(name: "JavaScriptKit", targets: ["JavaScriptKit"]) | ||
| ], | ||
| dependencies: [ | ||
| .package(url: "https://github.com/PureSwift/SwiftFoundation.git", .branch("develop")) | ||
| ], | ||
| targets: [ | ||
| .target( | ||
| name: "JavaScriptKit", | ||
| dependencies: [ | ||
| "_CJavaScriptKit", | ||
| "SwiftFoundation" | ||
| ] | ||
| ), | ||
| .target(name: "_CJavaScriptKit"), | ||
| .testTarget( | ||
| name: "JavaScriptKitTests", | ||
| dependencies: ["JavaScriptKit"] | ||
| ) | ||
| ] | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| // | ||
| // Assert.swift | ||
| // | ||
| // | ||
| // Created by Alsey Coleman Miller on 6/4/20. | ||
| // | ||
|
|
||
| /// Unconditionally prints a given message and stops execution. | ||
| internal func fatalError(_ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Never { | ||
| let message = message() | ||
| JSConsole.error("Fatal error: \(message)") | ||
| Swift.fatalError(message, file: file, line: line) | ||
| } | ||
|
|
||
| /// Performs a traditional C-style assert with an optional message. | ||
| internal func assert(_ condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { | ||
| let condition = condition() | ||
| let message = message() | ||
| JSConsole.assert(condition, "Assertion failure: \(message)") | ||
| Swift.assert(condition, message, file: file, line: line) | ||
| } | ||
|
|
||
| /// Performs a traditional C-style assert with an optional message. | ||
| internal func assert(_ condition: @autoclosure () -> JSBoolean, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) { | ||
| assert(condition().rawValue, message(), file: file, line: line) | ||
| } | ||
|
|
||
| internal extension Optional { | ||
|
|
||
| func assert(_ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Wrapped { | ||
| switch self { | ||
| case .none: | ||
| fatalError(message(), file: file, line: line) | ||
| case let .some(value): | ||
| return value | ||
| } | ||
|
Comment on lines
+30
to
+36
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The method name is |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| // | ||
| // CodingKey.swift | ||
| // | ||
| // | ||
| // Created by Alsey Coleman Miller on 5/30/20. | ||
| // | ||
|
|
||
| internal extension Sequence where Element == CodingKey { | ||
|
|
||
| /// KVC path string for current coding path. | ||
| var path: String { | ||
| return reduce("", { $0 + "\($0.isEmpty ? "" : ".")" + $1.stringValue }) | ||
| } | ||
| } | ||
|
|
||
| internal extension CodingKey { | ||
|
|
||
| static var sanitizedName: String { | ||
|
|
||
| let rawName = String(reflecting: self) | ||
| var elements = rawName.split(separator: ".") | ||
| guard elements.count > 2 | ||
| else { return rawName } | ||
| elements.removeFirst() | ||
| elements.removeAll { $0.hasPrefix("(unknown context") } | ||
| return elements.reduce("", { $0 + ($0.isEmpty ? "" : ".") + $1 }) | ||
| } | ||
| } | ||
|
Comment on lines
+8
to
+28
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These helper methods are only used in Encoder implementation, so I think it's better to move them to the JSEncoder.swift and make them fileprivate. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| // | ||
| // Date.swift | ||
| // JavaScriptKit | ||
| // | ||
| // Created by Alsey Coleman Miller on 6/4/20. | ||
| // | ||
|
|
||
| import SwiftFoundation | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please allow users to choose whether to use SwiftFoundation or Foundation. You can use |
||
|
|
||
| #if arch(wasm32) | ||
|
|
||
| // MARK: - Time | ||
|
|
||
| internal extension JSDate { | ||
|
|
||
| /// The interval between 00:00:00 UTC on 1 January 2001 and the current date and time. | ||
| static var timeIntervalSinceReferenceDate: SwiftFoundation.TimeInterval { | ||
| return JSDate.now - Date.timeIntervalBetween1970AndReferenceDate | ||
| } | ||
| } | ||
|
|
||
| public extension SwiftFoundation.Date { | ||
|
|
||
| /// Returns a `Date` initialized to the current date and time. | ||
| init() { | ||
| self.init(timeIntervalSinceReferenceDate: JSDate.timeIntervalSinceReferenceDate) | ||
| } | ||
|
|
||
| /// Returns a `Date` initialized relative to the current date and time by a given number of seconds. | ||
| init(timeIntervalSinceNow: SwiftFoundation.TimeInterval) { | ||
| self.init(timeIntervalSinceReferenceDate: timeIntervalSinceNow + JSDate.timeIntervalSinceReferenceDate) | ||
| } | ||
|
|
||
| /** | ||
| The time interval between the date and the current date and time. | ||
|
|
||
| If the date is earlier than the current date and time, the this property’s value is negative. | ||
|
|
||
| - SeeAlso: `timeIntervalSince(_:)` | ||
| - SeeAlso: `timeIntervalSince1970` | ||
| - SeeAlso: `timeIntervalSinceReferenceDate` | ||
| */ | ||
| var timeIntervalSinceNow: SwiftFoundation.TimeInterval { | ||
| return self.timeIntervalSinceReferenceDate - JSDate.timeIntervalSinceReferenceDate | ||
| } | ||
|
|
||
| /** | ||
| The interval between the date object and 00:00:00 UTC on 1 January 1970. | ||
|
|
||
| This property’s value is negative if the date object is earlier than 00:00:00 UTC on 1 January 1970. | ||
|
|
||
| - SeeAlso: `timeIntervalSince(_:)` | ||
| - SeeAlso: `timeIntervalSinceNow` | ||
| - SeeAlso: `timeIntervalSinceReferenceDate` | ||
| */ | ||
| var timeIntervalSince1970: SwiftFoundation.TimeInterval { | ||
| return self.timeIntervalSinceReferenceDate + Date.timeIntervalBetween1970AndReferenceDate | ||
| } | ||
| } | ||
|
|
||
| public extension SwiftFoundation.Date { | ||
|
|
||
| /// The interval between 00:00:00 UTC on 1 January 2001 and the current date and time. | ||
| static var _timeIntervalSinceReferenceDate: SwiftFoundation.TimeInterval { | ||
| // FIXME: Compiler error | ||
| return JSDate.timeIntervalSinceReferenceDate | ||
| } | ||
| } | ||
|
|
||
| // MARK: - CustomStringConvertible | ||
|
|
||
| extension SwiftFoundation.Date: CustomStringConvertible { | ||
|
|
||
| public var description: String { | ||
| return JSDate(self).toUTCString() | ||
| } | ||
| } | ||
|
|
||
| // MARK: - CustomDebugStringConvertible | ||
|
|
||
| extension SwiftFoundation.Date: CustomDebugStringConvertible { | ||
|
|
||
| public var debugDescription: String { | ||
| return description | ||
| } | ||
| } | ||
|
|
||
| #endif | ||
|
|
||
| // MARK: - JS Value | ||
|
|
||
| public extension JSDate { | ||
|
|
||
| convenience init(_ date: SwiftFoundation.Date) { | ||
| self.init(timeInterval: date.timeIntervalSince1970) | ||
| } | ||
| } | ||
|
|
||
| public extension SwiftFoundation.Date { | ||
|
|
||
| init(_ date: JSDate) { | ||
| self.init(timeIntervalSince1970: date.rawValue) | ||
| } | ||
| } | ||
|
|
||
| // MARK: - JSValueConvertible | ||
|
|
||
| extension SwiftFoundation.Date: JSValueConvertible { | ||
|
|
||
| public func jsValue() -> JSValue { | ||
| let date = JSDate(self) | ||
| assert(date.rawValue == timeIntervalSince1970) | ||
| return date.jsValue() | ||
| } | ||
| } | ||
|
|
||
| // MARK: - JSValueConstructible | ||
|
|
||
| extension SwiftFoundation.Date: JSValueConstructible { | ||
|
|
||
| public static func construct(from value: JSValue) -> Date? { | ||
| return value.object | ||
| .flatMap { JSDate($0) } | ||
| .flatMap { Date($0) } | ||
| ?? value.number.flatMap { Date(timeIntervalSince1970: $0) } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to keep this library independent from Foundation at this time because this library is the basis of any Swift web app.