Skip to content

Commit

Permalink
Merge branch 'master' into publish
Browse files Browse the repository at this point in the history
  • Loading branch information
sherpal committed Jul 3, 2024
2 parents 8461411 + 285cfc6 commit cc82df0
Show file tree
Hide file tree
Showing 48 changed files with 449 additions and 449 deletions.
11 changes: 7 additions & 4 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ inThisBuild(
url("https://github.com/sherpal")
)
),
crossScalaVersions := Seq("3.2.0", "2.13.5", "2.12.13"),
scalaVersion := crossScalaVersions.value.head
crossScalaVersions := Seq("3.3.1", "2.13.14", "2.12.19"),
scalaVersion := crossScalaVersions.value.head,
autoAPIMappings := true
)
)

Expand All @@ -45,13 +46,15 @@ lazy val `url-dsl` = crossProject(JSPlatform, JVMPlatform)
),
(Compile / doc / scalacOptions) ++= Seq(
"-no-link-warnings" // Suppress scaladoc "Could not find any member to link for" warnings
)
),
Compile / doc / scalacOptions ~= ((options: Seq[String]) => options.filterNot(_ == "-Xfatal-warnings"))
)
.jsSettings(
scalacOptions ++= sys.env.get("CI").map { _ =>
val localSourcesPath = (LocalRootProject / baseDirectory).value.toURI
val remoteSourcesPath = s"https://raw.githubusercontent.com/sherpal/url-dsl/${git.gitHeadCommit.value.get}/"
val sourcesOptionName = if (scalaVersion.value.startsWith("2.")) "-P:scalajs:mapSourceURI" else "-scalajs-mapSourceURI"
val sourcesOptionName =
if (scalaVersion.value.startsWith("2.")) "-P:scalajs:mapSourceURI" else "-scalajs-mapSourceURI"

s"${sourcesOptionName}:$localSourcesPath->$remoteSourcesPath"
}
Expand Down
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version = 1.8.0
sbt.version = 1.10.0
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2")
addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.0")

val scalaJSVersion =
Option(System.getenv("SCALAJS_VERSION")).getOrElse("1.9.0")
Option(System.getenv("SCALAJS_VERSION")).getOrElse("1.16.0")

addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.0.0")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % scalaJSVersion)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ final class JSUrlStringParser(val rawUrl: String) extends UrlStringParser {

def maybeFragment: Option[String] =
Option(urlParser.hash)
/*
/*
* Empty fragment are considered to have no fragment at all
*/
.filter(_.nonEmpty)
Expand Down
9 changes: 3 additions & 6 deletions url-dsl/.js/src/main/scala/urldsl/url/URL.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,19 @@ import scala.scalajs.js.annotation.JSGlobal
@JSGlobal
private[url] final class URL(url: String) extends js.Object {

/**
* Is a DOMString containing an initial '/' followed by the path of the URL.
/** Is a DOMString containing an initial '/' followed by the path of the URL.
*
* MDN
*/
var pathname: String = js.native

/**
* Is a DOMString containing a '?' followed by the parameters of the URL.
/** Is a DOMString containing a '?' followed by the parameters of the URL.
*
* MDN
*/
var search: String = js.native

/**
* Is a DOMString containing a '#' followed by the fragment identifier of the URL.
/** Is a DOMString containing a '#' followed by the fragment identifier of the URL.
*
* MDN
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package urldsl.url

import java.net.{URL, URLDecoder}
import java.net.{URI, URLDecoder}

final class JavaNetUrlStringParser(val rawUrl: String) extends UrlStringParser {

private val urlParser = new URL(rawUrl)
private val urlParser = URI.create(rawUrl).toURL()

def queryParametersString: String = Option(urlParser.getQuery).getOrElse("")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ import urldsl.errors.ErrorFromThrowable

trait FromStringWithNumeric {

implicit def numericFromString[T, A](
implicit num: Numeric[T],
implicit def numericFromString[T, A](implicit
num: Numeric[T],
fromThrowable: ErrorFromThrowable[A]
): FromString[T, A] = FromString.factory(
s =>
num.parseString(s) match {
case Some(t) => Right(t)
case None => Left(fromThrowable.fromThrowable(new Exception(s"$s is not numeric")))
}
): FromString[T, A] = FromString.factory(s =>
num.parseString(s) match {
case Some(t) => Right(t)
case None => Left(fromThrowable.fromThrowable(new Exception(s"$s is not numeric")))
}
)

}
3 changes: 1 addition & 2 deletions url-dsl/src/main/scala/urldsl/errors/DummyError.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package urldsl.errors
import urldsl.vocabulary.Segment

/**
* Error type with only one instance, for when you only care about knowing whether the error exists.
/** Error type with only one instance, for when you only care about knowing whether the error exists.
*/
sealed trait DummyError

Expand Down
6 changes: 3 additions & 3 deletions url-dsl/src/main/scala/urldsl/errors/ErrorFromThrowable.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package urldsl.errors

/**
* You can implement this trait for your own error type A, and give a implicit instance in order to use the
/** You can implement this trait for your own error type A, and give a implicit instance in order to use the
* functionality requiring it, e.g., in [[urldsl.vocabulary.FromString]].
*
* @tparam A tye type of your error.
* @tparam A
* tye type of your error.
*/
trait ErrorFromThrowable[A] {

Expand Down
10 changes: 5 additions & 5 deletions url-dsl/src/main/scala/urldsl/errors/ParamMatchingError.scala
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package urldsl.errors

/**
* You can implement this trait for your own error type `A`, and provide an implicit instance in the companion object of
* `A` in order to use all pre-defined [[urldsl.language.QueryParameters]].
/** You can implement this trait for your own error type `A`, and provide an implicit instance in the companion object
* of `A` in order to use all pre-defined [[urldsl.language.QueryParameters]].
*
* @example
* See implementations of [[DummyError]] and [[SimpleParamMatchingError]]
* See implementations of [[DummyError]] and [[SimpleParamMatchingError]]
*
* @tparam A the type of your error.
* @tparam A
* the type of your error.
*/
trait ParamMatchingError[A] {
def missingParameterError(paramName: String): A
Expand Down
8 changes: 4 additions & 4 deletions url-dsl/src/main/scala/urldsl/errors/PathMatchingError.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package urldsl.errors

import urldsl.vocabulary.Segment

/**
* You can implement this trait for your own error type `A`, a giving an implicit instance in the companion object of
/** You can implement this trait for your own error type `A`, a giving an implicit instance in the companion object of
* `A` so that it is available for all pre-defined [[urldsl.language.PathSegment]].
*
* @example
* See implementations of [[DummyError]] or [[SimpleParamMatchingError]]
* See implementations of [[DummyError]] or [[SimpleParamMatchingError]]
*
* @tparam A type of the error.
* @tparam A
* type of the error.
*/
trait PathMatchingError[+A] {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ package urldsl.errors

sealed trait SimpleParamMatchingError

/**
* An implementation of [[ParamMatchingError]] that simply wraps the trigger of the error inside its components.
/** An implementation of [[ParamMatchingError]] that simply wraps the trigger of the error inside its components.
*/
object SimpleParamMatchingError {

Expand Down
6 changes: 2 additions & 4 deletions url-dsl/src/main/scala/urldsl/language/AllImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ package urldsl.language

import urldsl.errors.{FragmentMatchingError, ParamMatchingError, PathMatchingError}

final class AllImpl[P, Q, F] private (
implicit
final class AllImpl[P, Q, F] private (implicit
protected val pathError: PathMatchingError[P],
protected val queryError: ParamMatchingError[Q],
protected val fragmentError: FragmentMatchingError[F]
Expand All @@ -12,8 +11,7 @@ final class AllImpl[P, Q, F] private (
with FragmentImpl[F]

object AllImpl {
def apply[P, Q, F](
implicit
def apply[P, Q, F](implicit
pathError: PathMatchingError[P],
queryError: ParamMatchingError[Q],
fragmentError: FragmentMatchingError[F]
Expand Down
91 changes: 47 additions & 44 deletions url-dsl/src/main/scala/urldsl/language/Fragment.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,30 @@ import urldsl.vocabulary.{Codec, FromString, MaybeFragment, Printer}
import scala.language.implicitConversions
import scala.reflect.ClassTag

/**
* Represents the fragment (or ref) of an URL, containing an information of type T, or an error of type E.
/** Represents the fragment (or ref) of an URL, containing an information of type T, or an error of type E.
*
* @tparam T type represented by this PathSegment
* @tparam E type of the error that this PathSegment produces on "illegal" url paths.
* @tparam T
* type represented by this PathSegment
* @tparam E
* type of the error that this PathSegment produces on "illegal" url paths.
*/
trait Fragment[T, +E] extends UrlPart[T, E] {

import Fragment.factory

/**
* Extract the information contained in this fragment, as an instance of T.
/** Extract the information contained in this fragment, as an instance of T.
*
* @param maybeFragment raw fragment information from the URL
* @return Right a T when the extraction was successful, and Left an error otherwise.
* @param maybeFragment
* raw fragment information from the URL
* @return
* Right a T when the extraction was successful, and Left an error otherwise.
*/
def matchFragment(maybeFragment: MaybeFragment): Either[E, T]

def matchRawUrl(url: String, urlStringParserGenerator: UrlStringParserGenerator): Either[E, T] =
matchFragment(urlStringParserGenerator.parser(url).maybeFragmentObj)

/**
* Creates a fragment information from an instance of T.
/** Creates a fragment information from an instance of T.
*/
def createFragment(t: T): MaybeFragment

Expand All @@ -51,31 +52,33 @@ trait Fragment[T, +E] extends UrlPart[T, E] {

def as[U](implicit codec: Codec[T, U]): Fragment[U, E] = as[U](codec.leftToRight _, codec.rightToLeft _)

/**
* Turns this fragment matching a `T` into a fragment matching an [[Option]] of T.
* It will return Some(t) if t could be extracted, and None otherwise.
/** Turns this fragment matching a `T` into a fragment matching an [[Option]] of T. It will return Some(t) if t could
* be extracted, and None otherwise.
*
* The failure that happened and led to an error does not matter: it will result in None, no matter what.
*/
def ? : Fragment[Option[T], E] = factory(
matchFragment(_) match {
case Left(_) => Right(None)
case Right(value) => Right(Some(value))
}, {
},
{
case Some(t) => createFragment(t)
case None => MaybeFragment(None)
}
)

/**
* Adds an extra satisfying criteria to the de-serialized output of this [[Fragment]].
* When the output of this [[Fragment]] does not satisfy the given predicate, the given error is returned
* instead.
/** Adds an extra satisfying criteria to the de-serialized output of this [[Fragment]]. When the output of this
* [[Fragment]] does not satisfy the given predicate, the given error is returned instead.
*
* @param predicate criteria that the output has to verify
* @param error error happening when it's not the case
* @tparam E1 new type of the error
* @return a new [[Fragment]] matching the same fragment information, but only when the predicate is satisfied
* @param predicate
* criteria that the output has to verify
* @param error
* error happening when it's not the case
* @tparam E1
* new type of the error
* @return
* a new [[Fragment]] matching the same fragment information, but only when the predicate is satisfied
*/
final def filter[E1 >: E](predicate: T => Boolean, error: MaybeFragment => E1): Fragment[T, E1] =
Fragment.factory[T, E1](
Expand All @@ -91,19 +94,20 @@ trait Fragment[T, +E] extends UrlPart[T, E] {
this.asInstanceOf[Fragment[T, DummyError]].filter(predicate, _ => DummyError.dummyError)
}

/**
* Returns a [[Fragment]] which outputs the contents of this [[Fragment]] when result is a [[Some]] and the
* specified `default` value otherwise.
* When generating the path, it will only generate paths corresponding to the [[Some]] case.
/** Returns a [[Fragment]] which outputs the contents of this [[Fragment]] when result is a [[Some]] and the specified
* `default` value otherwise. When generating the path, it will only generate paths corresponding to the [[Some]]
* case.
*
* @note This method is only available when `T =:= Option[U]`.
* @note
* This method is only available when `T =:= Option[U]`.
*
* @param default default value when output is empty
* @param default
* default value when output is empty
*/
final def getOrElse[U](default: => U)(implicit ev: T =:= Option[U]): Fragment[U, E] =
factory[U, E](
(maybeFragment: MaybeFragment) => matchFragment(maybeFragment).map(ev(_).getOrElse(default)),
//(u: U) => createFragment(ev.flip(Some(u)))
// (u: U) => createFragment(ev.flip(Some(u)))
// we keep the ugliness below while supporting 2.12 todo[scala3] remove
(u: U) => createFragment(Some(u).asInstanceOf[T])
)
Expand All @@ -118,14 +122,13 @@ object Fragment {
def createFragment(t: T): MaybeFragment = generator(t)
}

/**
* Creates a fragment matching any element of type `T`, as long as the [[urldsl.vocabulary.FromString]] can
/** Creates a fragment matching any element of type `T`, as long as the [[urldsl.vocabulary.FromString]] can
* de-serialize it.
*
* If the fragment is missing, returns an error.
*/
def fragment[T, A](
implicit fromString: FromString[T, A],
def fragment[T, A](implicit
fromString: FromString[T, A],
printer: Printer[T],
fragmentMatchingError: FragmentMatchingError[A]
): Fragment[T, A] = factory[T, A](
Expand All @@ -136,14 +139,13 @@ object Fragment {
(printer.apply _).andThen(Some(_)).andThen(MaybeFragment.apply)
)

/**
* Creates a fragment matching any element of type `T`, as long as the [[urldsl.vocabulary.FromString]] can
/** Creates a fragment matching any element of type `T`, as long as the [[urldsl.vocabulary.FromString]] can
* de-serialize it.
*
* If the fragment is missing, returns None.
*/
final def maybeFragment[T, A](
implicit fromString: FromString[T, A],
final def maybeFragment[T, A](implicit
fromString: FromString[T, A],
printer: Printer[T],
fragmentMatchingError: FragmentMatchingError[A]
): Fragment[Option[T], A] = factory[Option[T], A](
Expand All @@ -163,8 +165,8 @@ object Fragment {
(_: Unit) => MaybeFragment(None)
)

implicit def asFragment[T, A](t: T)(
implicit fromString: FromString[T, A],
implicit def asFragment[T, A](t: T)(implicit
fromString: FromString[T, A],
printer: Printer[T],
fragmentMatchingError: FragmentMatchingError[A],
classTag: ClassTag[T]
Expand All @@ -173,11 +175,12 @@ object Fragment {
case MaybeFragment(None) => Left(fragmentMatchingError.missingFragmentError)
case MaybeFragment(Some(fragment)) =>
fromString(fragment) match {
case Left(value) => Left(value)
case Right(decodedValue) => decodedValue match {
case value: T if value == t => Right(())
case _ => Left(fragmentMatchingError.wrongValue(decodedValue, t))
}
case Left(value) => Left(value)
case Right(decodedValue) =>
decodedValue match {
case value: T if value == t => Right(())
case _ => Left(fragmentMatchingError.wrongValue(decodedValue, t))
}
}
},
_ => MaybeFragment(Some(printer.print(t)))
Expand Down
Loading

0 comments on commit cc82df0

Please sign in to comment.