From b98ad60aa3fb1ebe280a0fba6ec9ad7809c91935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Tue, 29 Oct 2024 01:43:23 +0100 Subject: [PATCH] Migrate to Scala 3 (#349) * WIP: scala 3 * Pass tests * disable mima * Fix extension * fix tests * scalafmt and so on * unused * Use LTS in plugin module * lint * simplify * recover uuid, fix imports * oops * magic trick * just binary is fine * lol --- .github/workflows/ci.yml | 2 +- .scalafmt.conf | 12 +- build.sbt | 45 +++- .../main/scala/playground/smithyql/AST.scala | 5 +- .../main/scala/playground/smithyql/DSL.scala | 4 +- .../scala/playground/CompilationError.scala | 4 +- .../playground/DynamicServiceProxy.scala | 4 +- .../main/scala/playground/FileCompiler.scala | 1 - .../main/scala/playground/FileRunner.scala | 1 - .../scala/playground/NodeEncoderVisitor.scala | 4 +- .../scala/playground/OperationCompiler.scala | 24 +- .../scala/playground/OperationRunner.scala | 5 +- .../scala/playground/PlaygroundConfig.scala | 5 +- .../playground/QueryCompilerVisitor.scala | 8 +- .../playground/smithyql/RangeIndex.scala | 38 ++-- .../smithyutil/AddDynamicRefinements.scala | 48 ++-- .../scala/playground/std/StdlibRuntime.scala | 8 +- modules/core/src/main/smithy/std.smithy | 8 +- .../src/test/scala/playground/Diffs.scala | 32 ++- .../MultiServiceResolverTests.scala | 4 +- .../playground/PreludeCompilerTests.scala | 2 +- .../playground/smithyql/AtPositionTests.scala | 2 +- .../smithyql/CompilationTests.scala | 206 +++++++++++++----- .../test/scala/playground/e2e/E2ETests.scala | 5 +- .../smithyql/format/FormattingTests.scala | 2 +- .../playground/language/CommandProvider.scala | 48 ++-- .../language/CompletionVisitor.scala | 20 +- .../language/CodeLensProviderTests.scala | 2 +- .../language/CompletionItemTests.scala | 2 +- .../language/CompletionProviderTests.scala | 2 +- .../playground/language/CompletionTests.scala | 4 +- .../language/DiagnosticProviderTests.scala | 2 +- .../scala/playground/language/Diffs.scala | 13 +- .../DocumentSymbolProviderTests.scala | 2 +- .../scala/playground/lsp/ModelLoader.scala | 26 +-- .../lsp/PlaygroundLanguageServerAdapter.scala | 12 +- ...ageServerIntegrationTestSharedServer.scala | 30 +-- .../LanguageServerIntegrationTests.scala | 53 ++++- .../playground/lsp/harness/TestClient.scala | 9 +- .../playground/smithyql/parser/Parsers.scala | 2 +- .../smithyql/parser/v2/scanner.scala | 6 +- .../playground/smithyql/parser/Codecs.scala | 54 ++++- .../playground/smithyql/parser/Diffs.scala | 6 +- .../smithyql/parser/ParserSuite.scala | 2 +- .../parser/generative/ListParserTests.scala | 5 +- .../generative/PreludeParserTests.scala | 4 +- .../parser/generative/QueryParserTests.scala | 4 +- .../generative/SourceFileParserTests.scala | 4 +- .../parser/generative/StructParserTests.scala | 4 +- .../generative/UseServiceParserTests.scala | 4 +- .../smithyql/parser/v2/ScannerSuite.scala | 2 +- .../smithyql/parser/v2/ScannerTests.scala | 6 +- .../smithyql/StringRangeUtils.scala | 3 - .../playground/smithyql/WithSource.scala | 4 +- .../scala/playground/smithyql/Diffs.scala | 39 +++- project/build.properties | 2 +- vscode-extension/package.json | 2 +- vscode-extension/project/build.properties | 1 - 58 files changed, 553 insertions(+), 305 deletions(-) delete mode 100644 vscode-extension/project/build.properties diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 41241bbc..b36d33f9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: build: name: "Build" runs-on: ubuntu-20.04 - timeout-minutes: 30 + timeout-minutes: 10 steps: - uses: actions/checkout@v4.1.1 diff --git a/.scalafmt.conf b/.scalafmt.conf index f10b5579..2a7079ed 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,5 +1,9 @@ -runner.dialect=scala213source3 -version = 3.7.2 +version = 3.8.3 + +runner.dialect=scala3 +runner.dialectOverride.allowSignificantIndentation = false +runner.dialectOverride.allowQuietSyntax = true + maxColumn = 100 align.preset = some @@ -17,6 +21,10 @@ assumeStandardLibraryStripMargin = true trailingCommas = "multiple" +project { + git = true +} + rewrite.rules = [ RedundantBraces, RedundantParens, diff --git a/build.sbt b/build.sbt index 76b0abb4..59df191b 100644 --- a/build.sbt +++ b/build.sbt @@ -14,6 +14,12 @@ inThisBuild( ) ) +val ScalaLTS = "3.3.4" +val ScalaNext = "3.5.2" + +ThisBuild / scalaVersion := ScalaNext +ThisBuild / versionScheme := Some("early-semver") + import scala.sys.process.* def crossPlugin( @@ -30,13 +36,6 @@ val compilerPlugins = crossPlugin("org.typelevel" % "kind-projector" % "0.13.3") )) -ThisBuild / versionScheme := Some("early-semver") - -Global / onChangedBuildSource := ReloadOnSourceChanges - -ThisBuild / scalaVersion := "2.13.15" -ThisBuild / crossScalaVersions := Seq("2.13.15") - // For coursier's "latest.integration" ThisBuild / dynverSeparator := "-" @@ -54,8 +53,25 @@ val commonSettings = Seq( compilerPlugins, scalacOptions -= "-Xfatal-warnings", scalacOptions -= "-Vtype-diffs", - scalacOptions += "-Wnonunit-statement", - scalacOptions ++= Seq("-Xsource:3.0"), + scalacOptions -= "-language:existentials", + // https://github.com/lampepfl/dotty/issues/18674 + Test / scalacOptions -= "-Wunused:implicits", + Test / scalacOptions -= "-Wunused:explicits", + Test / scalacOptions -= "-Wunused:imports", + Test / scalacOptions -= "-Wunused:locals", + Test / scalacOptions -= "-Wunused:params", + Test / scalacOptions -= "-Wunused:privates", + // + scalacOptions += "-no-indent", + scalacOptions ++= { + if (scalaVersion.value.startsWith("3.5")) + Seq( + // for cats-tagless macros + "-experimental" + ) + else + Nil + }, Test / scalacOptions += "-Wconf:cat=deprecation:silent,msg=Specify both message and version:silent", scalacOptions ++= Seq("-release", "11"), mimaFailOnNoPrevious := false, @@ -73,8 +89,9 @@ lazy val pluginCore = module("plugin-core").settings( libraryDependencies ++= Seq( "com.disneystreaming.smithy4s" %% "smithy4s-http4s" % smithy4sVersion.value ), - // mimaPreviousArtifacts := Set(organization.value %% name.value % "0.3.0"), + // mimaPreviousArtifacts := Set(organization.value %% name.value % "0.7.0"), mimaPreviousArtifacts := Set.empty, + scalaVersion := ScalaLTS, ) lazy val pluginSample = module("plugin-sample") @@ -133,6 +150,7 @@ lazy val core = module("core") "com.disneystreaming.alloy" % "alloy-core" % "0.3.14" % Test, "software.amazon.smithy" % "smithy-aws-traits" % "1.52.1" % Test, ), + // todo: move this to a separate module like "examples" Smithy4sCodegenPlugin.defaultSettings(Test), ) .enablePlugins(Smithy4sCodegenPlugin) @@ -156,8 +174,11 @@ lazy val lsp = module("lsp") "io.circe" %% "circe-core" % "0.14.10", "org.http4s" %% "http4s-ember-client" % "0.23.29", "org.http4s" %% "http4s-ember-server" % "0.23.29" % Test, - "io.get-coursier" %% "coursier" % "2.1.14", - "org.typelevel" %% "cats-tagless-macros" % "0.16.2", + ("io.get-coursier" % "coursier" % "2.1.14") + .cross(CrossVersion.for3Use2_13) + .exclude("org.scala-lang.modules", "scala-collection-compat_2.13") + .exclude("com.github.plokhotnyuk.jsoniter-scala", "jsoniter-scala-core_2.13"), + "org.typelevel" %% "cats-tagless-core" % "0.16.2", ), buildInfoPackage := "playground.lsp.buildinfo", buildInfoKeys ++= Seq(version, scalaBinaryVersion), diff --git a/modules/ast/src/main/scala/playground/smithyql/AST.scala b/modules/ast/src/main/scala/playground/smithyql/AST.scala index 2b44037c..a542a1c7 100644 --- a/modules/ast/src/main/scala/playground/smithyql/AST.scala +++ b/modules/ast/src/main/scala/playground/smithyql/AST.scala @@ -166,8 +166,7 @@ object QualifiedIdentifier { implicit val show: Show[QualifiedIdentifier] = Show.fromToString - implicit val ord: Order[QualifiedIdentifier] = Order.by(unapply(_).get) - + implicit val ord: Order[QualifiedIdentifier] = Order.by(Tuple.fromProductTyped) } // the keywords of the clause are captured in the Prelude's useClauses list. @@ -240,7 +239,7 @@ final case class Binding[F[_]]( final case class Identifier( text: String -) extends AnyVal +) object Struct { diff --git a/modules/ast/src/main/scala/playground/smithyql/DSL.scala b/modules/ast/src/main/scala/playground/smithyql/DSL.scala index 85e62adb..0c6fa6e5 100644 --- a/modules/ast/src/main/scala/playground/smithyql/DSL.scala +++ b/modules/ast/src/main/scala/playground/smithyql/DSL.scala @@ -6,7 +6,7 @@ import cats.syntax.all.* object DSL { implicit class StringDSLOps( - val s: String + private val s: String ) extends AnyVal { def call( @@ -16,7 +16,7 @@ object DSL { )* ): Query[Id] = Query[Id]( operationName = QueryOperationName[Id](None, OperationName(s)), - input = struct(args: _*), + input = struct(args*), ) } diff --git a/modules/core/src/main/scala/playground/CompilationError.scala b/modules/core/src/main/scala/playground/CompilationError.scala index b8b44acf..f83391a9 100644 --- a/modules/core/src/main/scala/playground/CompilationError.scala +++ b/modules/core/src/main/scala/playground/CompilationError.scala @@ -111,8 +111,8 @@ sealed trait CompilationErrorDetails extends Product with Serializable { s"""Matching enums by value is deprecated and may be removed in the future. Use $enumName instead.""".stripMargin case DuplicateItem => "Duplicate item - some entries will be dropped to fit in a set shape." case AmbiguousService(workspaceServices) => - s"""Couldn't determine service for this operation. Add a use clause, or use an explicit reference to specify the service you want to use. - |Available services:""".stripMargin + workspaceServices + """Couldn't determine service for this operation. Add a use clause, or use an explicit reference to specify the service you want to use. + |Available services:""".stripMargin + workspaceServices .sorted .map(UseClause[Id](_).mapK(WithSource.liftId)) .map(Formatter.useClauseFormatter.format(_, Int.MaxValue)) diff --git a/modules/core/src/main/scala/playground/DynamicServiceProxy.scala b/modules/core/src/main/scala/playground/DynamicServiceProxy.scala index 1f677484..5f7b24fd 100644 --- a/modules/core/src/main/scala/playground/DynamicServiceProxy.scala +++ b/modules/core/src/main/scala/playground/DynamicServiceProxy.scala @@ -26,8 +26,6 @@ class DynamicServiceProxy[Alg[_[_, _, _, _, _]], Op[_, _, _, _, _]]( ): FunctorInterpreter[Op, F] = { val grp = serviceStatic.endpoints.groupBy(_.id).fmap(_.head) - type Proxy[I, E, O, SE, EO] = I => F[O] - def makeProxy[A, B]( schemaIn: Schema[A], schemaOut: Schema[B], @@ -39,7 +37,7 @@ class DynamicServiceProxy[Alg[_[_, _, _, _, _]], Op[_, _, _, _, _]]( } val endpointMapping = - new smithy4s.kinds.PolyFunction5[Endpoint[Op, *, *, *, *, *], Proxy] { + new service.FunctorEndpointCompiler[F] { private val trans = serviceStatic.toPolyFunction(interp) private def applyWithStatic[I, E, O, SI, SO, STI, STE, STO, STSI, STSO]( diff --git a/modules/core/src/main/scala/playground/FileCompiler.scala b/modules/core/src/main/scala/playground/FileCompiler.scala index d79a7529..d800b60b 100644 --- a/modules/core/src/main/scala/playground/FileCompiler.scala +++ b/modules/core/src/main/scala/playground/FileCompiler.scala @@ -3,7 +3,6 @@ package playground import cats.Parallel import cats.syntax.all.* import cats.~> -import playground.* import playground.smithyql.SourceFile import playground.smithyql.WithSource diff --git a/modules/core/src/main/scala/playground/FileRunner.scala b/modules/core/src/main/scala/playground/FileRunner.scala index a118273b..991ab6e2 100644 --- a/modules/core/src/main/scala/playground/FileRunner.scala +++ b/modules/core/src/main/scala/playground/FileRunner.scala @@ -2,7 +2,6 @@ package playground import cats.data.NonEmptyList import cats.syntax.all.* -import playground.* import playground.smithyql.SourceFile import playground.smithyql.SourceRange import playground.smithyql.WithSource diff --git a/modules/core/src/main/scala/playground/NodeEncoderVisitor.scala b/modules/core/src/main/scala/playground/NodeEncoderVisitor.scala index 7eefdd8c..691ddaf1 100644 --- a/modules/core/src/main/scala/playground/NodeEncoderVisitor.scala +++ b/modules/core/src/main/scala/playground/NodeEncoderVisitor.scala @@ -169,7 +169,7 @@ object NodeEncoderVisitor extends SchemaVisitor[NodeEncoder] { self => def struct[S]( shapeId: ShapeId, hints: Hints, - fieldsRaw: Vector[Field[S, _]], + fieldsRaw: Vector[Field[S, ?]], make: IndexedSeq[Any] => S, ): NodeEncoder[S] = { @@ -192,7 +192,7 @@ object NodeEncoderVisitor extends SchemaVisitor[NodeEncoder] { self => def union[U]( shapeId: ShapeId, hints: Hints, - alternatives: Vector[Alt[U, _]], + alternatives: Vector[Alt[U, ?]], dispatcher: Alt.Dispatcher[U], ): NodeEncoder[U] = dispatcher.compile(new Alt.Precompiler[NodeEncoder] { diff --git a/modules/core/src/main/scala/playground/OperationCompiler.scala b/modules/core/src/main/scala/playground/OperationCompiler.scala index 38079273..664f9c6e 100644 --- a/modules/core/src/main/scala/playground/OperationCompiler.scala +++ b/modules/core/src/main/scala/playground/OperationCompiler.scala @@ -14,6 +14,7 @@ import playground.smithyql.Query import playground.smithyql.WithSource import smithy.api import smithy4s.Endpoint +import smithy4s.Hints import smithy4s.Service import smithy4s.dynamic.DynamicSchemaIndex import smithyql.syntax.* @@ -22,12 +23,15 @@ import util.chaining.* trait CompiledInput { type _Op[_, _, _, _, _] + type I type E type O + type SI + type SO def catchError: Throwable => Option[E] def writeError: Option[NodeEncoder[E]] def writeOutput: NodeEncoder[O] - def op: _Op[_, E, O, _, _] + def op: _Op[I, E, O, SI, SO] } object CompiledInput { @@ -149,8 +153,8 @@ private class ServiceCompiler[Alg[_[_, _, _, _, _]]]( service: Service[Alg] ) extends OperationCompiler[IorNel[CompilationError, *]] { - private def compileEndpoint[In, Err, Out]( - e: Endpoint[service.Operation, In, Err, Out, _, _] + private def compileEndpoint[In, Err, Out, SIn, SOut]( + e: Endpoint[service.Operation, In, Err, Out, SIn, SOut] ): QueryCompiler[CompiledInput] = { val inputCompiler = e.input.compile(QueryCompilerVisitor.full) val outputEncoder = NodeEncoder.derive(e.output) @@ -162,10 +166,13 @@ private class ServiceCompiler[Alg[_[_, _, _, _, _]]]( .map { compiled => new CompiledInput { type _Op[_I, _E, _O, _SE, _SO] = service.Operation[_I, _E, _O, _SE, _SO] + type I = In type E = Err type O = Out + type SI = SIn + type SO = SOut - val op: _Op[_, Err, Out, _, _] = e.wrap(compiled) + val op: _Op[I, E, O, SI, SO] = e.wrap(compiled) val writeOutput: NodeEncoder[Out] = outputEncoder val writeError: Option[NodeEncoder[Err]] = errorEncoder val catchError: Throwable => Option[Err] = e.Error.unapply(_).map(_._2) @@ -174,12 +181,12 @@ private class ServiceCompiler[Alg[_[_, _, _, _, _]]]( } // https://github.com/kubukoz/smithy-playground/issues/154 - // map of endpoint names to (endpoint, input compiler) + // map of endpoint names to (endpoint hints, input compiler) private val endpoints = service .endpoints .toList .groupByNel(_.name) - .map(_.map(_.head).map(e => (e, compileEndpoint(e)))) + .map(_.map(_.head).map(e => (e.hints, compileEndpoint(e)))) // Checks the explicit service reference (if any). // Note that the reference should be valid thanks to MultiServiceResolver's checks. @@ -201,10 +208,9 @@ private class ServiceCompiler[Alg[_[_, _, _, _, _]]]( private def deprecatedOperationCheck( q: Query[WithSource], - endpoint: Endpoint[service.Operation, _, _, _, _, _], + endpointHints: Hints, ): IorNel[CompilationError, Unit] = - endpoint - .hints + endpointHints .get(api.Deprecated) .map { info => CompilationError.deprecation( diff --git a/modules/core/src/main/scala/playground/OperationRunner.scala b/modules/core/src/main/scala/playground/OperationRunner.scala index 32e0beb3..f7b79102 100644 --- a/modules/core/src/main/scala/playground/OperationRunner.scala +++ b/modules/core/src/main/scala/playground/OperationRunner.scala @@ -19,7 +19,6 @@ import cats.syntax.all.* import fs2.compression.Compression import org.http4s.Uri import org.http4s.client.Client -import playground.* import playground.plugins.PlaygroundPlugin import playground.plugins.SimpleHttpBuilder import playground.smithyql.InputNode @@ -157,7 +156,7 @@ object OperationRunner { def forServices[F[_]: StdlibRuntime: Async: Compression: std.Console]( services: List[DynamicSchemaIndex.ServiceWrapper], - getSchema: ShapeId => Option[Schema[_]], + getSchema: ShapeId => Option[Schema[?]], client: Client[F], baseUri: F[Uri], awsEnv: Resource[F, AwsEnvironment[F]], @@ -204,7 +203,7 @@ object OperationRunner { client: Client[F], baseUri: F[Uri], awsEnv: Resource[F, AwsEnvironment[F]], - schemaIndex: ShapeId => Option[Schema[_]], + schemaIndex: ShapeId => Option[Schema[?]], plugins: List[PlaygroundPlugin], ): Resolver[F] = new Resolver[F] { diff --git a/modules/core/src/main/scala/playground/PlaygroundConfig.scala b/modules/core/src/main/scala/playground/PlaygroundConfig.scala index cae84fe6..28d1037a 100644 --- a/modules/core/src/main/scala/playground/PlaygroundConfig.scala +++ b/modules/core/src/main/scala/playground/PlaygroundConfig.scala @@ -2,7 +2,6 @@ package playground import cats.kernel.Eq import cats.syntax.all.* -import com.github.plokhotnyuk.jsoniter_scala.core.JsonValueCodec import com.github.plokhotnyuk.jsoniter_scala.macros.JsonCodecMaker final case class PlaygroundConfig( @@ -47,7 +46,9 @@ object PlaygroundConfig { } object BuildConfig { - implicit val c: JsonValueCodec[BuildConfig] = JsonCodecMaker.make + // note: this is flagged as an unused import if imported + implicit val c: com.github.plokhotnyuk.jsoniter_scala.core.JsonValueCodec[BuildConfig] = + JsonCodecMaker.make def fromPlaygroundConfig( c: PlaygroundConfig diff --git a/modules/core/src/main/scala/playground/QueryCompilerVisitor.scala b/modules/core/src/main/scala/playground/QueryCompilerVisitor.scala index d51f811d..b31b9534 100644 --- a/modules/core/src/main/scala/playground/QueryCompilerVisitor.scala +++ b/modules/core/src/main/scala/playground/QueryCompilerVisitor.scala @@ -219,7 +219,7 @@ object QueryCompilerVisitorInternal extends SchemaVisitor[QueryCompiler] { private object FieldCompiler { def compile[A]( - field: Field[_, A] + field: Field[?, A] ): FieldCompiler[A] = new FieldCompiler[A] { override val compiler: QueryCompiler[A] = field.schema.compile(QueryCompilerVisitorInternal) @@ -233,7 +233,7 @@ object QueryCompilerVisitorInternal extends SchemaVisitor[QueryCompiler] { def struct[S]( shapeId: ShapeId, hints: Hints, - fieldsRaw: Vector[Field[S, _]], + fieldsRaw: Vector[Field[S, ?]], make: IndexedSeq[Any] => S, ): QueryCompiler[S] = { val fields = fieldsRaw @@ -318,7 +318,7 @@ object QueryCompilerVisitorInternal extends SchemaVisitor[QueryCompiler] { def union[U]( shapeId: ShapeId, hints: Hints, - alternatives: Vector[Alt[U, _]], + alternatives: Vector[Alt[U, ?]], dispatcher: Alt.Dispatcher[U], ): QueryCompiler[U] = { def handleAlt[A]( @@ -445,7 +445,7 @@ object QueryCompilerVisitorInternal extends SchemaVisitor[QueryCompiler] { .parTraverse { binding => document.compile(binding.value).tupleLeft(binding.identifier.value.text) } - .map(Document.obj(_: _*)) + .map(Document.obj(_*)) case NullLiteral() => Document.nullDoc.rightIor } diff --git a/modules/core/src/main/scala/playground/smithyql/RangeIndex.scala b/modules/core/src/main/scala/playground/smithyql/RangeIndex.scala index b5401827..e651290c 100644 --- a/modules/core/src/main/scala/playground/smithyql/RangeIndex.scala +++ b/modules/core/src/main/scala/playground/smithyql/RangeIndex.scala @@ -111,15 +111,14 @@ object RangeIndex { .fold( listed = l => entireNode(ctx) :: findInList(l, ctx), struct = s => entireNode(ctx) :: findInStruct(s, ctx.inStructBody), - string = - _ => { - val inQuotes = ContextRange( - node.range.shrink1, - ctx.inQuotes, - ) - - inQuotes :: entireNode(ctx) :: Nil - }, + string = { _ => + val inQuotes = ContextRange( + node.range.shrink1, + ctx.inQuotes, + ) + + inQuotes :: entireNode(ctx) :: Nil + }, int = default, bool = default, nul = default, @@ -150,19 +149,18 @@ object RangeIndex { private def findInStruct( struct: Struct[WithSource], ctx: NodeContext, - ): List[ContextRange] = + ): List[ContextRange] = { // Struct fields that allow nesting in them - { - val inFields = struct - .fields - .value - .value - .flatMap { binding => - findInNode(binding.value, ctx.inStructValue(binding.identifier.value.text)) - } + val inFields = struct + .fields + .value + .value + .flatMap { binding => + findInNode(binding.value, ctx.inStructValue(binding.identifier.value.text)) + } - ContextRange(struct.fields.range, ctx) :: inFields - } + ContextRange(struct.fields.range, ctx) :: inFields + } } diff --git a/modules/core/src/main/scala/playground/smithyutil/AddDynamicRefinements.scala b/modules/core/src/main/scala/playground/smithyutil/AddDynamicRefinements.scala index cec0ab98..6b59b234 100644 --- a/modules/core/src/main/scala/playground/smithyutil/AddDynamicRefinements.scala +++ b/modules/core/src/main/scala/playground/smithyutil/AddDynamicRefinements.scala @@ -2,6 +2,7 @@ package playground.smithyutil import cats.syntax.all.* import smithy.api +import smithy.api.Length import smithy4s.Refinement import smithy4s.RefinementProvider import smithy4s.Surjection @@ -10,6 +11,8 @@ import smithy4s.schema.Schema import smithy4s.schema.Schema.* import smithy4s.~> +import RefinementProvider.given + /** Reifies refinement hints into the schema. * * Notably, this does NOT recurse! In order to traverse an entire schema recursively, this has to @@ -18,7 +21,7 @@ import smithy4s.~> object AddDynamicRefinements extends (Schema ~> Schema) { private def void[C, A]( - underlying: RefinementProvider[C, A, _] + underlying: RefinementProvider[C, A, ?] ): RefinementProvider.Simple[C, A] = Refinement .drivenBy[C] @@ -31,7 +34,7 @@ object AddDynamicRefinements extends (Schema ~> Schema) { ) { def reifyHint[B]( - implicit rp: RefinementProvider[B, A, _] + using rp: RefinementProvider.Simple[B, A] ): Schema[A] = schema.hints.get(rp.tag).fold(schema)(schema.validated(_)(void(rp))) } @@ -39,36 +42,45 @@ object AddDynamicRefinements extends (Schema ~> Schema) { private def collection[C[_], A]( schema: Schema.CollectionSchema[C, A] ): Schema[C[A]] = schema.reifyHint( - RefinementProvider.lengthConstraint(schema.tag.iterator(_).size) + using RefinementProvider.lengthConstraint(schema.tag.iterator(_).size) ) 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)) + .reifyHint[Length]( + using RefinementProvider.lengthConstraint(schema.total(_).stringValue.size) + ) + .reifyHint( + using RefinementProvider.rangeConstraint[A, Int](schema.total(_).intValue) + ) + .reifyHint( + using RefinementProvider.patternConstraint(schema.total(_).stringValue) + ) def apply[A]( schema: Schema[A] ): Schema[A] = schema match { - case PrimitiveSchema(_, _, tag) => - tag match { - case PString => schema.reifyHint[api.Length].reifyHint[api.Pattern] - case PByte => schema.reifyHint[api.Range] - case PShort => schema.reifyHint[api.Range] - case PInt => schema.reifyHint[api.Range] - case PLong => schema.reifyHint[api.Range] - case PFloat => schema.reifyHint[api.Range] - case PDouble => schema.reifyHint[api.Range] - case PBigInt => schema.reifyHint[api.Range] - case PBigDecimal => schema.reifyHint[api.Range] + case p: PrimitiveSchema[?] => + p.tag match { + case PString => + schema + .reifyHint[api.Length] + .reifyHint[api.Pattern] + case PByte => (schema: Schema[Byte]).reifyHint[api.Range] + case PShort => (schema: Schema[Short]).reifyHint[api.Range] + case PInt => (schema: Schema[Int]).reifyHint[api.Range] + case PLong => (schema: Schema[Long]).reifyHint[api.Range] + case PFloat => (schema: Schema[Float]).reifyHint[api.Range] + case PDouble => (schema: Schema[Double]).reifyHint[api.Range] + case PBigInt => (schema: Schema[BigInt]).reifyHint[api.Range] + case PBigDecimal => (schema: Schema[BigDecimal]).reifyHint[api.Range] case PBlob => schema.reifyHint[api.Length] case PTimestamp | PDocument | PBoolean | PUUID => schema } - case c: CollectionSchema[_, _] => collection(c) + case c: CollectionSchema[a, f] => collection[a, f](c) case m: MapSchema[_, _] => m.reifyHint[api.Length] case e: EnumerationSchema[_] => enumSchema(e) // explicitly handling each remaining case, in order to get a "missing match" warning if the schema model changes diff --git a/modules/core/src/main/scala/playground/std/StdlibRuntime.scala b/modules/core/src/main/scala/playground/std/StdlibRuntime.scala index 6e1c59eb..e01f11a2 100644 --- a/modules/core/src/main/scala/playground/std/StdlibRuntime.scala +++ b/modules/core/src/main/scala/playground/std/StdlibRuntime.scala @@ -21,8 +21,14 @@ object StdlibRuntime { val random: Random[F] = new playground.std.Random[F] { + def nextUUID( - ): F[NextUUIDOutput] = UUIDGen[F].randomUUID.map(_.toString).map(NextUUIDOutput(_)) + ): F[NextUUIDOutput] = UUIDGen[F] + .randomUUID + .map(_.toString()) + .map(UUID(_)) + .map(NextUUIDOutput(_)) + } val clock: Clock[F] = diff --git a/modules/core/src/main/smithy/std.smithy b/modules/core/src/main/smithy/std.smithy index fdcc425c..59a721de 100644 --- a/modules/core/src/main/smithy/std.smithy +++ b/modules/core/src/main/smithy/std.smithy @@ -11,7 +11,9 @@ string UUID @stdlib @documentation("A standard library service providing random generators of data.") service Random { - operations: [NextUUID] + operations: [ + NextUUID + ] } @documentation("Generates a new UUID.") @@ -25,7 +27,9 @@ operation NextUUID { @stdlib @documentation("A standard library service providing time operations.") service Clock { - operations: [CurrentTimestamp] + operations: [ + CurrentTimestamp + ] } @documentation("Provides the current time as a Timestamp.") diff --git a/modules/core/src/test/scala/playground/Diffs.scala b/modules/core/src/test/scala/playground/Diffs.scala index 0cee1a04..361795f7 100644 --- a/modules/core/src/test/scala/playground/Diffs.scala +++ b/modules/core/src/test/scala/playground/Diffs.scala @@ -2,29 +2,41 @@ package playground import cats.data.Ior import playground.smithyql.ContextRange +import playground.smithyql.Diffs.given import playground.smithyql.NodeContext +import smithy.api.TimestampFormat import smithy4s.Blob +import smithy4s.ShapeId + +import scala.annotation.nowarn object Diffs { import com.softwaremill.diffx.* import com.softwaremill.diffx.cats.* - import com.softwaremill.diffx.generic.auto.* - implicit val diffNodeContext: Diff[NodeContext] = Diff.derivedDiff - implicit val diffContextRange: Diff[ContextRange] = Diff.derivedDiff - implicit val diffDiagnosticDetails: Diff[CompilationErrorDetails] = Diff.derivedDiff - implicit val diffDiagnostic: Diff[CompilationError] = Diff.derivedDiff + given Diff[ShapeId] = Diff.derived + + given Diff[NodeContext.PathEntry] = Diff.derived + given Diff[NodeContext] = Diff[List[NodeContext.PathEntry]].contramap(_.toList) + given Diff[ContextRange] = Diff.derived + given Diff[TimestampFormat] = Diff.derived + given Diff[DiagnosticTag] = Diff.derived + given Diff[DiagnosticSeverity] = Diff.derived + given Diff[DeprecatedInfo] = Diff.derived + given Diff[CompilationErrorDetails] = Diff.derived + given Diff[CompilationError] = Diff.derived - implicit val diffUnit: Diff[Unit] = + given Diff[Unit] = ( _, _, _, ) => IdenticalValue("unit") - implicit def diffForIor[E: Diff, A: Diff]: Diff[Ior[E, A]] = Diff.derivedDiff + @nowarn("msg=unused") + given [E: Diff, A: Diff]: Diff[Ior[E, A]] = Diff.derived - implicit val diffByteArray: Diff[Blob] = Diff[String].contramap(_.toString()) - implicit val diffDocument: Diff[smithy4s.Document] = Diff.derivedDiff - implicit val diffTimestamp: Diff[smithy4s.Timestamp] = Diff[String].contramap(_.toString()) + given Diff[Blob] = Diff[String].contramap(_.toUTF8String) + given Diff[smithy4s.Document] = Diff.derived + given Diff[smithy4s.Timestamp] = Diff[String].contramap(_.toString()) } diff --git a/modules/core/src/test/scala/playground/MultiServiceResolverTests.scala b/modules/core/src/test/scala/playground/MultiServiceResolverTests.scala index 9a04749a..84fc8997 100644 --- a/modules/core/src/test/scala/playground/MultiServiceResolverTests.scala +++ b/modules/core/src/test/scala/playground/MultiServiceResolverTests.scala @@ -3,8 +3,8 @@ package playground import cats.Id import cats.syntax.all.* import com.softwaremill.diffx.cats.* -import playground.Diffs.* -import playground.smithyql.Diffs.* +import playground.Diffs.given +import playground.smithyql.Diffs.given import playground.smithyql.OperationName import playground.smithyql.Prelude import playground.smithyql.QualifiedIdentifier diff --git a/modules/core/src/test/scala/playground/PreludeCompilerTests.scala b/modules/core/src/test/scala/playground/PreludeCompilerTests.scala index afc03679..1acfc46d 100644 --- a/modules/core/src/test/scala/playground/PreludeCompilerTests.scala +++ b/modules/core/src/test/scala/playground/PreludeCompilerTests.scala @@ -14,7 +14,7 @@ import playground.smithyql.parser.SourceParser import weaver.* import Assertions.* -import Diffs.* +import Diffs.given object PreludeCompilerTests extends FunSuite { diff --git a/modules/core/src/test/scala/playground/smithyql/AtPositionTests.scala b/modules/core/src/test/scala/playground/smithyql/AtPositionTests.scala index ae77eb49..1c335c7d 100644 --- a/modules/core/src/test/scala/playground/smithyql/AtPositionTests.scala +++ b/modules/core/src/test/scala/playground/smithyql/AtPositionTests.scala @@ -1,7 +1,7 @@ package playground.smithyql import playground.Assertions.* -import playground.Diffs.* +import playground.Diffs.given import playground.smithyql.parser.SourceParser import weaver.* diff --git a/modules/core/src/test/scala/playground/smithyql/CompilationTests.scala b/modules/core/src/test/scala/playground/smithyql/CompilationTests.scala index 32842f3a..df270c1b 100644 --- a/modules/core/src/test/scala/playground/smithyql/CompilationTests.scala +++ b/modules/core/src/test/scala/playground/smithyql/CompilationTests.scala @@ -35,7 +35,7 @@ import playground.CompiledInput import playground.DeprecatedInfo import playground.DiagnosticSeverity import playground.DiagnosticTag -import playground.Diffs.* +import playground.Diffs.given import playground.DynamicModel import playground.OperationCompiler import playground.PreludeCompiler @@ -154,7 +154,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile { WithSource.liftId(struct().mapK(WithSource.liftId)) - }(Schema.unit).isRight + }( + using Schema.unit + ).isRight ) } @@ -162,7 +164,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile { WithSource.liftId("test".mapK(WithSource.liftId)) - }(Schema.unit).isLeft + }( + using Schema.unit + ).isLeft ) } @@ -170,7 +174,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile { WithSource.liftId(struct("test" -> 42).mapK(WithSource.liftId)) - }(Schema.unit).isBoth + }( + using Schema.unit + ).isBoth ) } @@ -178,7 +184,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile { WithSource.liftId("foo".mapK(WithSource.liftId)) - }(Schema.string) == Ior.right("foo") + }( + using Schema.string + ) == Ior.right("foo") ) } @@ -195,7 +203,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { val result = compile { WithSource.liftId("".mapK(WithSource.liftId)) - }(dynamicStringSchema) + }( + using dynamicStringSchema + ) .leftMap(_.map(_.err.asInstanceOf[CompilationErrorDetails.RefinementFailure])) assert( @@ -208,7 +218,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { val result = compile { WithSource.liftId(struct("minLength" -> "").mapK(WithSource.liftId)) - }(dynamicStringSchema) + }( + using dynamicStringSchema + ) .leftMap(_.map(_.err.asInstanceOf[CompilationErrorDetails.RefinementFailure])) assert( @@ -220,7 +232,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile { WithSource.liftId(42.mapK(WithSource.liftId)) - }(Schema.string) == Ior.left( + }( + using Schema.string + ) == Ior.left( NonEmptyChain.of( CompilationError.error( CompilationErrorDetails.TypeMismatch( @@ -238,7 +252,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId(Long.MaxValue.mapK(WithSource.liftId)) - }(Schema.long), + }( + using Schema.long + ), Ior.right(Long.MaxValue), ) } @@ -247,7 +263,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile { WithSource.liftId((BigInt(Long.MaxValue) + 1).mapK(WithSource.liftId)) - }(Schema.long).isLeft + }( + using Schema.long + ).isLeft ) } @@ -255,7 +273,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId(42.mapK(WithSource.liftId)) - }(Schema.int), + }( + using Schema.int + ), Ior.right(42), ) } @@ -264,7 +284,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile { WithSource.liftId((Int.MaxValue.toLong + 1L).mapK(WithSource.liftId)) - }(Schema.int).isLeft + }( + using Schema.int + ).isLeft ) } @@ -272,7 +294,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId(IntLiteral("1e2").mapK(WithSource.liftId)) - }(Schema.int), + }( + using Schema.int + ), Ior.right(100), ) } @@ -281,7 +305,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile { WithSource.liftId(IntLiteral("10.1e0").mapK(WithSource.liftId)) - }(Schema.int).isLeft + }( + using Schema.int + ).isLeft ) } @@ -289,7 +315,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId(42.mapK(WithSource.liftId)) - }(Schema.short), + }( + using Schema.short + ), Ior.right(42.toShort), ) } @@ -298,7 +326,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile { WithSource.liftId((Short.MaxValue + 1).mapK(WithSource.liftId)) - }(Schema.short).isLeft + }( + using Schema.short + ).isLeft ) } @@ -306,7 +336,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId(IntLiteral("1e2").mapK(WithSource.liftId)) - }(Schema.short), + }( + using Schema.short + ), Ior.right(100.toShort), ) } @@ -315,7 +347,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId(Byte.MaxValue.mapK(WithSource.liftId)) - }(Schema.byte), + }( + using Schema.byte + ), Ior.right(127.toByte), ) } @@ -324,7 +358,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile { WithSource.liftId((Byte.MaxValue + 1).mapK(WithSource.liftId)) - }(Schema.byte).isLeft + }( + using Schema.byte + ).isLeft ) } @@ -332,7 +368,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId(IntLiteral("1e2").mapK(WithSource.liftId)) - }(Schema.byte), + }( + using Schema.byte + ), Ior.right(100.toByte), ) } @@ -341,7 +379,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert.same( compile { WithSource.liftId(Float.MaxValue.mapK(WithSource.liftId)) - }(Schema.float), + }( + using Schema.float + ), Ior.right(Float.MaxValue), ) } @@ -350,7 +390,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile { WithSource.liftId(Double.MaxValue.toString.mapK(WithSource.liftId)) - }(Schema.float).isLeft + }( + using Schema.float + ).isLeft ) } @@ -358,7 +400,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId(IntLiteral("0.1e0").mapK(WithSource.liftId)) - }(Schema.float), + }( + using Schema.float + ), Ior.right(0.1f), ) } @@ -367,7 +411,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId(Double.MaxValue.mapK(WithSource.liftId)) - }(Schema.double), + }( + using Schema.double + ), Ior.right(Double.MaxValue), ) } @@ -376,7 +422,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId((BigDecimal(Double.MaxValue) + 1).mapK(WithSource.liftId)) - }(Schema.double), + }( + using Schema.double + ), Ior.right(Double.MaxValue), ) } @@ -385,7 +433,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId(IntLiteral("0.1e0").mapK(WithSource.liftId)) - }(Schema.double), + }( + using Schema.double + ), Ior.right(0.1), ) } @@ -395,7 +445,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId(bi.mapK(WithSource.liftId)) - }(Schema.bigint), + }( + using Schema.bigint + ), Ior.right(bi), ) } @@ -405,7 +457,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile { WithSource.liftId("40.50".mapK(WithSource.liftId)) - }(Schema.bigint).isLeft + }( + using Schema.bigint + ).isLeft ) } @@ -413,7 +467,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId(IntLiteral("1e2").mapK(WithSource.liftId)) - }(Schema.bigint), + }( + using Schema.bigint + ), Ior.right(BigInt(100)), ) } @@ -423,7 +479,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId(bd.mapK(WithSource.liftId)) - }(Schema.bigdecimal), + }( + using Schema.bigdecimal + ), Ior.right(bd), ) } @@ -433,7 +491,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile { WithSource.liftId("AAAA".mapK(WithSource.liftId)) - }(Schema.bigdecimal).isLeft + }( + using Schema.bigdecimal + ).isLeft ) } @@ -441,7 +501,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId(IntLiteral("1e2").mapK(WithSource.liftId)) - }(Schema.bigdecimal), + }( + using Schema.bigdecimal + ), Ior.right(BigDecimal(100)), ) } @@ -450,7 +512,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId(true.mapK(WithSource.liftId)) - }(Schema.boolean), + }( + using Schema.boolean + ), Ior.right(true), ) } @@ -459,7 +523,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId(NullLiteral[WithSource]()) - }(Schema.document), + }( + using Schema.document + ), Ior.right(Document.nullDoc), ) } @@ -468,7 +534,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile { WithSource.liftId(NullLiteral[WithSource]()) - }(Schema.string).isLeft + }( + using Schema.string + ).isLeft ) } @@ -476,7 +544,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assertNoDiff( compile { WithSource.liftId("dGVzdA==".mapK(WithSource.liftId)) - }(Schema.bytes), + }( + using Schema.bytes + ), Ior.right(Blob("test".getBytes())), ) } @@ -485,7 +555,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile { WithSource.liftId("XYI519274n91lasdf/a'\'...,,".mapK(WithSource.liftId)) - }(Schema.bytes).isLeft + }( + using Schema.bytes + ).isLeft ) } @@ -542,7 +614,7 @@ object CompilationTests extends SimpleIOSuite with Checkers { pureTest("dynamic struct with default field") { val result = compile(WithSource.liftId(struct().mapK(WithSource.liftId)))( - dynamicSchemaFor[HasDefault] + using dynamicSchemaFor[HasDefault] ) // Object is empty here, but the server shall deserialize it providing the default @@ -598,7 +670,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { WithSource.liftId { struct("name" -> "foo").mapK(WithSource.liftId) } - }(dynamicSchemaFor[HasMixin]).void + }( + using dynamicSchemaFor[HasMixin] + ).void val expected = Ior.left( NonEmptyChain.of( @@ -674,7 +748,7 @@ object CompilationTests extends SimpleIOSuite with Checkers { pureTest("timestamp - OK") { val result = compile(WithSource.liftId("2022-07-11T17:42:28.000Z".mapK(WithSource.liftId)))( - Schema.timestamp + using Schema.timestamp ) val expected = Timestamp.parse("2022-07-11T17:42:28.000Z", TimestampFormat.DATE_TIME).get @@ -687,7 +761,7 @@ object CompilationTests extends SimpleIOSuite with Checkers { pureTest("timestamp - ignores format") { val result = compile(WithSource.liftId("2022-07-11T17:42:28.000Z".mapK(WithSource.liftId)))( - Schema.timestamp.addHints(TimestampFormat.EPOCH_SECONDS: TimestampFormat) + using Schema.timestamp.addHints(TimestampFormat.EPOCH_SECONDS: TimestampFormat) ) val expected = Timestamp.parse("2022-07-11T17:42:28.000Z", TimestampFormat.DATE_TIME).get @@ -700,7 +774,7 @@ object CompilationTests extends SimpleIOSuite with Checkers { pureTest("timestamp - fails when the format is invalid") { val result = compile(WithSource.liftId("not-a-timestamp".mapK(WithSource.liftId)))( - Schema.timestamp + using Schema.timestamp ).leftMap(_.map(_.err)) assertNoDiff( @@ -716,7 +790,7 @@ object CompilationTests extends SimpleIOSuite with Checkers { compile( WithSource.liftId("9c8f8f8f-8f8f-8f8f-8f8f-8f8f8f8f8f8f".mapK(WithSource.liftId)) )( - Schema.uuid + using Schema.uuid ) assertNoDiff( @@ -738,7 +812,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { Ior.right(Document.obj("enumWithLength" -> Document.fromString("AB"))), compile( WithSource.liftId(struct("enumWithLength" -> "AB").mapK(WithSource.liftId)) - )(dynamicSchemaFor[EnumStruct]), + )( + using dynamicSchemaFor[EnumStruct] + ), ) } @@ -746,7 +822,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile( WithSource.liftId(struct("enumWithLength" -> "ABC").mapK(WithSource.liftId)) - )(dynamicSchemaFor[EnumStruct]).isLeft + )( + using dynamicSchemaFor[EnumStruct] + ).isLeft ) } @@ -755,7 +833,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { Ior.right(Document.obj("intEnumWithRange" -> Document.fromInt(2))), compile( WithSource.liftId(struct("intEnumWithRange" -> "QUEEN").mapK(WithSource.liftId)) - )(dynamicSchemaFor[EnumStruct]), + )( + using dynamicSchemaFor[EnumStruct] + ), ) } @@ -763,7 +843,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile( WithSource.liftId(struct("intEnumWithRange" -> "KING").mapK(WithSource.liftId)) - )(dynamicSchemaFor[EnumStruct]).isLeft + )( + using dynamicSchemaFor[EnumStruct] + ).isLeft ) } @@ -772,7 +854,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { Ior.right(Document.obj("enumWithPattern" -> Document.fromString("AB"))), compile( WithSource.liftId(struct("enumWithPattern" -> "AB").mapK(WithSource.liftId)) - )(dynamicSchemaFor[EnumStruct]), + )( + using dynamicSchemaFor[EnumStruct] + ), ) } @@ -780,7 +864,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert( compile( WithSource.liftId(struct("enumWithPattern" -> "ABC").mapK(WithSource.liftId)) - )(dynamicSchemaFor[EnumStruct]).isLeft + )( + using dynamicSchemaFor[EnumStruct] + ).isLeft ) } @@ -851,7 +937,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { assert.same( compile( WithSource.liftId(List[InputNode[Id]](1, NullLiteral(), 3).mapK(WithSource.liftId)) - )(dynamicSchemaFor[SampleSparseList]).leftMap(_.map(_.err)), + )( + using dynamicSchemaFor[SampleSparseList] + ).leftMap(_.map(_.err)), Ior.right( Document.array( List( @@ -931,7 +1019,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { ) ) ) - )(dynamicSchemaFor[IntSet]) + )( + using dynamicSchemaFor[IntSet] + ) assert( actual == Ior.both( @@ -982,7 +1072,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { item, ).mapK(WithSource.liftId) ) - )(dynamicSchemaFor[FriendSet]) + )( + using dynamicSchemaFor[FriendSet] + ) .leftMap(_.map(_.err)) assertNoDiff( @@ -1004,7 +1096,7 @@ object CompilationTests extends SimpleIOSuite with Checkers { ).mapK(WithSource.liftId) ) )( - Schema.set(dynamicSchemaFor[Person]) + using Schema.set(dynamicSchemaFor[Person]) ) val expected = Set( @@ -1047,7 +1139,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { test("anything to document matches") { forall((wast: QueryCompiler.WAST) => assert( - compile[Document](wast)(Schema.document).isRight + compile[Document](wast)( + using Schema.document + ).isRight ) ) } @@ -1061,7 +1155,9 @@ object CompilationTests extends SimpleIOSuite with Checkers { struct("name" -> "aaa"), ).mapK(WithSource.liftId) ) - )(Schema.document), + )( + using Schema.document + ), Ior.right( Document.array( Document.obj( diff --git a/modules/e2e/src/test/scala/playground/e2e/E2ETests.scala b/modules/e2e/src/test/scala/playground/e2e/E2ETests.scala index de13b1af..e4440b0a 100644 --- a/modules/e2e/src/test/scala/playground/e2e/E2ETests.scala +++ b/modules/e2e/src/test/scala/playground/e2e/E2ETests.scala @@ -21,6 +21,7 @@ import weaver.* import java.io.PrintWriter import java.lang.ProcessBuilder.Redirect import java.util.concurrent.CompletableFuture +import scala.annotation.nowarn import scala.concurrent.duration.* import scala.jdk.CollectionConverters.* import scala.util.chaining.* @@ -93,7 +94,9 @@ object E2ETests extends SimpleIOSuite { .create() Resource - .make(IO(launcher.startListening()).timeout(5.seconds))(f => IO(f.cancel(true): Unit)) + .make(IO(launcher.startListening()).timeout(5.seconds))(f => + IO(f.cancel(true): @nowarn("msg=discarded non-Unit")) + ) .as(new LanguageServerAdapter(launcher.getRemoteProxy())) } } diff --git a/modules/formatter/src/test/scala/playground/smithyql/format/FormattingTests.scala b/modules/formatter/src/test/scala/playground/smithyql/format/FormattingTests.scala index dc3156e2..794126d1 100644 --- a/modules/formatter/src/test/scala/playground/smithyql/format/FormattingTests.scala +++ b/modules/formatter/src/test/scala/playground/smithyql/format/FormattingTests.scala @@ -11,7 +11,7 @@ import util.chaining.* import weaver.* import weaver.scalacheck.Checkers -import Diffs.* +import Diffs.given object FormattingTests extends SimpleIOSuite with Checkers { diff --git a/modules/language-support/src/main/scala/playground/language/CommandProvider.scala b/modules/language-support/src/main/scala/playground/language/CommandProvider.scala index 2a2fc9ba..b909a90e 100644 --- a/modules/language-support/src/main/scala/playground/language/CommandProvider.scala +++ b/modules/language-support/src/main/scala/playground/language/CommandProvider.scala @@ -1,5 +1,6 @@ package playground.language +import cats.Applicative import cats.Id import cats.MonadThrow import cats.data.NonEmptyList @@ -28,33 +29,13 @@ trait CommandProvider[F[_]] { object CommandProvider { - def instance[F[_]: MonadThrow: TextDocumentProvider: CommandResultReporter]( + def instance[F[_]: MonadThrow: TextDocumentProvider]( compiler: FileCompiler[F], runner: FileRunner.Resolver[F], + )( + using reporter: CommandResultReporter[F] ): CommandProvider[F] = new CommandProvider[F] { - private val reporter = CommandResultReporter[F] - - private case class RunnerBuildErrors( - issues: NonEmptyList[OperationRunner.Issue.Squashed] - ) extends Exception { - - def report: F[Unit] = { - val (protocolIssues, otherIssues) = issues.toList.partitionMap { - case p: OperationRunner.Issue.Squashed.ProtocolIssues => p.asLeft - - case p: OperationRunner.Issue.Squashed.OtherIssues => p.asRight - } - - CommandResultReporter[F] - .onUnsupportedProtocol - .whenA(protocolIssues.nonEmpty) *> - otherIssues.traverse_ { case OperationRunner.Issue.Squashed.OtherIssues(others) => - CommandResultReporter[F].onIssues(others) - } - } - - } private case class QueryError( e: Throwable, @@ -134,4 +115,25 @@ object CommandProvider { } + private case class RunnerBuildErrors( + issues: NonEmptyList[OperationRunner.Issue.Squashed] + ) extends Exception { + + def report[F[_]: CommandResultReporter: Applicative]: F[Unit] = { + val (protocolIssues, otherIssues) = issues.toList.partitionMap { + case p: OperationRunner.Issue.Squashed.ProtocolIssues => p.asLeft + + case p: OperationRunner.Issue.Squashed.OtherIssues => p.asRight + } + + CommandResultReporter[F] + .onUnsupportedProtocol + .whenA(protocolIssues.nonEmpty) *> + otherIssues.traverse_ { case OperationRunner.Issue.Squashed.OtherIssues(others) => + CommandResultReporter[F].onIssues(others) + } + } + + } + } diff --git a/modules/language-support/src/main/scala/playground/language/CompletionVisitor.scala b/modules/language-support/src/main/scala/playground/language/CompletionVisitor.scala index fcd8dd42..f8421a93 100644 --- a/modules/language-support/src/main/scala/playground/language/CompletionVisitor.scala +++ b/modules/language-support/src/main/scala/playground/language/CompletionVisitor.scala @@ -127,7 +127,7 @@ object CompletionItem { ).copy(detail = describeService(service)) def fromField( - field: Field[_, _] + field: Field[?, ?] ): CompletionItem = fromHints( kind = CompletionItemKind.Field, label = field.label, @@ -136,7 +136,7 @@ object CompletionItem { ) def fromAlt( - alt: Alt[_, _] + alt: Alt[?, ?] ): CompletionItem = fromHints( kind = CompletionItemKind.UnionMember, label = alt.label, @@ -156,7 +156,7 @@ object CompletionItem { kind: CompletionItemKind, label: String, insertText: InsertText, - schema: Schema[_], + schema: Schema[?], ): CompletionItem = { val isField = kind === CompletionItemKind.Field @@ -188,7 +188,7 @@ object CompletionItem { def describeType( isField: Boolean, - schema: Schema[_], + schema: Schema[?], ): String = { val isOptional = isField && !isRequiredField(schema) @@ -201,10 +201,10 @@ object CompletionItem { } private def isRequiredField( - schema: Schema[_] + schema: Schema[?] ): Boolean = schema.hints.has(smithy.api.Required) - private val describePrimitive: Primitive[_] => String = { + private val describePrimitive: Primitive[?] => String = { import smithy4s.schema.Primitive.* { @@ -238,7 +238,7 @@ object CompletionItem { // nice to have: precompile this? caching? def describeSchema( - schema: Schema[_] + schema: Schema[?] ): ( ) => String = schema match { @@ -310,7 +310,7 @@ object CompletionItem { def forOperation[Op[_, _, _, _, _]]( insertUseClause: InsertUseClause, - endpoint: Endpoint[Op, _, _, _, _, _], + endpoint: Endpoint[Op, ?, ?, ?, ?, ?], serviceId: QualifiedIdentifier, insertBodyStruct: InsertBodyStruct, ): CompletionItem = { @@ -567,7 +567,7 @@ object CompletionVisitor extends SchemaVisitor[CompletionResolver] { override def struct[S]( shapeId: ShapeId, hints: Hints, - fields: Vector[Field[S, _]], + fields: Vector[Field[S, ?]], make: IndexedSeq[Any] => S, ): CompletionResolver[S] = { val compiledFields = fields.map(field => (field, field.schema.compile(this))) @@ -595,7 +595,7 @@ object CompletionVisitor extends SchemaVisitor[CompletionResolver] { override def union[U]( shapeId: ShapeId, hints: Hints, - alternatives: Vector[Alt[U, _]], + alternatives: Vector[Alt[U, ?]], dispatcher: Alt.Dispatcher[U], ): CompletionResolver[U] = { val compiledAlts = alternatives.map { alt => diff --git a/modules/language-support/src/test/scala/playground/language/CodeLensProviderTests.scala b/modules/language-support/src/test/scala/playground/language/CodeLensProviderTests.scala index 9d62b88b..7407fdd4 100644 --- a/modules/language-support/src/test/scala/playground/language/CodeLensProviderTests.scala +++ b/modules/language-support/src/test/scala/playground/language/CodeLensProviderTests.scala @@ -12,7 +12,7 @@ import playground.OperationRunner import playground.PreludeCompiler import playground.ServiceIndex import playground.ServiceUtils.* -import playground.language.Diffs.* +import playground.language.Diffs.given import playground.smithyql.StringRangeUtils.* import playground.std.RandomGen import weaver.* diff --git a/modules/language-support/src/test/scala/playground/language/CompletionItemTests.scala b/modules/language-support/src/test/scala/playground/language/CompletionItemTests.scala index 9a3c443f..b9457c47 100644 --- a/modules/language-support/src/test/scala/playground/language/CompletionItemTests.scala +++ b/modules/language-support/src/test/scala/playground/language/CompletionItemTests.scala @@ -11,7 +11,7 @@ import playground.std.ClockOperation import smithy4s.schema.Schema import weaver.* -import Diffs.* +import Diffs.given object CompletionItemTests extends FunSuite { test("CompletionItem.fromField: required field") { diff --git a/modules/language-support/src/test/scala/playground/language/CompletionProviderTests.scala b/modules/language-support/src/test/scala/playground/language/CompletionProviderTests.scala index 4984f05d..e5e7c594 100644 --- a/modules/language-support/src/test/scala/playground/language/CompletionProviderTests.scala +++ b/modules/language-support/src/test/scala/playground/language/CompletionProviderTests.scala @@ -4,7 +4,7 @@ import demo.smithy.DemoServiceGen import demo.smithy.DeprecatedServiceGen import playground.Assertions.* import playground.ServiceUtils.* -import playground.language.Diffs.* +import playground.language.Diffs.given import playground.smithyql.Position import playground.smithyql.QualifiedIdentifier import playground.smithyql.StringRangeUtils.* diff --git a/modules/language-support/src/test/scala/playground/language/CompletionTests.scala b/modules/language-support/src/test/scala/playground/language/CompletionTests.scala index f8db225e..65ac32c0 100644 --- a/modules/language-support/src/test/scala/playground/language/CompletionTests.scala +++ b/modules/language-support/src/test/scala/playground/language/CompletionTests.scala @@ -16,7 +16,7 @@ import demo.smithy.PrivacyTier import demo.smithy.SampleSparseList import demo.smithy.SampleSparseMap import playground.Assertions.* -import playground.language.Diffs.* +import playground.language.Diffs.given import playground.smithyql.NodeContext import playground.smithyql.NodeContext.PathEntry.* import smithy.api.TimestampFormat @@ -30,7 +30,7 @@ import java.util.UUID object CompletionTests extends FunSuite { def getCompletions( - schema: Schema[_], + schema: Schema[?], ctx: NodeContext, ): List[CompletionItem] = schema.compile(CompletionVisitor).getCompletions(ctx) diff --git a/modules/language-support/src/test/scala/playground/language/DiagnosticProviderTests.scala b/modules/language-support/src/test/scala/playground/language/DiagnosticProviderTests.scala index f8d6236c..fcf19a40 100644 --- a/modules/language-support/src/test/scala/playground/language/DiagnosticProviderTests.scala +++ b/modules/language-support/src/test/scala/playground/language/DiagnosticProviderTests.scala @@ -19,7 +19,7 @@ import playground.CompilationError import playground.CompilationErrorDetails import playground.CompilationFailed import playground.DiagnosticSeverity -import playground.Diffs.* +import playground.Diffs.given import playground.FileCompiler import playground.FileRunner import playground.OperationCompiler diff --git a/modules/language-support/src/test/scala/playground/language/Diffs.scala b/modules/language-support/src/test/scala/playground/language/Diffs.scala index bf5421fb..ee6bc615 100644 --- a/modules/language-support/src/test/scala/playground/language/Diffs.scala +++ b/modules/language-support/src/test/scala/playground/language/Diffs.scala @@ -1,10 +1,15 @@ package playground.language import com.softwaremill.diffx.Diff +import playground.smithyql.Diffs.given object Diffs { - import com.softwaremill.diffx.generic.auto.* - implicit val diffCompletionItem: Diff[CompletionItem] = Diff.derivedDiff - implicit lazy val diffDocumentSymbol: Diff[DocumentSymbol] = Diff.derivedDiff - implicit lazy val diffCodeLens: Diff[CodeLens] = Diff.derivedDiff + given Diff[CompletionItemKind] = Diff.derived + given Diff[TextEdit] = Diff.derived + given Diff[InsertText] = Diff.derived + given Diff[CompletionItem] = Diff.derived + given Diff[SymbolKind] = Diff.derived + given Diff[DocumentSymbol] = Diff.derived + given Diff[Command] = Diff.derived + given Diff[CodeLens] = Diff.derived } diff --git a/modules/language-support/src/test/scala/playground/language/DocumentSymbolProviderTests.scala b/modules/language-support/src/test/scala/playground/language/DocumentSymbolProviderTests.scala index 213f7209..53e938ba 100644 --- a/modules/language-support/src/test/scala/playground/language/DocumentSymbolProviderTests.scala +++ b/modules/language-support/src/test/scala/playground/language/DocumentSymbolProviderTests.scala @@ -1,7 +1,7 @@ package playground.language import playground.Assertions.* -import playground.language.Diffs.* +import playground.language.Diffs.given import playground.smithyql.Position import playground.smithyql.SourceRange import weaver.* diff --git a/modules/lsp/src/main/scala/playground/lsp/ModelLoader.scala b/modules/lsp/src/main/scala/playground/lsp/ModelLoader.scala index 6793316e..cf456ab8 100644 --- a/modules/lsp/src/main/scala/playground/lsp/ModelLoader.scala +++ b/modules/lsp/src/main/scala/playground/lsp/ModelLoader.scala @@ -96,22 +96,20 @@ object ModelLoader { private def addFileImports( imports: Iterable[File] - ): ModelAssembler => ModelAssembler = - assembler => { - imports.foreach(f => assembler.addImport(f.toPath())) - assembler - } + ): ModelAssembler => ModelAssembler = { assembler => + imports.foreach(f => assembler.addImport(f.toPath())) + assembler + } private def addPlaygroundModels( classLoader: ClassLoader - ): ModelAssembler => ModelAssembler = - assembler => { - List( - "META-INF/smithy/std.smithy" - ).map(classLoader.getResource).foreach(assembler.addImport) + ): ModelAssembler => ModelAssembler = { assembler => + List( + "META-INF/smithy/std.smithy" + ).map(classLoader.getResource).foreach(assembler.addImport) - assembler - } + assembler + } def resolveModelDependencies( config: PlaygroundConfig @@ -150,8 +148,8 @@ object ModelLoader { } Fetch(FileCache[Task]().withTtl(1.hour)) - .addRepositories(repos: _*) - .addDependencies(deps: _*) + .addRepositories(repos*) + .addDependencies(deps*) .run() .toList } diff --git a/modules/lsp/src/main/scala/playground/lsp/PlaygroundLanguageServerAdapter.scala b/modules/lsp/src/main/scala/playground/lsp/PlaygroundLanguageServerAdapter.scala index 2c2c68f9..0695da52 100644 --- a/modules/lsp/src/main/scala/playground/lsp/PlaygroundLanguageServerAdapter.scala +++ b/modules/lsp/src/main/scala/playground/lsp/PlaygroundLanguageServerAdapter.scala @@ -97,12 +97,9 @@ final class PlaygroundLanguageServerAdapter[F[_]: Functor]( @JsonRequest("workspace/executeCommand") def executeCommand( params: ExecuteCommandParams - ): CompletableFuture[Object] = d - .unsafeToCompletableFuture( - impl - .executeCommand(params) - .as(null: Object) - ) + ): CompletableFuture[Object] = d.unsafeToCompletableFuture( + impl.executeCommand(params).as(null: Object) + ) @JsonNotification("workspace/didChangeWatchedFiles") def didChangeWatchedFiles( @@ -121,8 +118,7 @@ final class PlaygroundLanguageServerAdapter[F[_]: Functor]( @JsonRequest("smithyql/runQuery") def runQuery( params: RunFileParams - ): CompletableFuture[Object] = d - .unsafeToCompletableFuture(impl.runFile(params).as(null: Object)) + ): CompletableFuture[Object] = d.unsafeToCompletableFuture(impl.runFile(params).as(null: Object)) @JsonRequest("exit") def exit( diff --git a/modules/lsp/src/test/scala/playground/lsp/LanguageServerIntegrationTestSharedServer.scala b/modules/lsp/src/test/scala/playground/lsp/LanguageServerIntegrationTestSharedServer.scala index a84d9973..a85b39e2 100644 --- a/modules/lsp/src/test/scala/playground/lsp/LanguageServerIntegrationTestSharedServer.scala +++ b/modules/lsp/src/test/scala/playground/lsp/LanguageServerIntegrationTestSharedServer.scala @@ -29,32 +29,12 @@ object LanguageServerIntegrationTestSharedServer extends IOSuite with LanguageServerIntegrationTests { + override protected def checkStartupLogs: Boolean = true + type Res = Fixture def sharedResource: Resource[IO, Res] = makeServer(testWorkspacesBase / "default") - test("server init produces logs consistent with the workspace folder") { f => - val initLogs = List( - TestClient - .MessageLog( - MessageType.Info, - s"Hello from Smithy Playground v${BuildInfo.version}", - ), - TestClient.MessageLog( - MessageType.Info, - "Loaded Smithy Playground server with 2 sources, 0 imports, 2 dependencies and 0 plugins", - ), - ) - - // logs produced during an implicit initialization in the resource setup - f.client.getEvents.map { events => - assert.same( - events, - initLogs, - ) - } - } - test("completions").apply { f => f.server .completion( @@ -94,7 +74,7 @@ object LanguageServerIntegrationTestSharedServer report.getRelatedFullDocumentDiagnosticReport().getItems().asScala.toList assert(diagnosticItems.size == 1) && - assert(diagnosticItems.head.getSeverity() == DiagnosticSeverity.Error) && + assert.same(diagnosticItems.head.getSeverity(), DiagnosticSeverity.Error) && assert(diagnosticItems.head.getMessage.contains("Parsing failure")) } } @@ -312,7 +292,9 @@ object LanguageServerIntegrationTestSharedServer .map { events => assert.eql(events.length, 4) && assert.same(events(0), TestClient.OutputPanelShow) && - assert(events(1).asInstanceOf[TestClient.OutputLog].text.contains("Calling GetWeather")) && + assert( + events(1).asInstanceOf[TestClient.OutputLog].text.contains("Calling GetWeather") + ) && assert(events(2).asInstanceOf[TestClient.OutputLog].text.contains("// HTTP/1.1 GET")) && assert( events(3) diff --git a/modules/lsp/src/test/scala/playground/lsp/harness/LanguageServerIntegrationTests.scala b/modules/lsp/src/test/scala/playground/lsp/harness/LanguageServerIntegrationTests.scala index a7922192..231ce510 100644 --- a/modules/lsp/src/test/scala/playground/lsp/harness/LanguageServerIntegrationTests.scala +++ b/modules/lsp/src/test/scala/playground/lsp/harness/LanguageServerIntegrationTests.scala @@ -1,18 +1,25 @@ package playground.lsp.harness import cats.effect.IO +import cats.effect.IOLocal import cats.effect.Resource +import cats.syntax.all.* import org.eclipse.lsp4j.InitializeParams +import org.eclipse.lsp4j.MessageType import org.eclipse.lsp4j.WorkspaceFolder import playground.language.Uri import playground.lsp.LanguageServer import playground.lsp.MainServer +import playground.lsp.buildinfo.BuildInfo +import weaver.SourceLocation import scala.jdk.CollectionConverters.* import scala.util.chaining.* trait LanguageServerIntegrationTests { + protected def checkStartupLogs: Boolean = false + case class Fixture( server: LanguageServer[IO], client: TestClient[IO], @@ -34,16 +41,56 @@ trait LanguageServerIntegrationTests { ): Resource[IO, Fixture] = TestClient.forIO.toResource.flatMap { implicit client => MainServer .makeServer[IO] - .evalTap(_.initialize(initParams(workspaceDir))) - .map { server => - Fixture( + .evalMap { server => + val result = Fixture( server = server, client = client, workspaceDir = workspaceDir, ) + + server.initialize(initParams(workspaceDir)) *> + assertStartupEvents(client) + .as(result) } } + /* + * Note - this should've been a test (and used to). + * For some reason, it no longer worked because logs produced by the initialize call were suddenly being lost after resource initialization. + * The underlying cause for event loss was broken IOLocal propagation in the event of lifting resources to fs2 streams + * (resulting in the resource being acquired step-by-step with multiple fibers). + * + * If the underlying issue is solved, this can again be turned into a test. + */ + private def assertStartupEvents( + client: TestClient[IO] + ): IO[Unit] = client + .getEvents + .flatMap { events => + val initLogs = List( + TestClient + .MessageLog( + MessageType.Info, + s"Hello from Smithy Playground v${BuildInfo.version}", + ), + TestClient.MessageLog( + MessageType.Info, + "Loaded Smithy Playground server with 2 sources, 0 imports, 2 dependencies and 0 plugins", + ), + ) + IO { + require( + events.size == 2, + "Events emitted at startup should've had size 2, it was " + events.size + " instead", + ) + require( + events == initLogs, + "Events were not as expected, got: " + events, + ) + } + } + .whenA(checkStartupLogs) + def testWorkspacesBase: Uri = Uri.fromUriString( getClass .getResource("/test-workspaces") diff --git a/modules/lsp/src/test/scala/playground/lsp/harness/TestClient.scala b/modules/lsp/src/test/scala/playground/lsp/harness/TestClient.scala index d2831105..8eecd22b 100644 --- a/modules/lsp/src/test/scala/playground/lsp/harness/TestClient.scala +++ b/modules/lsp/src/test/scala/playground/lsp/harness/TestClient.scala @@ -12,10 +12,11 @@ import playground.lsp.LanguageClient trait TestClient[F[_]] extends LanguageClient[F] { def getEvents: F[List[TestClient.Event]] + def scoped: F ~> F def withConfiguration( - v: ConfigurationValue.Applied[_]* + v: ConfigurationValue.Applied[?]* ): F ~> F } @@ -42,7 +43,7 @@ object TestClient { ) { def addConfig( - values: ConfigurationValue.Applied[_]* + values: ConfigurationValue.Applied[?]* ): State = copy(configuration = configuration ++ values.map { v => v.cv.key -> v.encoded @@ -115,7 +116,7 @@ object TestClient { } def withConfiguration( - v: ConfigurationValue.Applied[_]* + v: ConfigurationValue.Applied[?]* ): IO ~> IO = new (IO ~> IO) { def apply[T]( @@ -124,7 +125,7 @@ object TestClient { state .modify { old => ( - old.addConfig(v: _*), + old.addConfig(v*), old, ) } diff --git a/modules/parser/src/main/scala/playground/smithyql/parser/Parsers.scala b/modules/parser/src/main/scala/playground/smithyql/parser/Parsers.scala index e6305336..1ac00fe7 100644 --- a/modules/parser/src/main/scala/playground/smithyql/parser/Parsers.scala +++ b/modules/parser/src/main/scala/playground/smithyql/parser/Parsers.scala @@ -170,7 +170,7 @@ object Parsers { ( // soft: allows backtracking if hash isn't present (for operation names) - segments.soft ~ (tokens.hash *> tokens.whitespace *> rawIdent), + segments.soft ~ (tokens.hash *> tokens.whitespace *> rawIdent) ).map(QualifiedIdentifier.apply.tupled) }.withContext("qualified_ident") diff --git a/modules/parser/src/main/scala/playground/smithyql/parser/v2/scanner.scala b/modules/parser/src/main/scala/playground/smithyql/parser/v2/scanner.scala index f0b4fb82..0f5f9683 100644 --- a/modules/parser/src/main/scala/playground/smithyql/parser/v2/scanner.scala +++ b/modules/parser/src/main/scala/playground/smithyql/parser/v2/scanner.scala @@ -134,7 +134,7 @@ object Scanner { // I love this language object jsonNumber { def unapply( - @nowarn("cat=unused") + @nowarn("msg=unused") unused: Unit ): Option[ ( @@ -181,7 +181,7 @@ object Scanner { val eatWhitespace: PartialFunction[Unit, Unit] = { object matches { def unapply( - @nowarn("cat=unused") u: Unit + @nowarn("msg=unused") u: Unit ): Option[ ( String, @@ -239,7 +239,7 @@ object Scanner { readAny .lift(()) .isDefined || - eatErrors(): Unit + eatErrors(): @nowarn("msg=unused value of type Boolean") // last-effort sanity check if (remaining == last) diff --git a/modules/parser/src/test/scala/playground/smithyql/parser/Codecs.scala b/modules/parser/src/test/scala/playground/smithyql/parser/Codecs.scala index 412c1976..8c82c7a3 100644 --- a/modules/parser/src/test/scala/playground/smithyql/parser/Codecs.scala +++ b/modules/parser/src/test/scala/playground/smithyql/parser/Codecs.scala @@ -1,28 +1,66 @@ package playground.smithyql.parser import io.circe.Codec +import io.circe.Decoder +import io.circe.Encoder +import playground.smithyql.Binding +import playground.smithyql.Comment +import playground.smithyql.Diffs.given +import playground.smithyql.Identifier +import playground.smithyql.InputNode import playground.smithyql.Listed +import playground.smithyql.OperationName +import playground.smithyql.Position import playground.smithyql.Prelude +import playground.smithyql.QualifiedIdentifier import playground.smithyql.Query +import playground.smithyql.QueryOperationName import playground.smithyql.SourceFile +import playground.smithyql.SourceRange +import playground.smithyql.Statement import playground.smithyql.Struct import playground.smithyql.UseClause import playground.smithyql.WithSource object Codecs { - import io.circe.generic.auto.* - import io.circe.generic.semiauto.* + given Codec[Position] = Codec.AsObject.derived + given Codec[Identifier] = Codec.AsObject.derived + given Codec[QualifiedIdentifier] = Codec.AsObject.derived + given Codec[Comment] = Codec.AsObject.derived + given Codec[SourceRange] = Codec.AsObject.derived + given [A: Codec]: Codec[WithSource[A]] = Codec.AsObject.derived - implicit val useClauseWithSourceCodec: Codec[UseClause[WithSource]] = deriveCodec + given Codec[UseClause[WithSource]] = Codec.AsObject.derived - implicit val listedWithSourceCodec: Codec[Listed[WithSource]] = deriveCodec + given Codec[WithSource[InputNode[WithSource]]] = Codec.AsObject.derived - implicit val structWithSourceCodec: Codec[Struct[WithSource]] = deriveCodec + given Codec[InputNode[WithSource]] = Codec.AsObject.derived - implicit val queryWithSourceCodec: Codec[Query[WithSource]] = deriveCodec + // strange thing - somehow doesn't get picked up automatically. + given Codec[List[WithSource[InputNode[WithSource]]]] = Codec.from( + Decoder.decodeList, + Encoder.encodeList, + ) - implicit val preludeWithSourceCodec: Codec[Prelude[WithSource]] = deriveCodec + given Codec[Listed[WithSource]] = Codec.AsObject.derived - implicit val sourceFileWithSourceCodec: Codec[SourceFile[WithSource]] = deriveCodec + given Codec[Binding[WithSource]] = Codec.AsObject.derived + given Codec[Struct.Fields[WithSource]] = Codec.AsObject.derived + + given Codec[Struct[WithSource]] = Codec.AsObject.derived + given Codec[OperationName[WithSource]] = Codec.AsObject.derived + given Codec[QueryOperationName[WithSource]] = Codec.AsObject.derived + given Codec[Query[WithSource]] = Codec.AsObject.derived + + given Codec[Prelude[WithSource]] = Codec.AsObject.derived + + given Codec[Statement[WithSource]] = Codec.AsObject.derived + + given lsw: Codec[List[Statement[WithSource]]] = Codec.from( + Decoder.decodeList, + Encoder.encodeList, + ) + + given Codec[SourceFile[WithSource]] = Codec.AsObject.derived } diff --git a/modules/parser/src/test/scala/playground/smithyql/parser/Diffs.scala b/modules/parser/src/test/scala/playground/smithyql/parser/Diffs.scala index 15c7f4b9..1367d882 100644 --- a/modules/parser/src/test/scala/playground/smithyql/parser/Diffs.scala +++ b/modules/parser/src/test/scala/playground/smithyql/parser/Diffs.scala @@ -1,9 +1,9 @@ package playground.smithyql.parser +import cats.parse.Parser import com.softwaremill.diffx.Diff object Diffs { - import com.softwaremill.diffx.generic.auto.* - - implicit val diffParsingFailure: Diff[ParsingFailure] = Diff.derivedDiff + given Diff[Parser.Error] = Diff.useEquals + given Diff[ParsingFailure] = Diff.derived } diff --git a/modules/parser/src/test/scala/playground/smithyql/parser/ParserSuite.scala b/modules/parser/src/test/scala/playground/smithyql/parser/ParserSuite.scala index c9f1ef87..95ea1188 100644 --- a/modules/parser/src/test/scala/playground/smithyql/parser/ParserSuite.scala +++ b/modules/parser/src/test/scala/playground/smithyql/parser/ParserSuite.scala @@ -120,7 +120,7 @@ trait ParserSuite extends SimpleIOSuite { ): List[TestCase] = { val baseDir = Paths .get(getClass().getResource("/parser-examples").getFile()) - .resolve(file.Path.of(prefix.head, prefix.tail: _*)) + .resolve(file.Path.of(prefix.head, prefix.tail*)) baseDir .toFile diff --git a/modules/parser/src/test/scala/playground/smithyql/parser/generative/ListParserTests.scala b/modules/parser/src/test/scala/playground/smithyql/parser/generative/ListParserTests.scala index 2c569430..8458527b 100644 --- a/modules/parser/src/test/scala/playground/smithyql/parser/generative/ListParserTests.scala +++ b/modules/parser/src/test/scala/playground/smithyql/parser/generative/ListParserTests.scala @@ -1,9 +1,10 @@ package playground.smithyql.parser.generative import playground.smithyql.* -import playground.smithyql.Diffs.* -import playground.smithyql.parser.Codecs.* +import playground.smithyql.Diffs.given +import playground.smithyql.parser.Codecs.given import playground.smithyql.parser.ParserSuite +import playground.smithyql.parser.SourceParser object ListParserTests extends ParserSuite { loadParserTests[Listed]("listed", trimWhitespace = true) diff --git a/modules/parser/src/test/scala/playground/smithyql/parser/generative/PreludeParserTests.scala b/modules/parser/src/test/scala/playground/smithyql/parser/generative/PreludeParserTests.scala index 34ce313d..5f06ffe9 100644 --- a/modules/parser/src/test/scala/playground/smithyql/parser/generative/PreludeParserTests.scala +++ b/modules/parser/src/test/scala/playground/smithyql/parser/generative/PreludeParserTests.scala @@ -1,8 +1,8 @@ package playground.smithyql.parser.generative import playground.smithyql.* -import playground.smithyql.Diffs.* -import playground.smithyql.parser.Codecs.* +import playground.smithyql.Diffs.given +import playground.smithyql.parser.Codecs.given import playground.smithyql.parser.ParserSuite object PreludeParserTests extends ParserSuite { diff --git a/modules/parser/src/test/scala/playground/smithyql/parser/generative/QueryParserTests.scala b/modules/parser/src/test/scala/playground/smithyql/parser/generative/QueryParserTests.scala index fe08713f..f285090c 100644 --- a/modules/parser/src/test/scala/playground/smithyql/parser/generative/QueryParserTests.scala +++ b/modules/parser/src/test/scala/playground/smithyql/parser/generative/QueryParserTests.scala @@ -1,8 +1,8 @@ package playground.smithyql.parser.generative import playground.smithyql.* -import playground.smithyql.Diffs.* -import playground.smithyql.parser.Codecs.* +import playground.smithyql.Diffs.given +import playground.smithyql.parser.Codecs.given import playground.smithyql.parser.ParserSuite object QueryParserTests extends ParserSuite { diff --git a/modules/parser/src/test/scala/playground/smithyql/parser/generative/SourceFileParserTests.scala b/modules/parser/src/test/scala/playground/smithyql/parser/generative/SourceFileParserTests.scala index 5d6ad8a1..a812b1bb 100644 --- a/modules/parser/src/test/scala/playground/smithyql/parser/generative/SourceFileParserTests.scala +++ b/modules/parser/src/test/scala/playground/smithyql/parser/generative/SourceFileParserTests.scala @@ -1,8 +1,8 @@ package playground.smithyql.parser.generative import playground.smithyql.* -import playground.smithyql.Diffs.* -import playground.smithyql.parser.Codecs.* +import playground.smithyql.Diffs.given +import playground.smithyql.parser.Codecs.given import playground.smithyql.parser.ParserSuite object SourceFileParserTests extends ParserSuite { diff --git a/modules/parser/src/test/scala/playground/smithyql/parser/generative/StructParserTests.scala b/modules/parser/src/test/scala/playground/smithyql/parser/generative/StructParserTests.scala index 011c0cc4..1eebed2f 100644 --- a/modules/parser/src/test/scala/playground/smithyql/parser/generative/StructParserTests.scala +++ b/modules/parser/src/test/scala/playground/smithyql/parser/generative/StructParserTests.scala @@ -1,8 +1,8 @@ package playground.smithyql.parser.generative import playground.smithyql.* -import playground.smithyql.Diffs.* -import playground.smithyql.parser.Codecs.* +import playground.smithyql.Diffs.given +import playground.smithyql.parser.Codecs.given import playground.smithyql.parser.ParserSuite object StructParserTests extends ParserSuite { diff --git a/modules/parser/src/test/scala/playground/smithyql/parser/generative/UseServiceParserTests.scala b/modules/parser/src/test/scala/playground/smithyql/parser/generative/UseServiceParserTests.scala index 052e3c93..b463ab0e 100644 --- a/modules/parser/src/test/scala/playground/smithyql/parser/generative/UseServiceParserTests.scala +++ b/modules/parser/src/test/scala/playground/smithyql/parser/generative/UseServiceParserTests.scala @@ -1,8 +1,8 @@ package playground.smithyql.parser.generative import playground.smithyql.* -import playground.smithyql.Diffs.* -import playground.smithyql.parser.Codecs.* +import playground.smithyql.Diffs.given +import playground.smithyql.parser.Codecs.given import playground.smithyql.parser.ParserSuite object UseServiceParserTests extends ParserSuite { diff --git a/modules/parser/src/test/scala/playground/smithyql/parser/v2/ScannerSuite.scala b/modules/parser/src/test/scala/playground/smithyql/parser/v2/ScannerSuite.scala index 9ed715fe..26862820 100644 --- a/modules/parser/src/test/scala/playground/smithyql/parser/v2/ScannerSuite.scala +++ b/modules/parser/src/test/scala/playground/smithyql/parser/v2/ScannerSuite.scala @@ -9,7 +9,7 @@ import playground.smithyql.parser.v2.scanner.Scanner import playground.smithyql.parser.v2.scanner.Token import weaver.* -import Diffs.* +import Diffs.given import Scanner.scan trait ScannerSuite { self: IOSuite => diff --git a/modules/parser/src/test/scala/playground/smithyql/parser/v2/ScannerTests.scala b/modules/parser/src/test/scala/playground/smithyql/parser/v2/ScannerTests.scala index 5bcbb054..5766ef72 100644 --- a/modules/parser/src/test/scala/playground/smithyql/parser/v2/ScannerTests.scala +++ b/modules/parser/src/test/scala/playground/smithyql/parser/v2/ScannerTests.scala @@ -10,14 +10,16 @@ import playground.smithyql.parser.v2.scanner.TokenKind.* import weaver.* import weaver.scalacheck.Checkers -import Diffs.* +import scala.annotation.nowarn + +import Diffs.given import Scanner.scan object ScannerTests extends SimpleIOSuite with Checkers with ScannerSuite { arbTests("Any string input scans successfully") { implicit arbString => forall { (s: String) => - scan(s): Unit + scan(s): @nowarn("msg=discarded non-Unit value") success } } diff --git a/modules/source/src/main/scala/playground/smithyql/StringRangeUtils.scala b/modules/source/src/main/scala/playground/smithyql/StringRangeUtils.scala index 82b26ee2..f628cf2b 100644 --- a/modules/source/src/main/scala/playground/smithyql/StringRangeUtils.scala +++ b/modules/source/src/main/scala/playground/smithyql/StringRangeUtils.scala @@ -1,8 +1,5 @@ package playground.smithyql -import playground.smithyql.Position -import playground.smithyql.SourceRange - // Mostly for testing. object StringRangeUtils { diff --git a/modules/source/src/main/scala/playground/smithyql/WithSource.scala b/modules/source/src/main/scala/playground/smithyql/WithSource.scala index 6a455f58..8004d272 100644 --- a/modules/source/src/main/scala/playground/smithyql/WithSource.scala +++ b/modules/source/src/main/scala/playground/smithyql/WithSource.scala @@ -9,13 +9,11 @@ import cats.kernel.Eq import cats.kernel.Order import cats.syntax.all.* import cats.~> -import playground.smithyql.InputNode -import playground.smithyql.Query // todo: multiline final case class Comment( text: String -) extends AnyVal +) object Comment { implicit val eq: Eq[Comment] = Eq.by(_.text) diff --git a/modules/source/src/test/scala/playground/smithyql/Diffs.scala b/modules/source/src/test/scala/playground/smithyql/Diffs.scala index d97d97c4..2807cf5d 100644 --- a/modules/source/src/test/scala/playground/smithyql/Diffs.scala +++ b/modules/source/src/test/scala/playground/smithyql/Diffs.scala @@ -1,27 +1,48 @@ package playground.smithyql +import cats.Id import com.softwaremill.diffx.Diff object Diffs { import com.softwaremill.diffx.cats.* import com.softwaremill.diffx.generic.auto.* - implicit val diffSourceRange: Diff[SourceRange] = Diff.derivedDiff + given Diff[Position] = Diff.derived - implicit val diffComment: Diff[Comment] = Diff.derivedDiff + given Diff[SourceRange] = Diff.derived - implicit val diffQualifiedIdentifier: Diff[QualifiedIdentifier] = Diff.derivedDiff + given Diff[Comment] = Diff.derived - implicit val diffUseClause: Diff[UseClause[WithSource]] = Diff.derivedDiff + given Diff[QualifiedIdentifier] = Diff.derived - implicit def diffListedWithSource: Diff[Listed[WithSource]] = Diff.derivedDiff + given [A: Diff]: Diff[WithSource[A]] = Diff.derived - implicit val diffStructWithSource: Diff[Struct[WithSource]] = Diff.derivedDiff + given Diff[UseClause[WithSource]] = Diff.derived - implicit val diffQueryWithSource: Diff[Query[WithSource]] = Diff.derivedDiff + given Diff[InputNode[WithSource]] = Diff.derived - implicit val diffPreludeWithSource: Diff[Prelude[WithSource]] = Diff.derivedDiff + given Diff[Listed[WithSource]] = Diff.derived - implicit val diffSourceFile: Diff[SourceFile[WithSource]] = Diff.derivedDiff + given Diff[NodeKind] = Diff.derived + given Diff[Identifier] = Diff.derived + + given Diff[Binding[WithSource]] = Diff.derived + + given Diff[Struct.Fields[WithSource]] = Diff.derived + + given Diff[Struct[WithSource]] = Diff.derived + + given Diff[OperationName[WithSource]] = Diff.derived + given opNameDiffId: Diff[OperationName[Id]] = Diff.derived + + given Diff[QueryOperationName[WithSource]] = Diff.derived + + given Diff[Query[WithSource]] = Diff.derived + + given Diff[Prelude[WithSource]] = Diff.derived + + given Diff[Statement[WithSource]] = Diff.derived + + given Diff[SourceFile[WithSource]] = Diff.derived } diff --git a/project/build.properties b/project/build.properties index 40b3b8e7..bc739060 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.9.0 +sbt.version=1.10.3 diff --git a/vscode-extension/package.json b/vscode-extension/package.json index 46cdadd8..7544af86 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -77,7 +77,7 @@ "smithyql.server.artifact": { "type": "string", "description": "The coordinates to the language server artifact", - "default": "com.kubukoz.playground:lsp_2.13" + "default": "com.kubukoz.playground::lsp" }, "smithyql.server.version": { "type": "string", diff --git a/vscode-extension/project/build.properties b/vscode-extension/project/build.properties deleted file mode 100644 index 563a014d..00000000 --- a/vscode-extension/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.7.2