Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
b9fb002
Added strongly typed classes
colemancda Jun 3, 2020
ff13814
Added `JSPromise`
colemancda Jun 3, 2020
94c7dbb
Working on `JSPromise`
colemancda Jun 3, 2020
4714de8
Working on `JSPromise`
colemancda Jun 3, 2020
b5c8fa3
Added `JSError`
colemancda Jun 4, 2020
1a44d94
Updated `JSType`
colemancda Jun 4, 2020
c88b849
Working on `JSBluetooth`
colemancda Jun 4, 2020
128a862
Working on `JSBluetooth`
colemancda Jun 4, 2020
2f0eae8
Updated example
colemancda Jun 4, 2020
b75da55
Updated `JSBluetoothDevice`
colemancda Jun 4, 2020
3f47ae9
Added `JSConsole`
colemancda Jun 4, 2020
cde8d76
Added `JSBluetoothRemoteGATTServer`
colemancda Jun 4, 2020
4fb0f75
Updated `JSPromise`
colemancda Jun 4, 2020
66dd688
Updated logging
colemancda Jun 4, 2020
e14b6ac
Updated `JSPromise`
colemancda Jun 4, 2020
e4f4025
Updated `JSConsole`
colemancda Jun 4, 2020
ea55aa5
Fixed `JSType.toString()`
colemancda Jun 4, 2020
e002eb8
Updated `JSPromise`
colemancda Jun 4, 2020
195b5e2
Updated logging
colemancda Jun 4, 2020
f1be2de
Added `JSBluetooth.isAvailable`
colemancda Jun 4, 2020
7eb4587
Updated `JSPromise`
colemancda Jun 4, 2020
b1a06cb
Added `JSBluetoothRemoteGATTService`
colemancda Jun 4, 2020
235a4fe
Updated `JSPromise`
colemancda Jun 4, 2020
31e87ef
Renamed `JSDecoder`
colemancda Jun 4, 2020
8d5a12b
Fixed `JSConsole.assert()`
colemancda Jun 4, 2020
23d930b
Added `JSBluetooth.devices`
colemancda Jun 5, 2020
4356521
Added `JSEncoder`
colemancda Jun 5, 2020
4ed88b3
Added `JSObject.keys`
colemancda Jun 5, 2020
fdef8c2
Updated dependencies
colemancda Jun 5, 2020
a3093b9
Added `JSDate`
colemancda Jun 5, 2020
cfc85ce
Updated assertions
colemancda Jun 5, 2020
9fbb5e7
Updated `JSDate`
colemancda Jun 5, 2020
8f05e88
Fixed `JSEncoder`
colemancda Jun 5, 2020
c976028
Fixed `CodingKey.sanitizedName`
colemancda Jun 5, 2020
6a1528f
Fixed `JSArray`
colemancda Jun 5, 2020
699a1f0
Fixed `JSEncoder`
colemancda Jun 5, 2020
830a969
Updated dependencies
colemancda Jun 5, 2020
bb9e31c
Updated from `kateinoigakukun/JavaScriptKit`
colemancda Jun 5, 2020
d56d684
Fixed `JSDate`
colemancda Jun 5, 2020
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
8 changes: 7 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@ let package = Package(
products: [
.library(name: "JavaScriptKit", targets: ["JavaScriptKit"])
],
dependencies: [
.package(url: "https://github.com/PureSwift/SwiftFoundation.git", .branch("develop"))
Copy link
Member

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.

],
targets: [
.target(
name: "JavaScriptKit",
dependencies: ["_CJavaScriptKit"],
dependencies: [
"_CJavaScriptKit",
"SwiftFoundation"
],
linkerSettings: [
.unsafeFlags(
[
Expand Down
27 changes: 27 additions & 0 deletions Package@swift-5.2.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// swift-tools-version:5.2
Copy link
Member

Choose a reason for hiding this comment

The 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"]
)
]
)
38 changes: 38 additions & 0 deletions Sources/JavaScriptKit/Assert.swift
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method name is assert but it uses fatalError. Should we use fatalError instead?

}
}
28 changes: 28 additions & 0 deletions Sources/JavaScriptKit/Extensions/CodingKey.swift
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
Copy link
Member

Choose a reason for hiding this comment

The 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.

127 changes: 127 additions & 0 deletions Sources/JavaScriptKit/Foundation/Date.swift
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
Copy link
Member

Choose a reason for hiding this comment

The 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 canImport feature like this. https://github.com/kateinoigakukun/CanImportMagic/blob/master/Packages/LibraryX/Sources/LibraryX/LibraryX.swift


#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) }
}
}
Loading