diff --git a/build.sbt b/build.sbt index 3045860b..eaf9035b 100644 --- a/build.sbt +++ b/build.sbt @@ -95,7 +95,7 @@ lazy val source = module("source") lazy val parser = module("parser") .settings( libraryDependencies ++= Seq( - "org.typelevel" %% "cats-parse" % "0.3.10", + "org.typelevel" %% "cats-parse" % "1.0.0", "io.circe" %% "circe-generic" % "0.14.6" % Test, "io.circe" %% "circe-parser" % "0.14.6" % Test, "co.fs2" %% "fs2-io" % "3.9.4" % Test, @@ -154,8 +154,8 @@ lazy val lsp = module("lsp") libraryDependencies ++= Seq( "org.eclipse.lsp4j" % "org.eclipse.lsp4j" % "0.21.2", "io.circe" %% "circe-core" % "0.14.6", - "org.http4s" %% "http4s-ember-client" % "0.23.23", - "org.http4s" %% "http4s-ember-server" % "0.23.23" % Test, + "org.http4s" %% "http4s-ember-client" % "0.23.25", + "org.http4s" %% "http4s-ember-server" % "0.23.25" % Test, "io.get-coursier" %% "coursier" % "2.1.9", "org.typelevel" %% "cats-tagless-core" % "0.15.0", ), diff --git a/modules/core/src/main/scala/playground/smithyutil/AddDynamicRefinements.scala b/modules/core/src/main/scala/playground/smithyutil/AddDynamicRefinements.scala index e5817182..a91aecb0 100644 --- a/modules/core/src/main/scala/playground/smithyutil/AddDynamicRefinements.scala +++ b/modules/core/src/main/scala/playground/smithyutil/AddDynamicRefinements.scala @@ -48,6 +48,13 @@ object AddDynamicRefinements extends (Schema ~> Schema) { schema.reifyHint(RefinementProvider.iterableLengthConstraint[IndexedSeq, A]) } + private def enumSchema[A]( + schema: Schema.EnumerationSchema[A] + ): Schema[A] = schema + .reifyHint(RefinementProvider.lengthConstraint(schema.total(_).stringValue.size)) + .reifyHint(RefinementProvider.rangeConstraint[A, Int](schema.total(_).intValue)) + .reifyHint(RefinementProvider.patternConstraint(schema.total(_).stringValue)) + def apply[A]( schema: Schema[A] ): Schema[A] = @@ -69,10 +76,10 @@ object AddDynamicRefinements extends (Schema ~> Schema) { case c: CollectionSchema[_, _] => collection(c) case m: MapSchema[_, _] => m.reifyHint[api.Length] - // explicitly handling each remaining case, in order to get a "mising match" warning if the schema model changes + case e: EnumerationSchema[_] => enumSchema(e) + // explicitly handling each remaining case, in order to get a "missing match" warning if the schema model changes case b: BijectionSchema[_, _] => b case r: RefinementSchema[_, _] => r - case e: EnumerationSchema[_] => e case s: StructSchema[_] => s case l: LazySchema[_] => l case u: UnionSchema[_] => u diff --git a/modules/core/src/test/scala/playground/smithyql/CompilationTests.scala b/modules/core/src/test/scala/playground/smithyql/CompilationTests.scala index 3a1d880a..4a5c9327 100644 --- a/modules/core/src/test/scala/playground/smithyql/CompilationTests.scala +++ b/modules/core/src/test/scala/playground/smithyql/CompilationTests.scala @@ -11,6 +11,7 @@ import com.softwaremill.diffx.Diff import com.softwaremill.diffx.cats._ import demo.smithy.Bad import demo.smithy.DeprecatedServiceGen +import demo.smithy.EnumStruct import demo.smithy.FriendSet import demo.smithy.Good import demo.smithy.HasConstraintFields @@ -732,6 +733,57 @@ object CompilationTests extends SimpleIOSuite with Checkers { ) } + pureTest("enum - length validation (dynamic, OK)") { + assert.same( + Ior.right(Document.obj("enumWithLength" -> Document.fromString("AB"))), + compile( + WithSource.liftId(struct("enumWithLength" -> "AB").mapK(WithSource.liftId)) + )(dynamicSchemaFor[EnumStruct]), + ) + } + + pureTest("enum - length validation (dynamic, fail)") { + assert( + compile( + WithSource.liftId(struct("enumWithLength" -> "ABC").mapK(WithSource.liftId)) + )(dynamicSchemaFor[EnumStruct]).isLeft + ) + } + + pureTest("enum - range validation (dynamic, OK)") { + assert.same( + Ior.right(Document.obj("intEnumWithRange" -> Document.fromInt(2))), + compile( + WithSource.liftId(struct("intEnumWithRange" -> "QUEEN").mapK(WithSource.liftId)) + )(dynamicSchemaFor[EnumStruct]), + ) + } + + pureTest("enum - range validation (dynamic, fail)") { + assert( + compile( + WithSource.liftId(struct("intEnumWithRange" -> "KING").mapK(WithSource.liftId)) + )(dynamicSchemaFor[EnumStruct]).isLeft + ) + } + + pureTest("enum - pattern validation (dynamic, OK)") { + assert.same( + Ior.right(Document.obj("enumWithPattern" -> Document.fromString("AB"))), + compile( + WithSource.liftId(struct("enumWithPattern" -> "AB").mapK(WithSource.liftId)) + )(dynamicSchemaFor[EnumStruct]), + ) + } + + pureTest("enum - pattern validation (dynamic, fail)") { + assert( + compile( + WithSource.liftId(struct("enumWithPattern" -> "ABC").mapK(WithSource.liftId)) + )(dynamicSchemaFor[EnumStruct]).isLeft + ) + } + pureTest("enum - fallback to string value") { implicit val diffPower: Diff[Power] = Diff.derived diff --git a/modules/core/src/test/smithy/demo.smithy b/modules/core/src/test/smithy/demo.smithy index af8c7695..80f04d05 100644 --- a/modules/core/src/test/smithy/demo.smithy +++ b/modules/core/src/test/smithy/demo.smithy @@ -228,6 +228,31 @@ string MyString @length(min: 1) string StringWithLength +structure EnumStruct { + @length(max: 2) + enumWithLength: EnumABC + + @pattern("^.{0,2}$") + enumWithPattern: EnumABC + + @range(max: 2) + intEnumWithRange: FaceCard +} + +enum EnumABC { + A, + AB, + ABC +} + +intEnum FaceCard { + JACK = 1 + QUEEN = 2 + KING = 3 + ACE = 4 + JOKER = 5 +} + structure HasConstraintFields { @required minLength: StringWithLength diff --git a/project/plugins.sbt b/project/plugins.sbt index 43876a26..390e4710 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -4,7 +4,7 @@ addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.11") addSbtPlugin("io.github.davidgregory084" % "sbt-tpolecat" % "0.4.3") // try to keep in sync with smithy-build.json -addSbtPlugin("com.disneystreaming.smithy4s" % "smithy4s-sbt-codegen" % "0.18.0") +addSbtPlugin("com.disneystreaming.smithy4s" % "smithy4s-sbt-codegen" % "0.18.8") addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.11.0") addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "1.1.1") diff --git a/smithy-build.json b/smithy-build.json index 8e5362c8..4a732538 100644 --- a/smithy-build.json +++ b/smithy-build.json @@ -2,7 +2,7 @@ "imports": ["modules/core/src/test/smithy"], "mavenDependencies": [ "com.disneystreaming.alloy:alloy-core:0.2.8", - "com.disneystreaming.smithy4s:smithy4s-protocol:0.18.2", + "com.disneystreaming.smithy4s:smithy4s-protocol:0.18.8", "software.amazon.smithy:smithy-aws-traits:1.45.0" ] }