Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: armanbilge/fs2-dom
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.2.0-M4
Choose a base ref
...
head repository: armanbilge/fs2-dom
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.2.0-RC1
Choose a head ref
  • 5 commits
  • 5 files changed
  • 2 contributors

Commits on Feb 9, 2023

  1. Copy the full SHA
    f613c2a View commit details
  2. Merge pull request #58 from armanbilge/update/fs2-core-3.6.1

    Update fs2-core to 3.6.1
    armanbilge authored Feb 9, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    9bc4a58 View commit details

Commits on Feb 12, 2023

  1. Copy the full SHA
    9ad30bb View commit details
  2. Fix doc

    armanbilge committed Feb 12, 2023
    Copy the full SHA
    dbb648b View commit details

Commits on Feb 14, 2023

  1. Merge pull request #60 from armanbilge/pr/i28

    Remove circe dep, rework `Serializer`
    armanbilge authored Feb 14, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    13b4385 View commit details
6 changes: 2 additions & 4 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -26,8 +26,7 @@ ThisBuild / githubWorkflowBuildPreamble +=
)

val ceVersion = "3.4.6"
val fs2Version = "3.6.0"
val circeVersion = "0.14.3"
val fs2Version = "3.6.1"
val sjsDomVersion = "2.3.0"
val munitCEVersion = "2.0.0-M3"
val scalaCheckEffectVersion = "2.0.0-M2"
@@ -54,8 +53,7 @@ lazy val dom = project
libraryDependencies ++= Seq(
"org.typelevel" %%% "cats-effect" % ceVersion,
"co.fs2" %%% "fs2-core" % fs2Version,
"org.scala-js" %%% "scalajs-dom" % sjsDomVersion,
"io.circe" %%% "circe-scalajs" % circeVersion
"org.scala-js" %%% "scalajs-dom" % sjsDomVersion
)
)

