Skip to content

Commit c81cf3d

Browse files
nguyenyouclaude
andcommitted
Fix: Add binary compatibility forwarders for recover* methods
In 18.0.0-M3, recover/recoverToTry/recoverToEither/recoverIgnoreErrors were moved from EventStream/Signal to RecoverOps[Self, A] where Self has no `<: Observable[_]` bound. This changed the Scala.js IR method descriptors, breaking linking for libraries compiled against 17.x. Add forwarding overrides on EventStream, Signal, and StrictSignal that delegate to mapRecover, restoring the old method descriptors. Fixes #149 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 895fa2d commit c81cf3d

File tree

3 files changed

+37
-3
lines changed

3 files changed

+37
-3
lines changed

src/main/scala/com/raquo/airstream/core/EventStream.scala

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import java.util.concurrent.Flow
2121
import scala.concurrent.{ExecutionContext, Future}
2222
import scala.scalajs.js
2323
import scala.scalajs.js.JSConverters._
24-
import scala.util.{Success, Try}
24+
import scala.util.{Failure, Success, Try}
2525

2626
trait EventStream[+A]
2727
extends Observable[A]
@@ -39,6 +39,20 @@ with DynamicImportStreamOps[A] // dynamicImport (Scala 3 only)
3939
new MapStream(this, project, recover = None)
4040
}
4141

42+
// -- BinCompat forwarders for RecoverOps methods.
43+
// In Airstream 17.x, these were defined on EventStream directly. In 18.0.0-M3
44+
// they moved to RecoverOps[Self, A] where Self has no `<: Observable[_]` bound,
45+
// changing the Scala.js IR method descriptor. These forwarders restore the old
46+
// descriptors so that libraries compiled against 17.x can link against 18.x.
47+
48+
override def recover[B >: A](pf: PartialFunction[Throwable, Option[B]]): EventStream[B] = mapRecover(identity, pf)
49+
50+
override def recoverIgnoreErrors: EventStream[A] = recover[A](_ => None)
51+
52+
override def recoverToTry: EventStream[Try[A]] = mapRecover(Success(_), err => Some(Failure(err)))
53+
54+
override def recoverToEither: EventStream[Either[Throwable, A]] = mapRecover(Right(_), err => Some(Left(err)))
55+
4256
/** If `recover` is defined and needs to be called, it can do the following:
4357
* - Return Some(value) to make this stream emit value
4458
* - Return None to make this stream ignore (swallow) this error

src/main/scala/com/raquo/airstream/core/Signal.scala

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import com.raquo.ew.JsArray
1818
import scala.concurrent.{ExecutionContext, Future}
1919
import scala.scalajs.js
2020
import scala.scalajs.js.JSConverters._
21-
import scala.util.Try
21+
import scala.util.{Failure, Success, Try}
2222

2323
/** Signal is an Observable with a current value. */
2424
trait Signal[+A]
@@ -52,6 +52,16 @@ with DynamicImportSignalOps[A] // dynamicImport (Scala 3 only)
5252
new MapSignal(parent = this, project, recover = None)
5353
}
5454

55+
// -- BinCompat forwarders for RecoverOps methods (see EventStream for explanation)
56+
57+
override def recover[B >: A](pf: PartialFunction[Throwable, Option[B]]): Signal[B] = mapRecover(identity, pf)
58+
59+
override def recoverIgnoreErrors: Signal[A] = recover[A](_ => None)
60+
61+
override def recoverToTry: Signal[Try[A]] = mapRecover(Success(_), err => Some(Failure(err)))
62+
63+
override def recoverToEither: Signal[Either[Throwable, A]] = mapRecover(Right(_), err => Some(Left(err)))
64+
5565
/** If `recover` is defined and needs to be called, it can do the following:
5666
* - Return Some(value) to make this stream emit value
5767
* - Return None to make this stream ignore (swallow) this error

src/main/scala/com/raquo/airstream/state/StrictSignal.scala

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import com.raquo.airstream.core.{CoreOps, RecoverOps, ScanLeftSignalOps, Signal}
44
import com.raquo.airstream.debug.{Debugger, DebugSignalOps}
55
import com.raquo.airstream.distinct.DistinctOps
66

7-
import scala.util.Try
7+
import scala.util.{Failure, Success, Try}
88

99
/** A Signal that lets you directly query its current value.
1010
*
@@ -32,6 +32,16 @@ with DebugSignalOps[StrictSignal, A] {
3232
)
3333
}
3434

35+
// -- BinCompat forwarders: must override Signal's forwarders with StrictSignal return type
36+
37+
override def recover[B >: A](pf: PartialFunction[Throwable, Option[B]]): StrictSignal[B] = mapRecover(identity, pf)
38+
39+
override def recoverIgnoreErrors: StrictSignal[A] = recover[A](_ => None)
40+
41+
override def recoverToTry: StrictSignal[Try[A]] = mapRecover(Success(_), err => Some(Failure(err)))
42+
43+
override def recoverToEither: StrictSignal[Either[Throwable, A]] = mapRecover(Right(_), err => Some(Left(err)))
44+
3545
/** If `recover` is defined and needs to be called, it can do the following:
3646
* - Return Some(value) to make this stream emit value
3747
* - Return None to make this signal ignore (swallow) this error

0 commit comments

Comments
 (0)