From a160fda8785dd42b9d149ee5271913f7e9e6e30a Mon Sep 17 00:00:00 2001 From: Jamie Willis Date: Wed, 26 Mar 2025 15:03:13 +0000 Subject: [PATCH] fix(js): made typeclasses lazy, allowing for tree-shaking on scala.js --- .../ws/zio/TapirSttpClientZioWebSockets.scala | 2 +- .../ws/zio/TapirSttpClientZioWebSockets.scala | 2 +- .../sttp/tapir/client/tests/ClientTests.scala | 2 +- core/src/main/scala/sttp/tapir/Codec.scala | 94 +++++++++---------- core/src/main/scala/sttp/tapir/Schema.scala | 66 ++++++------- .../sttp/tapir/generic/Configuration.scala | 2 +- .../sttp/tapir/typelevel/MatchType.scala | 18 ++-- .../openapi/models/OpenapiSchemaType.scala | 38 ++++---- .../models/OpenapiSecuritySchemeType.scala | 12 +-- 9 files changed, 118 insertions(+), 118 deletions(-) diff --git a/client/sttp-client/src/main/scalajs/sttp/tapir/client/sttp/ws/zio/TapirSttpClientZioWebSockets.scala b/client/sttp-client/src/main/scalajs/sttp/tapir/client/sttp/ws/zio/TapirSttpClientZioWebSockets.scala index 83eff11e57..58ef9f9402 100644 --- a/client/sttp-client/src/main/scalajs/sttp/tapir/client/sttp/ws/zio/TapirSttpClientZioWebSockets.scala +++ b/client/sttp-client/src/main/scalajs/sttp/tapir/client/sttp/ws/zio/TapirSttpClientZioWebSockets.scala @@ -5,6 +5,6 @@ import sttp.capabilities.zio.ZioStreams import sttp.tapir.client.sttp.WebSocketToPipe trait TapirSttpClientZioWebSockets { - implicit val webSocketsSupportedForZioStreams: WebSocketToPipe[ZioStreams with WebSockets] = + implicit lazy val webSocketsSupportedForZioStreams: WebSocketToPipe[ZioStreams with WebSockets] = new WebSocketToZioPipe[ZioStreams with WebSockets] } diff --git a/client/sttp-client/src/main/scalajvm/sttp/tapir/client/sttp/ws/zio/TapirSttpClientZioWebSockets.scala b/client/sttp-client/src/main/scalajvm/sttp/tapir/client/sttp/ws/zio/TapirSttpClientZioWebSockets.scala index 83eff11e57..58ef9f9402 100644 --- a/client/sttp-client/src/main/scalajvm/sttp/tapir/client/sttp/ws/zio/TapirSttpClientZioWebSockets.scala +++ b/client/sttp-client/src/main/scalajvm/sttp/tapir/client/sttp/ws/zio/TapirSttpClientZioWebSockets.scala @@ -5,6 +5,6 @@ import sttp.capabilities.zio.ZioStreams import sttp.tapir.client.sttp.WebSocketToPipe trait TapirSttpClientZioWebSockets { - implicit val webSocketsSupportedForZioStreams: WebSocketToPipe[ZioStreams with WebSockets] = + implicit lazy val webSocketsSupportedForZioStreams: WebSocketToPipe[ZioStreams with WebSockets] = new WebSocketToZioPipe[ZioStreams with WebSockets] } diff --git a/client/tests/src/main/scala/sttp/tapir/client/tests/ClientTests.scala b/client/tests/src/main/scala/sttp/tapir/client/tests/ClientTests.scala index 45b3524f4f..1bea6065d0 100644 --- a/client/tests/src/main/scala/sttp/tapir/client/tests/ClientTests.scala +++ b/client/tests/src/main/scala/sttp/tapir/client/tests/ClientTests.scala @@ -13,7 +13,7 @@ import sttp.tapir.{DecodeResult, _} import scala.concurrent.ExecutionContext abstract class ClientTests[R] extends AsyncFunSuite with Matchers with BeforeAndAfterAll { - implicit val ioRT: IORuntime = ClientTestsPlatform.ioRT + implicit lazy val ioRT: IORuntime = ClientTestsPlatform.ioRT implicit override val executionContext: ExecutionContext = ClientTestsPlatform.executionContext type Port = Int diff --git a/core/src/main/scala/sttp/tapir/Codec.scala b/core/src/main/scala/sttp/tapir/Codec.scala index 5112aa00fd..dbeec6d419 100644 --- a/core/src/main/scala/sttp/tapir/Codec.scala +++ b/core/src/main/scala/sttp/tapir/Codec.scala @@ -191,41 +191,41 @@ object Codec extends CodecExtensions with CodecExtensions2 with FormCodecMacros } def idPlain[L](s: Schema[L] = Schema[L](SchemaType.SString())): Codec[L, L, CodecFormat.TextPlain] = id(CodecFormat.TextPlain(), s) - implicit val string: Codec[String, String, TextPlain] = id[String, TextPlain](TextPlain(), Schema.schemaForString) - - implicit val byte: Codec[String, Byte, TextPlain] = parsedString[Byte](_.toByte).schema(Schema.schemaForByte) - implicit val short: Codec[String, Short, TextPlain] = parsedString[Short](_.toShort).schema(Schema.schemaForShort) - implicit val int: Codec[String, Int, TextPlain] = parsedString[Int](_.toInt).schema(Schema.schemaForInt) - implicit val long: Codec[String, Long, TextPlain] = parsedString[Long](_.toLong).schema(Schema.schemaForLong) - implicit val float: Codec[String, Float, TextPlain] = parsedString[Float](_.toFloat).schema(Schema.schemaForFloat) - implicit val double: Codec[String, Double, TextPlain] = parsedString[Double](_.toDouble).schema(Schema.schemaForDouble) - implicit val boolean: Codec[String, Boolean, TextPlain] = parsedString[Boolean](_.toBoolean).schema(Schema.schemaForBoolean) - implicit val uuid: Codec[String, UUID, TextPlain] = parsedString[UUID](UUID.fromString).schema(Schema.schemaForUUID) - implicit val bigDecimal: Codec[String, BigDecimal, TextPlain] = parsedString[BigDecimal](BigDecimal(_)).schema(Schema.schemaForBigDecimal) - implicit val javaBigDecimal: Codec[String, JBigDecimal, TextPlain] = + implicit lazy val string: Codec[String, String, TextPlain] = id[String, TextPlain](TextPlain(), Schema.schemaForString) + + implicit lazy val byte: Codec[String, Byte, TextPlain] = parsedString[Byte](_.toByte).schema(Schema.schemaForByte) + implicit lazy val short: Codec[String, Short, TextPlain] = parsedString[Short](_.toShort).schema(Schema.schemaForShort) + implicit lazy val int: Codec[String, Int, TextPlain] = parsedString[Int](_.toInt).schema(Schema.schemaForInt) + implicit lazy val long: Codec[String, Long, TextPlain] = parsedString[Long](_.toLong).schema(Schema.schemaForLong) + implicit lazy val float: Codec[String, Float, TextPlain] = parsedString[Float](_.toFloat).schema(Schema.schemaForFloat) + implicit lazy val double: Codec[String, Double, TextPlain] = parsedString[Double](_.toDouble).schema(Schema.schemaForDouble) + implicit lazy val boolean: Codec[String, Boolean, TextPlain] = parsedString[Boolean](_.toBoolean).schema(Schema.schemaForBoolean) + implicit lazy val uuid: Codec[String, UUID, TextPlain] = parsedString[UUID](UUID.fromString).schema(Schema.schemaForUUID) + implicit lazy val bigDecimal: Codec[String, BigDecimal, TextPlain] = parsedString[BigDecimal](BigDecimal(_)).schema(Schema.schemaForBigDecimal) + implicit lazy val javaBigDecimal: Codec[String, JBigDecimal, TextPlain] = parsedString[JBigDecimal](new JBigDecimal(_)).schema(Schema.schemaForJBigDecimal) - implicit val bigInt: Codec[String, BigInt, TextPlain] = parsedString[BigInt](BigInt(_)).schema(Schema.schemaForBigInt) - implicit val javaBigInteger: Codec[String, JBigInteger, TextPlain] = + implicit lazy val bigInt: Codec[String, BigInt, TextPlain] = parsedString[BigInt](BigInt(_)).schema(Schema.schemaForBigInt) + implicit lazy val javaBigInteger: Codec[String, JBigInteger, TextPlain] = parsedString[JBigInteger](new JBigInteger(_)).schema(Schema.schemaForJBigInteger) - implicit val localTime: Codec[String, LocalTime, TextPlain] = + implicit lazy val localTime: Codec[String, LocalTime, TextPlain] = string.map(LocalTime.parse(_))(DateTimeFormatter.ISO_LOCAL_TIME.format).schema(Schema.schemaForLocalTime) - implicit val localDate: Codec[String, LocalDate, TextPlain] = + implicit lazy val localDate: Codec[String, LocalDate, TextPlain] = string.map(LocalDate.parse(_))(DateTimeFormatter.ISO_LOCAL_DATE.format).schema(Schema.schemaForLocalDate) - implicit val offsetDateTime: Codec[String, OffsetDateTime, TextPlain] = + implicit lazy val offsetDateTime: Codec[String, OffsetDateTime, TextPlain] = string.map(OffsetDateTime.parse(_))(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format).schema(Schema.schemaForOffsetDateTime) - implicit val zonedDateTime: Codec[String, ZonedDateTime, TextPlain] = + implicit lazy val zonedDateTime: Codec[String, ZonedDateTime, TextPlain] = string.map(ZonedDateTime.parse(_))(DateTimeFormatter.ISO_ZONED_DATE_TIME.format).schema(Schema.schemaForZonedDateTime) - implicit val instant: Codec[String, Instant, TextPlain] = + implicit lazy val instant: Codec[String, Instant, TextPlain] = string.map(Instant.parse(_))(DateTimeFormatter.ISO_INSTANT.format).schema(Schema.schemaForInstant) - implicit val date: Codec[String, Date, TextPlain] = instant.map(Date.from(_))(_.toInstant).schema(Schema.schemaForDate) - implicit val zoneOffset: Codec[String, ZoneOffset, TextPlain] = parsedString[ZoneOffset](ZoneOffset.of).schema(Schema.schemaForZoneOffset) - implicit val zoneId: Codec[String, ZoneId, TextPlain] = parsedString[ZoneId](ZoneId.of).schema(Schema.schemaForZoneId) - implicit val duration: Codec[String, Duration, TextPlain] = parsedString[Duration](Duration.parse).schema(Schema.schemaForJavaDuration) - implicit val offsetTime: Codec[String, OffsetTime, TextPlain] = + implicit lazy val date: Codec[String, Date, TextPlain] = instant.map(Date.from(_))(_.toInstant).schema(Schema.schemaForDate) + implicit lazy val zoneOffset: Codec[String, ZoneOffset, TextPlain] = parsedString[ZoneOffset](ZoneOffset.of).schema(Schema.schemaForZoneOffset) + implicit lazy val zoneId: Codec[String, ZoneId, TextPlain] = parsedString[ZoneId](ZoneId.of).schema(Schema.schemaForZoneId) + implicit lazy val duration: Codec[String, Duration, TextPlain] = parsedString[Duration](Duration.parse).schema(Schema.schemaForJavaDuration) + implicit lazy val offsetTime: Codec[String, OffsetTime, TextPlain] = string.map(OffsetTime.parse(_))(DateTimeFormatter.ISO_OFFSET_TIME.format).schema(Schema.schemaForOffsetTime) - implicit val scalaDuration: Codec[String, SDuration, TextPlain] = + implicit lazy val scalaDuration: Codec[String, SDuration, TextPlain] = parsedString[SDuration](SDuration.apply).schema(Schema.schemaForScalaDuration) - implicit val localDateTime: Codec[String, LocalDateTime, TextPlain] = string + implicit lazy val localDateTime: Codec[String, LocalDateTime, TextPlain] = string .mapDecode { l => try { try { @@ -239,7 +239,7 @@ object Codec extends CodecExtensions with CodecExtensions2 with FormCodecMacros }(h => OffsetDateTime.of(h, ZoneOffset.UTC).toString) .schema(Schema.schemaForLocalDateTime) - implicit val uri: PlainCodec[Uri] = + implicit lazy val uri: PlainCodec[Uri] = string .mapDecode(raw => Uri.parse(raw).fold(e => DecodeResult.Error(raw, new IllegalArgumentException(e)), DecodeResult.Value(_)))( _.toString() @@ -249,20 +249,20 @@ object Codec extends CodecExtensions with CodecExtensions2 with FormCodecMacros def parsedString[T: Schema](parse: String => T): Codec[String, T, TextPlain] = string.map(parse)(_.toString).schema(implicitly[Schema[T]]) - implicit val byteArray: Codec[Array[Byte], Array[Byte], OctetStream] = + implicit lazy val byteArray: Codec[Array[Byte], Array[Byte], OctetStream] = id[Array[Byte], OctetStream](OctetStream(), Schema.schemaForByteArray) - implicit val inputStream: Codec[InputStream, InputStream, OctetStream] = + implicit lazy val inputStream: Codec[InputStream, InputStream, OctetStream] = id[InputStream, OctetStream](OctetStream(), Schema.schemaForInputStream) - implicit val inputStreamRange: Codec[InputStreamRange, InputStreamRange, OctetStream] = + implicit lazy val inputStreamRange: Codec[InputStreamRange, InputStreamRange, OctetStream] = id[InputStreamRange, OctetStream](OctetStream(), Schema.schemaForInputStreamRange) - implicit val byteBuffer: Codec[ByteBuffer, ByteBuffer, OctetStream] = + implicit lazy val byteBuffer: Codec[ByteBuffer, ByteBuffer, OctetStream] = id[ByteBuffer, OctetStream](OctetStream(), Schema.schemaForByteBuffer) - implicit val fileRange: Codec[FileRange, FileRange, OctetStream] = + implicit lazy val fileRange: Codec[FileRange, FileRange, OctetStream] = id[FileRange, OctetStream](OctetStream(), Schema.schemaForFileRange) - implicit val file: Codec[FileRange, TapirFile, OctetStream] = fileRange.map(_.file)(f => FileRange(f)) + implicit lazy val file: Codec[FileRange, TapirFile, OctetStream] = fileRange.map(_.file)(f => FileRange(f)) - implicit val formSeqUtf8: Codec[String, Seq[(String, String)], XWwwFormUrlencoded] = formSeq(StandardCharsets.UTF_8) - implicit val formMapUtf8: Codec[String, Map[String, String], XWwwFormUrlencoded] = formMap(StandardCharsets.UTF_8) + implicit lazy val formSeqUtf8: Codec[String, Seq[(String, String)], XWwwFormUrlencoded] = formSeq(StandardCharsets.UTF_8) + implicit lazy val formMapUtf8: Codec[String, Map[String, String], XWwwFormUrlencoded] = formMap(StandardCharsets.UTF_8) def formSeq(charset: Charset): Codec[String, Seq[(String, String)], XWwwFormUrlencoded] = string.format(XWwwFormUrlencoded()).map(UrlencodedData.decode(_, charset))(UrlencodedData.encode(_, charset)) @@ -395,7 +395,7 @@ object Codec extends CodecExtensions with CodecExtensions2 with FormCodecMacros // - implicit val webSocketFrame: Codec[WebSocketFrame, WebSocketFrame, CodecFormat.TextPlain] = Codec.idPlain() + implicit lazy val webSocketFrame: Codec[WebSocketFrame, WebSocketFrame, CodecFormat.TextPlain] = Codec.idPlain() /** A codec which expects only text frames (all other frames cause a decoding error) and handles the text using the given `stringCodec`. */ @@ -593,15 +593,15 @@ object Codec extends CodecExtensions with CodecExtensions2 with FormCodecMacros // header values - implicit val mediaType: Codec[String, MediaType, CodecFormat.TextPlain] = Codec.string.mapDecode { v => + implicit lazy val mediaType: Codec[String, MediaType, CodecFormat.TextPlain] = Codec.string.mapDecode { v => DecodeResult.fromEitherString(v, MediaType.parse(v)) }(_.toString) - implicit val etag: Codec[String, ETag, CodecFormat.TextPlain] = Codec.string.mapDecode { v => + implicit lazy val etag: Codec[String, ETag, CodecFormat.TextPlain] = Codec.string.mapDecode { v => DecodeResult.fromEitherString(v, ETag.parse(v)) }(_.toString) - implicit val range: Codec[String, Range, CodecFormat.TextPlain] = Codec.string.mapDecode { v => + implicit lazy val range: Codec[String, Range, CodecFormat.TextPlain] = Codec.string.mapDecode { v => DecodeResult.fromEitherString(v, Range.parse(v)).flatMap { case Nil => DecodeResult.Missing case List(r) => DecodeResult.Value(r) @@ -609,11 +609,11 @@ object Codec extends CodecExtensions with CodecExtensions2 with FormCodecMacros } }(_.toString) - implicit val contentRange: Codec[String, ContentRange, CodecFormat.TextPlain] = Codec.string.mapDecode { v => + implicit lazy val contentRange: Codec[String, ContentRange, CodecFormat.TextPlain] = Codec.string.mapDecode { v => DecodeResult.fromEitherString(v, ContentRange.parse(v)) }(_.toString) - implicit val cacheDirective: Codec[String, List[CacheDirective], CodecFormat.TextPlain] = Codec.string.mapDecode { v => + implicit lazy val cacheDirective: Codec[String, List[CacheDirective], CodecFormat.TextPlain] = Codec.string.mapDecode { v => @tailrec def toEitherOrList[T, U](l: List[Either[T, U]], acc: List[U]): Either[T, List[U]] = l match { case Nil => Right(acc.reverse) @@ -629,8 +629,8 @@ object Codec extends CodecExtensions with CodecExtensions2 with FormCodecMacros case Right(r) => DecodeResult.Value(r) } - implicit val cookie: Codec[String, List[Cookie], TextPlain] = Codec.string.mapDecode(decodeCookie)(cs => Cookie.toString(cs)) - implicit val cookies: Codec[List[String], List[Cookie], TextPlain] = Codec.list(cookie).map(_.flatten)(List(_)) + implicit lazy val cookie: Codec[String, List[Cookie], TextPlain] = Codec.string.mapDecode(decodeCookie)(cs => Cookie.toString(cs)) + implicit lazy val cookies: Codec[List[String], List[Cookie], TextPlain] = Codec.list(cookie).map(_.flatten)(List(_)) private[tapir] def decodeCookieWithMeta(cookie: String): DecodeResult[CookieWithMeta] = CookieWithMeta.parse(cookie) match { @@ -638,8 +638,8 @@ object Codec extends CodecExtensions with CodecExtensions2 with FormCodecMacros case Right(r) => DecodeResult.Value(r) } - implicit val cookieWithMeta: Codec[String, CookieWithMeta, TextPlain] = Codec.string.mapDecode(decodeCookieWithMeta)(_.toString) - implicit val cookiesWithMeta: Codec[List[String], List[CookieWithMeta], TextPlain] = Codec.list(cookieWithMeta) + implicit lazy val cookieWithMeta: Codec[String, CookieWithMeta, TextPlain] = Codec.string.mapDecode(decodeCookieWithMeta)(_.toString) + implicit lazy val cookiesWithMeta: Codec[List[String], List[CookieWithMeta], TextPlain] = Codec.list(cookieWithMeta) // raw tuples @@ -737,9 +737,9 @@ case class MultipartCodec[T](rawBodyType: RawBodyType.MultipartBody, codec: Code } object MultipartCodec extends MultipartCodecMacros { - private val arrayBytePartListCodec = implicitly[Codec[List[Part[Array[Byte]]], List[Part[Array[Byte]]], OctetStream]] + private lazy val arrayBytePartListCodec = implicitly[Codec[List[Part[Array[Byte]]], List[Part[Array[Byte]]], OctetStream]] - val Default: MultipartCodec[Seq[Part[Array[Byte]]]] = + lazy val Default: MultipartCodec[Seq[Part[Array[Byte]]]] = Codec .multipart(Map.empty, Some(PartCodec(RawBodyType.ByteArrayBody, arrayBytePartListCodec))) // we know that all parts will end up as byte arrays; also, removing/restoring the by-name grouping of parts diff --git a/core/src/main/scala/sttp/tapir/Schema.scala b/core/src/main/scala/sttp/tapir/Schema.scala index 754614af51..30943ea0c4 100644 --- a/core/src/main/scala/sttp/tapir/Schema.scala +++ b/core/src/main/scala/sttp/tapir/Schema.scala @@ -304,39 +304,39 @@ object Schema extends LowPrioritySchema with SchemaCompanionMacros { /** Creates a schema for type `T`, where the low-level representation is binary. */ def binary[T]: Schema[T] = Schema(SBinary()) - implicit val schemaForString: Schema[String] = Schema(SString()) - implicit val schemaForByte: Schema[Byte] = Schema(SInteger()) - implicit val schemaForShort: Schema[Short] = Schema(SInteger()) - implicit val schemaForInt: Schema[Int] = Schema(SInteger[Int]()).format("int32") - implicit val schemaForLong: Schema[Long] = Schema(SInteger[Long]()).format("int64") - implicit val schemaForFloat: Schema[Float] = Schema(SNumber[Float]()).format("float") - implicit val schemaForDouble: Schema[Double] = Schema(SNumber[Double]()).format("double") - implicit val schemaForBoolean: Schema[Boolean] = Schema(SBoolean()) - implicit val schemaForUnit: Schema[Unit] = Schema(SProduct.empty) - implicit val schemaForFileRange: Schema[FileRange] = Schema(SBinary()) - implicit val schemaForByteArray: Schema[Array[Byte]] = Schema(SBinary()) - implicit val schemaForByteBuffer: Schema[ByteBuffer] = Schema(SBinary()) - implicit val schemaForInputStream: Schema[InputStream] = Schema(SBinary()) - implicit val schemaForInputStreamRange: Schema[InputStreamRange] = Schema(SchemaType.SBinary()) - implicit val schemaForInstant: Schema[Instant] = Schema(SDateTime()) - implicit val schemaForZonedDateTime: Schema[ZonedDateTime] = Schema(SDateTime()) - implicit val schemaForOffsetDateTime: Schema[OffsetDateTime] = Schema(SDateTime()) - implicit val schemaForDate: Schema[Date] = Schema(SDateTime()) - implicit val schemaForLocalDateTime: Schema[LocalDateTime] = Schema(SString()) - implicit val schemaForLocalDate: Schema[LocalDate] = Schema(SDate()) - implicit val schemaForZoneOffset: Schema[ZoneOffset] = Schema(SString()) - implicit val schemaForZoneId: Schema[ZoneId] = Schema(SString()) - implicit val schemaForJavaDuration: Schema[Duration] = Schema(SString()) - implicit val schemaForLocalTime: Schema[LocalTime] = Schema(SString()) - implicit val schemaForOffsetTime: Schema[OffsetTime] = Schema(SString()) - implicit val schemaForScalaDuration: Schema[scala.concurrent.duration.Duration] = Schema(SString()) - implicit val schemaForUUID: Schema[UUID] = Schema(SString[UUID]()).format("uuid") - implicit val schemaForBigDecimal: Schema[BigDecimal] = Schema(SNumber()) - implicit val schemaForJBigDecimal: Schema[JBigDecimal] = Schema(SNumber()) - implicit val schemaForBigInt: Schema[BigInt] = Schema(SInteger()) - implicit val schemaForJBigInteger: Schema[JBigInteger] = Schema(SInteger()) - implicit val schemaForFile: Schema[TapirFile] = Schema(SBinary()) - implicit val schemaForUri: Schema[Uri] = Schema(SString()) + implicit lazy val schemaForString: Schema[String] = Schema(SString()) + implicit lazy val schemaForByte: Schema[Byte] = Schema(SInteger()) + implicit lazy val schemaForShort: Schema[Short] = Schema(SInteger()) + implicit lazy val schemaForInt: Schema[Int] = Schema(SInteger[Int]()).format("int32") + implicit lazy val schemaForLong: Schema[Long] = Schema(SInteger[Long]()).format("int64") + implicit lazy val schemaForFloat: Schema[Float] = Schema(SNumber[Float]()).format("float") + implicit lazy val schemaForDouble: Schema[Double] = Schema(SNumber[Double]()).format("double") + implicit lazy val schemaForBoolean: Schema[Boolean] = Schema(SBoolean()) + implicit lazy val schemaForUnit: Schema[Unit] = Schema(SProduct.empty) + implicit lazy val schemaForFileRange: Schema[FileRange] = Schema(SBinary()) + implicit lazy val schemaForByteArray: Schema[Array[Byte]] = Schema(SBinary()) + implicit lazy val schemaForByteBuffer: Schema[ByteBuffer] = Schema(SBinary()) + implicit lazy val schemaForInputStream: Schema[InputStream] = Schema(SBinary()) + implicit lazy val schemaForInputStreamRange: Schema[InputStreamRange] = Schema(SchemaType.SBinary()) + implicit lazy val schemaForInstant: Schema[Instant] = Schema(SDateTime()) + implicit lazy val schemaForZonedDateTime: Schema[ZonedDateTime] = Schema(SDateTime()) + implicit lazy val schemaForOffsetDateTime: Schema[OffsetDateTime] = Schema(SDateTime()) + implicit lazy val schemaForDate: Schema[Date] = Schema(SDateTime()) + implicit lazy val schemaForLocalDateTime: Schema[LocalDateTime] = Schema(SString()) + implicit lazy val schemaForLocalDate: Schema[LocalDate] = Schema(SDate()) + implicit lazy val schemaForZoneOffset: Schema[ZoneOffset] = Schema(SString()) + implicit lazy val schemaForZoneId: Schema[ZoneId] = Schema(SString()) + implicit lazy val schemaForJavaDuration: Schema[Duration] = Schema(SString()) + implicit lazy val schemaForLocalTime: Schema[LocalTime] = Schema(SString()) + implicit lazy val schemaForOffsetTime: Schema[OffsetTime] = Schema(SString()) + implicit lazy val schemaForScalaDuration: Schema[scala.concurrent.duration.Duration] = Schema(SString()) + implicit lazy val schemaForUUID: Schema[UUID] = Schema(SString[UUID]()).format("uuid") + implicit lazy val schemaForBigDecimal: Schema[BigDecimal] = Schema(SNumber()) + implicit lazy val schemaForJBigDecimal: Schema[JBigDecimal] = Schema(SNumber()) + implicit lazy val schemaForBigInt: Schema[BigInt] = Schema(SInteger()) + implicit lazy val schemaForJBigInteger: Schema[JBigInteger] = Schema(SInteger()) + implicit lazy val schemaForFile: Schema[TapirFile] = Schema(SBinary()) + implicit lazy val schemaForUri: Schema[Uri] = Schema(SString()) .encodedExample(Uri("https", "example.com")) implicit def schemaForOption[T: Schema]: Schema[Option[T]] = implicitly[Schema[T]].asOption diff --git a/core/src/main/scala/sttp/tapir/generic/Configuration.scala b/core/src/main/scala/sttp/tapir/generic/Configuration.scala index cdbf38e292..b3ce3a7ae5 100644 --- a/core/src/main/scala/sttp/tapir/generic/Configuration.scala +++ b/core/src/main/scala/sttp/tapir/generic/Configuration.scala @@ -68,6 +68,6 @@ object Configuration { private val shortKebabCaseSubtypeTransformation: SName => String = shortIdentitySubtypeTransformation.andThen(kebabCaseTransformation) - implicit val default: Configuration = Configuration(Predef.identity, None, shortIdentitySubtypeTransformation) + implicit lazy val default: Configuration = Configuration(Predef.identity, None, shortIdentitySubtypeTransformation) } diff --git a/core/src/main/scala/sttp/tapir/typelevel/MatchType.scala b/core/src/main/scala/sttp/tapir/typelevel/MatchType.scala index bbc85decb8..e986760fec 100644 --- a/core/src/main/scala/sttp/tapir/typelevel/MatchType.scala +++ b/core/src/main/scala/sttp/tapir/typelevel/MatchType.scala @@ -13,15 +13,15 @@ trait MatchType[T] { object MatchType extends MatchTypeMacros { - implicit val string: MatchType[String] = matchTypeFromPartial { case _: String => true } - implicit val bool: MatchType[Boolean] = matchTypeFromPartial[Boolean] { case _: Boolean => true } - implicit val char: MatchType[Char] = matchTypeFromPartial[Char] { case _: Char => true } - implicit val byte: MatchType[Byte] = matchTypeFromPartial[Byte] { case _: Byte => true } - implicit val short: MatchType[Short] = matchTypeFromPartial[Short] { case _: Short => true } - implicit val long: MatchType[Long] = matchTypeFromPartial { case _: Long => true } - implicit val float: MatchType[Float] = matchTypeFromPartial[Float] { case _: Float => true } - implicit val double: MatchType[Double] = matchTypeFromPartial[Double] { case _: Double => true } - implicit val int: MatchType[Int] = matchTypeFromPartial[Int] { case _: Int => true } + implicit lazy val string: MatchType[String] = matchTypeFromPartial { case _: String => true } + implicit lazy val bool: MatchType[Boolean] = matchTypeFromPartial[Boolean] { case _: Boolean => true } + implicit lazy val char: MatchType[Char] = matchTypeFromPartial[Char] { case _: Char => true } + implicit lazy val byte: MatchType[Byte] = matchTypeFromPartial[Byte] { case _: Byte => true } + implicit lazy val short: MatchType[Short] = matchTypeFromPartial[Short] { case _: Short => true } + implicit lazy val long: MatchType[Long] = matchTypeFromPartial { case _: Long => true } + implicit lazy val float: MatchType[Float] = matchTypeFromPartial[Float] { case _: Float => true } + implicit lazy val double: MatchType[Double] = matchTypeFromPartial[Double] { case _: Double => true } + implicit lazy val int: MatchType[Int] = matchTypeFromPartial[Int] { case _: Int => true } private[typelevel] def matchTypeFromPartial[T](pf: PartialFunction[Any, Boolean]): MatchType[T] = { a => pf.lift(a).getOrElse(false) } } diff --git a/openapi-codegen/core/src/main/scala/sttp/tapir/codegen/openapi/models/OpenapiSchemaType.scala b/openapi-codegen/core/src/main/scala/sttp/tapir/codegen/openapi/models/OpenapiSchemaType.scala index 38d40adb2f..c3f1d7e803 100644 --- a/openapi-codegen/core/src/main/scala/sttp/tapir/codegen/openapi/models/OpenapiSchemaType.scala +++ b/openapi-codegen/core/src/main/scala/sttp/tapir/codegen/openapi/models/OpenapiSchemaType.scala @@ -142,7 +142,7 @@ object OpenapiSchemaType { import io.circe._ import cats.implicits._ - implicit val OpenapiSchemaRefDecoder: Decoder[OpenapiSchemaRef] = { (c: HCursor) => + implicit lazy val OpenapiSchemaRefDecoder: Decoder[OpenapiSchemaRef] = { (c: HCursor) => for { r <- c.downField("$ref").as[String] } yield { @@ -163,7 +163,7 @@ object OpenapiSchemaType { } yield (t, nullableByType || nb.contains(true)) } - implicit val OpenapiSchemaBooleanDecoder: Decoder[OpenapiSchemaBoolean] = { (c: HCursor) => + implicit lazy val OpenapiSchemaBooleanDecoder: Decoder[OpenapiSchemaBoolean] = { (c: HCursor) => for { p <- typeAndNullable(c).ensure(DecodingFailure("Given type is not boolean!", c.history))(_._1 == "boolean") } yield { @@ -171,7 +171,7 @@ object OpenapiSchemaType { } } - implicit val OpenapiSchemaStringTypeDecoder: Decoder[OpenapiSchemaStringType] = { (c: HCursor) => + implicit lazy val OpenapiSchemaStringTypeDecoder: Decoder[OpenapiSchemaStringType] = { (c: HCursor) => for { p <- typeAndNullable(c).ensure(DecodingFailure("Given type is not string!", c.history))(_._1 == "string") f <- c.downField("format").as[Option[String]] @@ -189,7 +189,7 @@ object OpenapiSchemaType { } } - implicit val OpenapiSchemaNumericTypeDecoder: Decoder[OpenapiSchemaNumericType] = { (c: HCursor) => + implicit lazy val OpenapiSchemaNumericTypeDecoder: Decoder[OpenapiSchemaNumericType] = { (c: HCursor) => for { p <- typeAndNullable(c) .ensure(DecodingFailure("Given type is not number/integer!", c.history))(v => v._1 == "number" || v._1 == "integer") @@ -218,7 +218,7 @@ object OpenapiSchemaType { } } - implicit val OpenapiSchemaSimpleTypeDecoder: Decoder[OpenapiSchemaSimpleType] = + implicit lazy val OpenapiSchemaSimpleTypeDecoder: Decoder[OpenapiSchemaSimpleType] = List[Decoder[OpenapiSchemaSimpleType]]( Decoder[OpenapiSchemaRef].widen, Decoder[OpenapiSchemaBoolean].widen, @@ -226,14 +226,14 @@ object OpenapiSchemaType { Decoder[OpenapiSchemaNumericType].widen ).reduceLeft(_ or _) - implicit val DiscriminatorDecoder: Decoder[Discriminator] = { (c: HCursor) => + implicit lazy val DiscriminatorDecoder: Decoder[Discriminator] = { (c: HCursor) => for { propertyName <- c.downField("propertyName").as[String] mapping <- c.downField("mapping").as[Option[Map[String, String]]] } yield Discriminator(propertyName, mapping) } - implicit val OpenapiSchemaOneOfDecoder: Decoder[OpenapiSchemaOneOf] = { (c: HCursor) => + implicit lazy val OpenapiSchemaOneOfDecoder: Decoder[OpenapiSchemaOneOf] = { (c: HCursor) => for { variants <- c.downField("oneOf").as[Seq[OpenapiSchemaSimpleType]] discriminator <- c.downField("discriminator").as[Option[Discriminator]] @@ -242,7 +242,7 @@ object OpenapiSchemaType { } } - implicit val OpenapiSchemaAllOfDecoder: Decoder[OpenapiSchemaAllOf] = { (c: HCursor) => + implicit lazy val OpenapiSchemaAllOfDecoder: Decoder[OpenapiSchemaAllOf] = { (c: HCursor) => for { d <- c.downField("allOf").as[Seq[OpenapiSchemaSimpleType]] } yield { @@ -250,7 +250,7 @@ object OpenapiSchemaType { } } - implicit val OpenapiSchemaAnyOfDecoder: Decoder[OpenapiSchemaAnyOf] = { (c: HCursor) => + implicit lazy val OpenapiSchemaAnyOfDecoder: Decoder[OpenapiSchemaAnyOf] = { (c: HCursor) => for { d <- c.downField("anyOf").as[Seq[OpenapiSchemaSimpleType]] } yield { @@ -258,7 +258,7 @@ object OpenapiSchemaType { } } - implicit val OpenapiSchemaMixedTypeDecoder: Decoder[OpenapiSchemaMixedType] = { + implicit lazy val OpenapiSchemaMixedTypeDecoder: Decoder[OpenapiSchemaMixedType] = { List[Decoder[OpenapiSchemaMixedType]]( Decoder[OpenapiSchemaOneOf].widen, Decoder[OpenapiSchemaAnyOf].widen, @@ -266,7 +266,7 @@ object OpenapiSchemaType { ).reduceLeft(_ or _) } - implicit val OpenapiSchemaNotDecoder: Decoder[OpenapiSchemaNot] = { (c: HCursor) => + implicit lazy val OpenapiSchemaNotDecoder: Decoder[OpenapiSchemaNot] = { (c: HCursor) => for { d <- c.downField("not").as[OpenapiSchemaType] } yield { @@ -274,10 +274,10 @@ object OpenapiSchemaType { } } - implicit val OpenapiSchemaConstantDecoder: Decoder[OpenapiSchemaConstantString] = + implicit lazy val OpenapiSchemaConstantDecoder: Decoder[OpenapiSchemaConstantString] = Decoder.decodeString.map(OpenapiSchemaConstantString.apply) - implicit val OpenapiSchemaEnumDecoder: Decoder[OpenapiSchemaEnum] = { (c: HCursor) => + implicit lazy val OpenapiSchemaEnumDecoder: Decoder[OpenapiSchemaEnum] = { (c: HCursor) => for { p <- typeAndNullable(c) (tpe, nb) = p @@ -286,13 +286,13 @@ object OpenapiSchemaType { } yield OpenapiSchemaEnum(tpe, items, nb) } - implicit val SchemaTypeWithDefaultDecoder: Decoder[(OpenapiSchemaType, Option[Json])] = { (c: HCursor) => + implicit lazy val SchemaTypeWithDefaultDecoder: Decoder[(OpenapiSchemaType, Option[Json])] = { (c: HCursor) => for { schemaType <- c.as[OpenapiSchemaType] maybeDefault <- c.downField("default").as[Option[Json]] } yield (schemaType, maybeDefault) } - implicit val OpenapiSchemaObjectDecoder: Decoder[OpenapiSchemaObject] = { (c: HCursor) => + implicit lazy val OpenapiSchemaObjectDecoder: Decoder[OpenapiSchemaObject] = { (c: HCursor) => for { p <- typeAndNullable(c).ensure(DecodingFailure("Given type is not object!", c.history))(_._1 == "object") fieldsWithDefaults <- c.downField("properties").as[Option[Map[String, (OpenapiSchemaType, Option[Json])]]] @@ -304,7 +304,7 @@ object OpenapiSchemaType { } } - implicit val OpenapiSchemaMapDecoder: Decoder[OpenapiSchemaMap] = { (c: HCursor) => + implicit lazy val OpenapiSchemaMapDecoder: Decoder[OpenapiSchemaMap] = { (c: HCursor) => for { p <- typeAndNullable(c).ensure(DecodingFailure("Given type is not object!", c.history))(_._1 == "object") t <- c.downField("additionalProperties").as[OpenapiSchemaType] @@ -314,14 +314,14 @@ object OpenapiSchemaType { } } - implicit val xmlArrayConfigurationDecoder: Decoder[OpenapiXml.XmlArrayConfiguration] = { (c: HCursor) => + implicit lazy val xmlArrayConfigurationDecoder: Decoder[OpenapiXml.XmlArrayConfiguration] = { (c: HCursor) => for { name <- c.downField("name").as[Option[String]] wrapped <- c.downField("wrapped").as[Option[Boolean]] } yield OpenapiXml.XmlArrayConfiguration(name, wrapped, None) } - implicit val OpenapiSchemaArrayDecoder: Decoder[OpenapiSchemaArray] = { (c: HCursor) => + implicit lazy val OpenapiSchemaArrayDecoder: Decoder[OpenapiSchemaArray] = { (c: HCursor) => for { p <- typeAndNullable(c).ensure(DecodingFailure("Given type is not array!", c.history))(v => v._1 == "array" || v._1 == "object") f <- c.downField("items").as[OpenapiSchemaType] @@ -337,7 +337,7 @@ object OpenapiSchemaType { } } - implicit val OpenapiSchemaAnyDecoder: Decoder[OpenapiSchemaAny] = { (c: HCursor) => + implicit lazy val OpenapiSchemaAnyDecoder: Decoder[OpenapiSchemaAny] = { (c: HCursor) => for { _ <- c.downField("type").as[Option[String]].ensure(DecodingFailure("Type must not be defined!", c.history))(_.isEmpty) nb <- c.downField("nullable").as[Option[Boolean]] diff --git a/openapi-codegen/core/src/main/scala/sttp/tapir/codegen/openapi/models/OpenapiSecuritySchemeType.scala b/openapi-codegen/core/src/main/scala/sttp/tapir/codegen/openapi/models/OpenapiSecuritySchemeType.scala index a460c9fc58..554936e526 100644 --- a/openapi-codegen/core/src/main/scala/sttp/tapir/codegen/openapi/models/OpenapiSecuritySchemeType.scala +++ b/openapi-codegen/core/src/main/scala/sttp/tapir/codegen/openapi/models/OpenapiSecuritySchemeType.scala @@ -17,7 +17,7 @@ object OpenapiSecuritySchemeType { import io.circe._ import cats.implicits._ - private implicit val BearerTypeDecoder: Decoder[OpenapiSecuritySchemeBearerType.type] = { (c: HCursor) => + private implicit lazy val BearerTypeDecoder: Decoder[OpenapiSecuritySchemeBearerType.type] = { (c: HCursor) => for { _ <- c.get[String]("type").ensure(DecodingFailure("Given type is not http!", c.history))(_ == "http") _ <- c.get[String]("scheme").ensure(DecodingFailure("Given scheme is not bearer!", c.history))(_ == "bearer") @@ -26,7 +26,7 @@ object OpenapiSecuritySchemeType { } } - private implicit val BasicTypeDecoder: Decoder[OpenapiSecuritySchemeBasicType.type] = { (c: HCursor) => + private implicit lazy val BasicTypeDecoder: Decoder[OpenapiSecuritySchemeBasicType.type] = { (c: HCursor) => for { _ <- c.get[String]("type").ensure(DecodingFailure("Given type is not http!", c.history))(_ == "http") _ <- c.get[String]("scheme").ensure(DecodingFailure("Given scheme is not basic!", c.history))(_ == "basic") @@ -37,7 +37,7 @@ object OpenapiSecuritySchemeType { private val ApiKeyInOptions = List("header", "query", "cookie") - private implicit val ApiKeyDecoder: Decoder[OpenapiSecuritySchemeApiKeyType] = { (c: HCursor) => + private implicit lazy val ApiKeyDecoder: Decoder[OpenapiSecuritySchemeApiKeyType] = { (c: HCursor) => for { _ <- c.get[String]("type").ensure(DecodingFailure("Given type is not apiKey!", c.history))(_ == "apiKey") in <- c.get[String]("in").ensure(DecodingFailure("Invalid apiKey in value!", c.history))(ApiKeyInOptions.contains) @@ -47,7 +47,7 @@ object OpenapiSecuritySchemeType { } } - private implicit val OAuth2FlowDecoder: Decoder[OAuth2Flow] = { (c: HCursor) => + private implicit lazy val OAuth2FlowDecoder: Decoder[OAuth2Flow] = { (c: HCursor) => for { a <- c.get[Option[String]]("authorizationUrl") t <- c.get[Option[String]]("tokenUrl") @@ -58,7 +58,7 @@ object OpenapiSecuritySchemeType { } } - private implicit val OpenapiSecuritySchemeOAuth2TypeDecoder: Decoder[OpenapiSecuritySchemeOAuth2Type] = { (c: HCursor) => + private implicit lazy val OpenapiSecuritySchemeOAuth2TypeDecoder: Decoder[OpenapiSecuritySchemeOAuth2Type] = { (c: HCursor) => for { fs <- c .get[JsonObject]("flows") @@ -78,7 +78,7 @@ object OpenapiSecuritySchemeType { } } - implicit val OpenapiSecuritySchemeTypeDecoder: Decoder[OpenapiSecuritySchemeType] = + implicit lazy val OpenapiSecuritySchemeTypeDecoder: Decoder[OpenapiSecuritySchemeType] = List[Decoder[OpenapiSecuritySchemeType]]( Decoder[OpenapiSecuritySchemeBearerType.type].widen, Decoder[OpenapiSecuritySchemeBasicType.type].widen,