14 changes: 7 additions & 7 deletions dom/src/main/scala/fs2/dom/History.scala
Original file line number Diff line number Diff line change
@@ -51,7 +51,7 @@ abstract class History[F[_], S] private {
object History {
private[dom] def apply[F[_], S](window: dom.Window, history: dom.History)(implicit
F: Async[F],
serializer: Serializer[F, S]
serializer: Serializer[S]
): History[F, S] =
new History[F, S] {

@@ -72,7 +72,7 @@ object History {
.repeatEval {
for {
event <- queue.take
state <- serializer.deserialize(event.state)
state <- serializer.deserialize(event.state).liftTo[F]
} yield Some(state)
}
} yield (got, updates)
@@ -82,7 +82,7 @@ object History {
}

def get = OptionT(F.delay(Option(history.state)))
.semiflatMap(serializer.deserialize(_))
.semiflatMap(serializer.deserialize(_).liftTo[F])
.value

def continuous = Stream.repeatEval(get)
@@ -105,14 +105,14 @@ object History {
def go(delta: Int) = asyncPopState(history.go(delta))

def pushState(state: S) =
serializer.serialize(state).flatMap(s => F.delay(history.pushState(s, "")))
F.delay(history.pushState(serializer.serialize(state), ""))
def pushState(state: S, url: String) =
serializer.serialize(state).flatMap(s => F.delay(history.pushState(s, "", url)))
F.delay(history.pushState(serializer.serialize(state), "", url))

def replaceState(state: S) =
serializer.serialize(state).flatMap(s => F.delay(history.replaceState(s, "")))
F.delay(history.replaceState(serializer.serialize(state), ""))
def replaceState(state: S, url: String) =
serializer.serialize(state).flatMap(s => F.delay(history.replaceState(s, "", url)))
F.delay(history.replaceState(serializer.serialize(state), "", url))

def asyncPopState(thunk: => Unit): F[Unit] = F.async_[Unit] { cb =>
window.addEventListener[dom.PopStateEvent](
5 changes: 2 additions & 3 deletions dom/src/main/scala/fs2/dom/PopStateEvent.scala
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ import org.scalajs.dom

abstract class PopStateEvent[F[_]] private[dom] extends Event[F] {

def state[F[_], S](implicit serializer: Serializer[F, S]): F[S]
def state[S: Serializer]: Either[Throwable, S]

}

@@ -38,6 +38,5 @@ private trait PopStateEventImpl[F[_]] extends PopStateEvent[F] with EventImpl[F]
def event: dom.PopStateEvent
implicit def F: Sync[F]

def state[F[_], S](implicit serializer: Serializer[F, S]) =
serializer.deserialize(event.state)
def state[S](implicit serializer: Serializer[S]) = serializer.deserialize(event.state)
}
43 changes: 17 additions & 26 deletions dom/src/main/scala/fs2/dom/Serializer.scala
Original file line number Diff line number Diff line change
@@ -16,46 +16,37 @@

package fs2.dom

import cats.Invariant
import cats.effect.kernel.Sync
import cats.syntax.all._
import io.circe.Decoder
import io.circe.Encoder
import io.circe.scalajs._

import scala.scalajs.js

/** @see [[https://developer.mozilla.org/en-US/docs/Glossary/Serializable_object]]
*
* @todo So far the only instance of [[Serializer]] is for `Unit`.
* Track progress in [[https://github.com/armanbilge/fs2-dom/issues/59 fs2-dom#59]]).
*/
trait Serializer[F[_], A] { outer =>
sealed abstract class Serializer[A] private {

def serialize(a: A): F[js.Any]
def serialize(a: A): js.Any

def deserialize(serialized: js.Any): F[A]

final def imap[B](f: A => B)(g: B => A)(implicit F: Invariant[F]): Serializer[F, B] =
new Serializer[F, B] {
def serialize(b: B): F[js.Any] = outer.serialize(g(b))
def deserialize(serialized: js.Any): F[B] = outer.deserialize(serialized).imap(f)(g)
}
def deserialize(serialized: js.Any): Either[Throwable, A]

}

object Serializer {

implicit def invariant[F[_]: Invariant]: Invariant[Serializer[F, *]] =
new Invariant[Serializer[F, *]] {
def imap[A, B](fa: Serializer[F, A])(f: A => B)(g: B => A): Serializer[F, B] =
fa.imap(f)(g)
}
implicit def unit: Serializer[Unit] = new Serializer[Unit] {
def serialize(u: Unit): js.Any = u
def deserialize(serialized: js.Any): Either[Throwable, Unit] = Either.unit
}

implicit def fromCirceCodec[F[_], A](implicit
F: Sync[F],
decoder: Decoder[A],
encoder: Encoder[A]
): Serializer[F, A] = new Serializer[F, A] {
def serialize(a: A): F[js.Any] = F.delay(a.asJsAny)
def deserialize(serialized: js.Any): F[A] = decodeJs[A](serialized).liftTo[F]
// used in test
private[dom] implicit def int: Serializer[Int] = new Serializer[Int] {
def serialize(i: Int): js.Any = i
def deserialize(serialized: js.Any): Either[Throwable, Int] = (serialized: Any) match {
case i: Int => Right(i)
case x => Left(new NumberFormatException(x.toString))
}
}

}
4 changes: 2 additions & 2 deletions dom/src/main/scala/fs2/dom/Window.scala
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ import org.scalajs.dom

abstract class Window[F[_]] private extends WindowCrossCompat[F] {

def history[S](implicit serializer: Serializer[F, S]): History[F, S]
def history[S: Serializer]: History[F, S]

def localStorage: Storage[F]

@@ -46,7 +46,7 @@ object Window {

private[dom] def window = _window

def history[S](implicit serializer: Serializer[F, S]) = History(window, window.history)
def history[S: Serializer] = History(window, window.history)

def localStorage = Storage(window.localStorage)