From 39dd9ca50cfd0d6df2fb16f6f1bc071961b1a517 Mon Sep 17 00:00:00 2001 From: Dmytro Obodowsky Date: Sat, 2 Dec 2023 20:32:48 -0600 Subject: [PATCH 1/2] add cross compilation for scala 2.12 and 2.13. adjust code for both scala versions --- build.sc | 100 ++++++++++++------ modules/cli/src/runners/OpenApi.scala | 4 +- modules/cli/src/runners/Proto.scala | 3 +- .../cli/src/runners/formatter/Formatter.scala | 2 + .../src/runners/openapi/ReportResult.scala | 2 +- .../src/parsers/MetadataParser.scala | 1 - .../formatter/src/parsers/ShapeIdParser.scala | 2 +- .../formatter/src/parsers/ShapeParser.scala | 1 - .../formatter/src/parsers/SmithyParser.scala | 1 - .../src/parsers/WhitespaceParser.scala | 2 +- modules/formatter/src/writer/NodeWriter.scala | 4 +- modules/formatter/src/writer/package.scala | 1 + .../json-schema/src/JsonSchemaCompiler.scala | 2 +- .../src/internals/Extractors.scala | 5 +- modules/json-schema/tests/src/TestUtils.scala | 1 - modules/openapi/src/OpenApiCompiler.scala | 2 +- .../src/internals/ApiResponseToParams.scala | 16 ++- .../src/internals/ContentToSchemaOpt.scala | 1 + .../openapi/src/internals/GetExtensions.scala | 3 +- .../src/internals/HeadersToParams.scala | 3 +- .../src/internals/IModelPostProcessor.scala | 7 +- .../src/internals/IModelToSmithy.scala | 20 ++-- .../src/internals/OpenApiToIModel.scala | 21 ++-- .../src/internals/ParseOperations.scala | 19 ++-- .../postprocess/AllOfTransformer.scala | 34 ++++-- .../DiscriminatedTransformer.scala | 2 +- .../postprocess/NewtypeTransformer.scala | 2 +- .../postprocess/SimplifyNameTransformer.scala | 1 + .../postprocess/TaggedUnionTransformer.scala | 13 +-- modules/openapi/tests/src/TestUtils.scala | 3 +- .../src/smithyproto/proto3/Compiler.scala | 1 - .../proto3/ModelPreProcessor.scala | 21 ++-- modules/transitive/src/closure/ModelOps.scala | 5 +- .../src/closure/TransitiveModel.scala | 3 +- .../transitive/tests/src/ClosureSpec.scala | 2 +- 35 files changed, 190 insertions(+), 120 deletions(-) diff --git a/build.sc b/build.sc index 91d9237..8c2cddf 100644 --- a/build.sc +++ b/build.sc @@ -27,6 +27,8 @@ import mill.scalalib.api.ZincWorkerUtil import scala.Ordering.Implicits._ +val scalaVersions = List("2.13.12", "2.12.18") + trait BaseModule extends Module with HeaderModule { def millSourcePath: Path = { val originalRelativePath = super.millSourcePath.relativeTo(os.pwd) @@ -105,8 +107,8 @@ trait BasePublishModule extends BaseModule with CiReleaseModule { } } -trait ScalaVersionModule extends ScalaModule with ScalafmtModule { - def scalaVersion = T.input("2.13.12") +trait ScalaVersionModule extends CrossScalaModule with ScalafmtModule { +// override def scalaVersion = T.input("2.13.12") def scalacOptions = T { super.scalacOptions() ++ scalacOptionsFor(scalaVersion()) @@ -138,14 +140,14 @@ trait BaseMunitTests extends TestModule.Munit { ) } -object `json-schema` extends BaseScalaModule { - def moduleDeps = Seq( - openapi - ) +object `json-schema` extends Cross[`json-schema-module`](scalaVersions) +trait `json-schema-module` extends BaseScalaModule { + def moduleDeps = Seq(openapi()) def ivyDeps = Agg( Deps.circe.jawn, - Deps.everit.jsonSchema + Deps.everit.jsonSchema, + Deps.collectionsCompat ) object tests extends this.ScalaTests with BaseMunitTests { @@ -156,14 +158,16 @@ object `json-schema` extends BaseScalaModule { } } -object openapi extends BaseScalaModule { +object openapi extends Cross[OpenApiModule](scalaVersions) +trait OpenApiModule extends BaseScalaModule { def ivyDeps = Deps.swagger.parser ++ Agg( Deps.smithy.model, Deps.smithy.build, Deps.cats.mtl, Deps.ciString, Deps.slf4j, - Deps.alloy.core + Deps.alloy.core, + Deps.collectionsCompat ) def moduleDeps = Seq( @@ -172,12 +176,14 @@ object openapi extends BaseScalaModule { object tests extends this.ScalaTests with BaseMunitTests { def ivyDeps = super.ivyDeps() ++ Agg( - Deps.smithy.build + Deps.smithy.build, + Deps.scalaJavaCompat ) } } -object cli extends BaseScalaModule with buildinfo.BuildInfo { +object cli extends Cross[CliModule](scalaVersions) +trait CliModule extends BaseScalaModule with buildinfo.BuildInfo { def ivyDeps = Agg( Deps.decline, Deps.coursier, @@ -197,7 +203,8 @@ object cli extends BaseScalaModule with buildinfo.BuildInfo { BuildInfo.Value("cliVersion", publishVersion().toString) ) - def moduleDeps = Seq(openapi, proto.core, `json-schema`, formatter.jvm) + def moduleDeps = + Seq(openapi(), proto.core(), `json-schema`(), formatter.jvm()) def runProtoAux = T.task { (inputs: List[Path], output: Path) => val inputArgs = inputs.flatMap { p => @@ -216,10 +223,13 @@ object cli extends BaseScalaModule with buildinfo.BuildInfo { object formatter extends BaseModule { outer => val deps = Agg( - ivy"org.typelevel::cats-parse::1.0.0" + ivy"org.typelevel::cats-parse::1.0.0", + Deps.collectionsCompat ) - object jvm extends BaseScalaModule { + object jvm extends Cross[JvmModule](scalaVersions) + + trait JvmModule extends BaseScalaModule { override def ivyDeps = T { super.ivyDeps() ++ deps } override def millSourcePath = outer.millSourcePath @@ -230,8 +240,9 @@ object formatter extends BaseModule { outer => ) } - object `parser-test` extends BaseScalaNoPublishModule { - def moduleDeps = Seq(formatter.jvm) + object `parser-test` extends Cross[ParserTestModule](scalaVersions) + trait ParserTestModule extends BaseScalaNoPublishModule { + def moduleDeps = Seq(formatter.jvm()) override def millSourcePath = outer.millSourcePath / "parser-test" def ivyDeps = Agg( @@ -240,14 +251,15 @@ object formatter extends BaseModule { outer => ) } - object shaded extends BaseJavaModule { + object shaded extends ShadedModule + trait ShadedModule extends BaseJavaModule { override def millSourcePath = outer.millSourcePath / "shaded" override def localClasspath: T[Seq[PathRef]] = - formatter.jvm.localClasspath() + formatter.jvm().localClasspath() override def resolvedRunIvyDeps: T[Agg[PathRef]] = - formatter.jvm.resolvedRunIvyDeps() + formatter.jvm().resolvedRunIvyDeps() override def publishXmlDeps = T.task { Agg.empty[Dependency] } @@ -263,12 +275,12 @@ object formatter extends BaseModule { outer => object `java-api` extends BaseJavaModule { override def unmanagedClasspath = T { - super.unmanagedClasspath() ++ Agg(formatter.jvm.shaded.jar()) + super.unmanagedClasspath() ++ Agg(formatter.jvm().shaded.jar()) } override def publishXmlDeps = T.task { Agg( mill.scalalib.publish.Dependency( - formatter.jvm.shaded.publishSelfDependency(), + formatter.jvm().shaded.publishSelfDependency(), Scope.Compile ) ) @@ -277,7 +289,8 @@ object formatter extends BaseModule { outer => } } - object js extends BaseScalaJSModule { + object js extends Cross[JsModule](scalaVersions) + trait JsModule extends BaseScalaJSModule { override def ivyDeps = T { super.ivyDeps() ++ deps } override def millSourcePath = outer.millSourcePath @@ -311,14 +324,17 @@ object traits extends BaseJavaModule { ) } - object tests + object tests extends Cross[TestsModule](scalaVersions) + trait TestsModule extends JavaModuleTests with ScalaVersionModule with BaseMunitTests } -object `readme-validator` extends BaseScalaNoPublishModule { - def moduleDeps = Seq(openapi, proto.core, `json-schema`) +object `readme-validator` + extends Cross[`readme-validator-module`](scalaVersions) +trait `readme-validator-module` extends BaseScalaNoPublishModule { + def moduleDeps = Seq(openapi(), proto.core(), `json-schema`()) def ivyDeps = Agg( Deps.cats.parse, @@ -338,13 +354,14 @@ object `readme-validator` extends BaseScalaNoPublishModule { } object proto extends Module { - - object core extends BaseScalaModule { + object core extends Cross[CoreModule](scalaVersions) + trait CoreModule extends BaseScalaModule { def ivyDeps = Agg( Deps.smithy.model, - Deps.alloy.core + Deps.alloy.core, + Deps.collectionsCompat ) - def moduleDeps = Seq(traits, transitive) + def moduleDeps = Seq(traits, transitive()) object tests extends this.ScalaTests with BaseMunitTests @@ -377,7 +394,9 @@ object proto extends Module { } } - object examples extends BaseScalaModule with ScalaPBModule { + object examples extends Cross[ExamplesModule](scalaVersions) + + trait ExamplesModule extends BaseScalaModule with ScalaPBModule { def scalaPBVersion = Deps.scalapb.version def smithyFiles = T.sources { @@ -396,7 +415,7 @@ object proto extends Module { os.remove.all(cliRunOutput) os.makeDir.all(cliRunOutput) val input = smithyFiles().toList.map(_.path) - val f = cli.runProtoAux() + val f = cli().runProtoAux() f(input, cliRunOutput) cliRunOutput } @@ -409,12 +428,18 @@ object proto extends Module { } } -object transitive extends BaseScalaModule { +object transitive extends Cross[TransitiveModule](scalaVersions) +trait TransitiveModule extends BaseScalaModule { def ivyDeps = Agg( Deps.smithy.model, - Deps.smithy.build + Deps.smithy.build, + Deps.collectionsCompat ) - object tests extends ScalaTests with BaseMunitTests + object tests extends ScalaTests with BaseMunitTests { + def ivyDeps = super.ivyDeps() ++ Agg( + Deps.scalaJavaCompat + ) + } } object Deps { @@ -454,6 +479,11 @@ object Deps { val ujson = ivy"com.lihaoyi::ujson:3.1.3" } + val collectionsCompat = + ivy"org.scala-lang.modules::scala-collection-compat:2.11.0" + + val scalaJavaCompat = ivy"org.scala-lang.modules::scala-java8-compat:1.0.2" + val munitVersion = "1.0.0-M10" object grpc { val version = "1.59.1" @@ -557,7 +587,7 @@ private val allScalacOptions = Seq( ScalacOption("-Wunused:implicits", isSupported = version => v213 <= version && version < v300), // ^ Replaces the above ScalacOption("-Wunused:explicits", isSupported = version => v213 <= version && version < v300), // Warn if an explicit parameter is unused. ScalacOption("-Ywarn-unused:imports", isSupported = version => v212 <= version && version < v213), // Warn if an import selector is not referenced. - ScalacOption("-Wunused:imports", isSupported = version => v213 <= version && version < v300), // ^ Replaces the above +// ScalacOption("-Wunused:imports", isSupported = version => v213 <= version && version < v300), // ^ Replaces the above ScalacOption("-Ywarn-unused:locals", isSupported = version => v212 <= version && version < v213), // Warn if a local definition is unused. ScalacOption("-Wunused:locals", isSupported = version => v213 <= version && version < v300), // ^ Replaces the above ScalacOption("-Ywarn-unused:params", isSupported = version => v212 <= version && version < v213), // Warn if a value parameter is unused. diff --git a/modules/cli/src/runners/OpenApi.scala b/modules/cli/src/runners/OpenApi.scala index df14c5a..b4bace0 100644 --- a/modules/cli/src/runners/OpenApi.scala +++ b/modules/cli/src/runners/OpenApi.scala @@ -24,7 +24,7 @@ object OpenApi { def runOpenApi(opts: OpenAPIJsonSchemaOpts): Unit = { val transformers = TransformerLookup.getAll() - val report = ReportResult(opts.outputPath, opts.outputJson).apply + val report = ReportResult(opts.outputPath, opts.outputJson).apply _ report( ParseAndCompile.openapi( @@ -42,7 +42,7 @@ object OpenApi { def runJsonSchema(opts: OpenAPIJsonSchemaOpts): Unit = { val transformers = TransformerLookup.getAll() - val report = ReportResult(opts.outputPath, opts.outputJson).apply + val report = ReportResult(opts.outputPath, opts.outputJson).apply _ report( ParseAndCompile.jsonSchema( opts.inputFiles, diff --git a/modules/cli/src/runners/Proto.scala b/modules/cli/src/runners/Proto.scala index cf31110..dc4a3cb 100644 --- a/modules/cli/src/runners/Proto.scala +++ b/modules/cli/src/runners/Proto.scala @@ -125,7 +125,8 @@ private object Deps { .assemble() .unwrap() - modelBuilder.addShapes(upstreamModel): Unit + modelBuilder.addShapes(upstreamModel) + () } } } diff --git a/modules/cli/src/runners/formatter/Formatter.scala b/modules/cli/src/runners/formatter/Formatter.scala index 08f944c..55b7091 100644 --- a/modules/cli/src/runners/formatter/Formatter.scala +++ b/modules/cli/src/runners/formatter/Formatter.scala @@ -33,6 +33,8 @@ import software.amazon.smithy.model.Model import scala.util.Try +import scala.collection.compat._ + object Formatter { def run(formatOpts: FormatOpts): Unit = { diff --git a/modules/cli/src/runners/openapi/ReportResult.scala b/modules/cli/src/runners/openapi/ReportResult.scala index 59ddf49..b35803e 100644 --- a/modules/cli/src/runners/openapi/ReportResult.scala +++ b/modules/cli/src/runners/openapi/ReportResult.scala @@ -72,7 +72,7 @@ final case class ReportResult(outputPath: os.Path, outputJson: Boolean) { ".smithy" ) // convert e.g. my.namespace.test.smithy to my/namespace/test.smithy val path = outputPath / os.SubPath(subPath) - path -> in._2 + (path, os.Source.WritableSource(in._2)) } def apply(result: OpenApiCompiler.Result[Model], debug: Boolean): Unit = { diff --git a/modules/formatter/src/parsers/MetadataParser.scala b/modules/formatter/src/parsers/MetadataParser.scala index 3e4aa14..e774e90 100644 --- a/modules/formatter/src/parsers/MetadataParser.scala +++ b/modules/formatter/src/parsers/MetadataParser.scala @@ -20,7 +20,6 @@ import smithytranslate.formatter.parsers.NodeParser.{ node_object_key, node_value } -import smithytranslate.formatter.parsers.equal import smithytranslate.formatter.parsers.WhitespaceParser.{br, sp, sp0} import cats.parse.{Parser, Parser0} import smithytranslate.formatter.ast.MetadataStatement diff --git a/modules/formatter/src/parsers/ShapeIdParser.scala b/modules/formatter/src/parsers/ShapeIdParser.scala index a9c7db4..f7a846d 100644 --- a/modules/formatter/src/parsers/ShapeIdParser.scala +++ b/modules/formatter/src/parsers/ShapeIdParser.scala @@ -45,7 +45,7 @@ object ShapeIdParser { .map(Namespace.tupled) val absolute_root_shape_id: Parser[AbsoluteRootShapeId] = ((namespace <* Parser.char('#')) ~ identifier) - .map(AbsoluteRootShapeId.apply.tupled) + .map { case (ns, id) => AbsoluteRootShapeId.apply(ns, id) } val root_shape_id: Parser[RootShapeId] = absolute_root_shape_id.backtrack .eitherOr(identifier) diff --git a/modules/formatter/src/parsers/ShapeParser.scala b/modules/formatter/src/parsers/ShapeParser.scala index 65a949e..b6db292 100644 --- a/modules/formatter/src/parsers/ShapeParser.scala +++ b/modules/formatter/src/parsers/ShapeParser.scala @@ -48,7 +48,6 @@ import smithytranslate.formatter.ast.shapes.ShapeStatementsCase.{ ApplyStatementCase, ShapeStatementCase } -import smithytranslate.formatter.parsers.equal import smithytranslate.formatter.parsers.WhitespaceParser.{br, sp, sp0, ws} import smithytranslate.formatter.parsers.NodeParser._ import smithytranslate.formatter.parsers.ShapeIdParser._ diff --git a/modules/formatter/src/parsers/SmithyParser.scala b/modules/formatter/src/parsers/SmithyParser.scala index 22f73bb..a30c700 100644 --- a/modules/formatter/src/parsers/SmithyParser.scala +++ b/modules/formatter/src/parsers/SmithyParser.scala @@ -17,7 +17,6 @@ package formatter package parsers import smithytranslate.formatter.ast.Idl -import smithytranslate.formatter.parsers.IdlParser import cats.syntax.all._ trait SmithyParser { diff --git a/modules/formatter/src/parsers/WhitespaceParser.scala b/modules/formatter/src/parsers/WhitespaceParser.scala index 0364617..d4e038c 100644 --- a/modules/formatter/src/parsers/WhitespaceParser.scala +++ b/modules/formatter/src/parsers/WhitespaceParser.scala @@ -42,7 +42,7 @@ object WhitespaceParser { val commentType: Parser[CommentType] = documentation_comment.backtrack | line_comment val comment: Parser[Comment] = - (commentType ~ not_newline <* nl).map(Comment.apply.tupled) + (commentType ~ not_newline <* nl).map { case (a, b) => Comment.apply(a, b) } private val commentOrNewline: Parser[Option[Comment]] = comment.eitherOr(nl).map(_.toOption) diff --git a/modules/formatter/src/writer/NodeWriter.scala b/modules/formatter/src/writer/NodeWriter.scala index c193c81..e9cba14 100644 --- a/modules/formatter/src/writer/NodeWriter.scala +++ b/modules/formatter/src/writer/NodeWriter.scala @@ -136,7 +136,7 @@ object NodeWriter { } implicit val quotedTextWriter: Writer[QuotedText] = Writer.write { case QuotedText(text) => - s"\"${text.map(_.write).mkString}\"" + s"""\"${text.map(_.write).mkString}\"""" } implicit val textBlockContentWriter: Writer[TextBlockContent] = Writer.write { case TextBlockContent(quotes, text) => @@ -144,7 +144,7 @@ object NodeWriter { } implicit val textBlockWriter: Writer[TextBlock] = Writer.write { case TextBlock(text) => - s"\"\"\"\n${text.writeN}\"\"\"" + s"""\"\"\"\n${text.writeN}\"\"\"""" } implicit val fracWriter: Writer[Frac] = Writer.write { case Frac(frac) => s".${frac.write}" diff --git a/modules/formatter/src/writer/package.scala b/modules/formatter/src/writer/package.scala index eedbc2a..8925c83 100644 --- a/modules/formatter/src/writer/package.scala +++ b/modules/formatter/src/writer/package.scala @@ -22,6 +22,7 @@ import smithytranslate.formatter.writers.NodeWriter.{ } import smithytranslate.formatter.writers.WhiteSpaceWriter.wsWriter import smithytranslate.formatter.writers.Writer.WriterOps +import scala.collection.compat._ package object writers { val traitKeyValueLimitLength = 80 diff --git a/modules/json-schema/src/JsonSchemaCompiler.scala b/modules/json-schema/src/JsonSchemaCompiler.scala index 61e4c7f..b75e3ba 100644 --- a/modules/json-schema/src/JsonSchemaCompiler.scala +++ b/modules/json-schema/src/JsonSchemaCompiler.scala @@ -70,7 +70,7 @@ object JsonSchemaCompiler { inputs: Input* ): Result[SmithyModel] = { val (errors0, smithy0) = inputs.toList - .foldMap(JsonSchemaToIModel.compile.tupled) + .foldMap { case (ns, s, raw) => JsonSchemaToIModel.compile(ns, s, raw) } .map(IModelPostProcessor(opts.useVerboseNames)) .map(new IModelToSmithy(opts.useEnumTraitSyntax)) val errors = errors0.toList diff --git a/modules/json-schema/src/internals/Extractors.scala b/modules/json-schema/src/internals/Extractors.scala index 44a3c06..c892d88 100644 --- a/modules/json-schema/src/internals/Extractors.scala +++ b/modules/json-schema/src/internals/Extractors.scala @@ -27,6 +27,7 @@ import smithytranslate.openapi.internals.Hint import smithytranslate.openapi.internals.GetExtensions import scala.jdk.CollectionConverters._ import cats.syntax.all._ +import scala.collection.compat._ object Extractors { @@ -54,7 +55,7 @@ object Extractors { } private def getValues(e: EnumSchema): Vector[String] = { - e.getPossibleValues.asScala.collect { case s: String => + e.getPossibleValuesAsList.asScala.collect { case s: String => s }.toVector } @@ -278,7 +279,7 @@ object Extractors { def getExtensions(): java.util.Map[String, Any] = Option(schema.getUnprocessedProperties()) .map { _.asScala.view.filterKeys(_.startsWith("x-")).toMap } - .getOrElse(Map.empty) + .getOrElse(Map.empty[String, Any]) .asJava } diff --git a/modules/json-schema/tests/src/TestUtils.scala b/modules/json-schema/tests/src/TestUtils.scala index 5356531..0922752 100644 --- a/modules/json-schema/tests/src/TestUtils.scala +++ b/modules/json-schema/tests/src/TestUtils.scala @@ -59,7 +59,6 @@ object TestUtils { ), inputs.map(i => i.filePath -> i.jsonSpec): _* ) - val resultW = result.map(ModelWrapper(_)) val assembler = Model diff --git a/modules/openapi/src/OpenApiCompiler.scala b/modules/openapi/src/OpenApiCompiler.scala index f919bba..de8008d 100644 --- a/modules/openapi/src/OpenApiCompiler.scala +++ b/modules/openapi/src/OpenApiCompiler.scala @@ -148,7 +148,7 @@ object OpenApiCompiler { ): Result[SmithyModel] = { val (errors0, smithy0) = inputs.toList .map(_.leftMap(NonEmptyChain.fromNonEmptyList)) - .foldMap(OpenApiToIModel.compile.tupled) + .foldMap { case (c, e) => OpenApiToIModel.compile(c, e) } .map(IModelPostProcessor(opts.useVerboseNames)) .map(new IModelToSmithy(opts.useEnumTraitSyntax)) val errors = errors0.toList diff --git a/modules/openapi/src/internals/ApiResponseToParams.scala b/modules/openapi/src/internals/ApiResponseToParams.scala index 8b9a81e..36be7ea 100644 --- a/modules/openapi/src/internals/ApiResponseToParams.scala +++ b/modules/openapi/src/internals/ApiResponseToParams.scala @@ -15,7 +15,10 @@ package smithytranslate.openapi.internals +import io.swagger.v3.oas.models.media.Schema import io.swagger.v3.oas.models.responses.ApiResponse +import smithytranslate.openapi.internals.GetExtensions.HasExtensions + import scala.jdk.CollectionConverters._ object ApiResponseToParams @@ -32,9 +35,11 @@ object ApiResponseToParams response.getContent() ).toList bodies.toList match { - case Nil => None - case (contentType, bodySchema) :: Nil => - val bodyExts = GetExtensions.from(bodySchema) + case Nil => None + case (contentType, bodySchema: Schema[_]) :: Nil => + // TODO: figure out how to deal with reflective calls in scala 2.12 + val bodyExts = + GetExtensions.from(bodySchema.asInstanceOf[HasExtensions]) Some( Param( "body", @@ -48,7 +53,8 @@ object ApiResponseToParams ) case list => val bodySchema = ContentTypeDiscriminatedSchema(list.toMap) - val bodyExts = GetExtensions.from(bodySchema) + val bodyExts = + GetExtensions.from(bodySchema.asInstanceOf[HasExtensions]) Some( Param( "body", @@ -65,7 +71,7 @@ object ApiResponseToParams maybeRef match { case Some(ref) => Left(ref) case None => - val exts = GetExtensions.from(response) + val exts = GetExtensions.from(response.asInstanceOf[HasExtensions]) val httpMessageInfo = HttpMessageInfo(opName, allParams, exts) Right(httpMessageInfo) } diff --git a/modules/openapi/src/internals/ContentToSchemaOpt.scala b/modules/openapi/src/internals/ContentToSchemaOpt.scala index d8ecb4c..5eacd31 100644 --- a/modules/openapi/src/internals/ContentToSchemaOpt.scala +++ b/modules/openapi/src/internals/ContentToSchemaOpt.scala @@ -18,6 +18,7 @@ package smithytranslate.openapi.internals import io.swagger.v3.oas.models.media.Schema import scala.jdk.CollectionConverters._ import io.swagger.v3.oas.models.media.Content +import scala.collection.compat._ object ContentToSchemaOpt extends (Content => Map[String, Schema[_]]) { diff --git a/modules/openapi/src/internals/GetExtensions.scala b/modules/openapi/src/internals/GetExtensions.scala index 65ab214..8045668 100644 --- a/modules/openapi/src/internals/GetExtensions.scala +++ b/modules/openapi/src/internals/GetExtensions.scala @@ -17,7 +17,6 @@ package smithytranslate.openapi.internals import software.amazon.smithy.model.node.Node import scala.jdk.CollectionConverters._ -import smithytranslate.openapi.internals.OpenApiPattern import scala.language.reflectiveCalls import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.{node => jackson} @@ -29,7 +28,7 @@ object GetExtensions { def transformPattern[A]( local: Local ): OpenApiPattern[A] => OpenApiPattern[A] = { - val maybeHints = from(local.schema) + val maybeHints = from(local.schema.asInstanceOf[HasExtensions]) (pattern: OpenApiPattern[A]) => pattern.mapContext(_.addHints(maybeHints, retainTopLevel = true)) } diff --git a/modules/openapi/src/internals/HeadersToParams.scala b/modules/openapi/src/internals/HeadersToParams.scala index 9cbc935..b3700fa 100644 --- a/modules/openapi/src/internals/HeadersToParams.scala +++ b/modules/openapi/src/internals/HeadersToParams.scala @@ -16,6 +16,7 @@ package smithytranslate.openapi.internals import io.swagger.v3.oas.models.headers.Header +import smithytranslate.openapi.internals.GetExtensions.HasExtensions object HeadersToParams extends (Iterable[(String, Header)] => Vector[Param]) { @@ -25,7 +26,7 @@ object HeadersToParams extends (Iterable[(String, Header)] => Vector[Param]) { Option(headerMap).toVector.flatten.map { case (name, header) => val requiredHint = if (header.getRequired()) List(Hint.Required) else List.empty - val exts = GetExtensions.from(header) + val exts = GetExtensions.from(header.asInstanceOf[HasExtensions]) val hints = List(Hint.Header(name)) ++ requiredHint ++ exts val refOrSchema = Option(header.get$ref()) match { case Some(value) => Left(value) diff --git a/modules/openapi/src/internals/IModelPostProcessor.scala b/modules/openapi/src/internals/IModelPostProcessor.scala index 189fede..49b0f06 100644 --- a/modules/openapi/src/internals/IModelPostProcessor.scala +++ b/modules/openapi/src/internals/IModelPostProcessor.scala @@ -36,8 +36,11 @@ object IModelPostProcessor { private[this] def transform( in: IModel, allTransformers: List[IModelPostProcessor] - ): IModel = - allTransformers.foldLeft(in)((vd, transformer) => transformer(vd)) + ): IModel = { + allTransformers.foldLeft(in) { (model, transformer) => + transformer(model) + } + } def apply(useVerboseNames: Boolean)(in: IModel): IModel = { val nameTransform = diff --git a/modules/openapi/src/internals/IModelToSmithy.scala b/modules/openapi/src/internals/IModelToSmithy.scala index cdb9ff4..a3221ac 100644 --- a/modules/openapi/src/internals/IModelToSmithy.scala +++ b/modules/openapi/src/internals/IModelToSmithy.scala @@ -27,18 +27,17 @@ import smithytranslate.ContentTypeDiscriminatedTrait import smithytranslate.ContentTypeTrait import smithytranslate.ErrorMessageTrait import smithytranslate.NullFormatTrait -import smithytranslate.openapi.internals.ApiKeyLocation import smithytranslate.openapi.internals.Hint.Header import smithytranslate.openapi.internals.Hint.QueryParam -import smithytranslate.openapi.internals.SecurityScheme import smithytranslate.openapi.internals.TimestampFormat.DateTime import smithytranslate.openapi.internals.TimestampFormat.SimpleDate import software.amazon.smithy.model.Model import software.amazon.smithy.model.node.Node import software.amazon.smithy.model.pattern.UriPattern -import software.amazon.smithy.model.shapes.{EnumShape, _} import software.amazon.smithy.model.traits._ import software.amazon.smithy.model.traits.HttpTrait +import software.amazon.smithy.model.shapes._ +import software.amazon.smithy.model.shapes.{Shape => JShape} import scala.jdk.CollectionConverters._ @@ -46,7 +45,7 @@ final class IModelToSmithy(useEnumTraitSyntax: Boolean) extends (IModel => Model) { def apply(iModel: IModel): Model = { - val shapes = iModel.definitions.map[Shape] { + val shapes = iModel.definitions.map { case Structure(id, fields, _, structHints) => val members = fields.map { case Field(id, tpe, hints) => val memName = id.memberName.value.toString @@ -60,6 +59,12 @@ final class IModelToSmithy(useEnumTraitSyntax: Boolean) if (nameWillNeedChange && !isHeaderOrQuery) List(Hint.JsonName(memName)) else List.empty + +// ShapeBuilderOps[MemberShape.Builder, MemberShape](MemberShape +// .builder() +// .id(id.toSmithy) +// .target(tpe.toSmithy)).addHints(hints ++ jsonNameHint).build() + MemberShape .builder() .id(id.toSmithy) @@ -170,7 +175,6 @@ final class IModelToSmithy(useEnumTraitSyntax: Boolean) case other => throw new IllegalArgumentException(s"Unexpected input: $other") } - val builder = Model.builder() if (iModel.suppressions.nonEmpty) { builder.putMetadataProperty("suppressions", iModel.suppressions.toNode) @@ -179,7 +183,7 @@ final class IModelToSmithy(useEnumTraitSyntax: Boolean) builder.build() } - private def buildEnum(e: Enumeration): Shape = { + private def buildEnum(e: Enumeration): JShape = { val Enumeration(id, values, hints) = e if (useEnumTraitSyntax) { val enumTraitBuilder = EnumTrait.builder(): @annotation.nowarn( @@ -298,7 +302,7 @@ final class IModelToSmithy(useEnumTraitSyntax: Boolean) } } - private def hintsToTraits(hints: List[Hint]) = hints.flatMap[Trait] { + private def hintsToTraits(hints: List[Hint]) = hints.flatMap { case Hint.Description(value) => List(new DocumentationTrait(value)) case Hint.Body => List(new HttpPayloadTrait()) case Hint.Header(name) => List(new HttpHeaderTrait(name)) @@ -395,7 +399,7 @@ final class IModelToSmithy(useEnumTraitSyntax: Boolean) case _ => List.empty } - implicit class ShapeBuilderOps[A <: AbstractShapeBuilder[A, S], S <: Shape]( + implicit class ShapeBuilderOps[A <: AbstractShapeBuilder[A, S], S <: JShape]( builder: AbstractShapeBuilder[A, S] ) { def addHints(hints: List[Hint]): A = { diff --git a/modules/openapi/src/internals/OpenApiToIModel.scala b/modules/openapi/src/internals/OpenApiToIModel.scala index 0bee97b..27edc84 100644 --- a/modules/openapi/src/internals/OpenApiToIModel.scala +++ b/modules/openapi/src/internals/OpenApiToIModel.scala @@ -20,6 +20,7 @@ import cats.Parallel import cats.mtl.Tell import io.swagger.v3.oas.models.OpenAPI import io.swagger.v3.oas.models.media._ + import scala.jdk.CollectionConverters._ import cats.data._ import Primitive._ @@ -27,6 +28,7 @@ import cats.syntax.all._ import ModelError._ import cats.Monad import org.typelevel.ci._ +import smithytranslate.openapi.internals.GetExtensions.HasExtensions object OpenApiToIModel { @@ -362,7 +364,7 @@ private class OpenApiToIModel[F[_]: Parallel: TellShape: TellError]( private def recordService(opDefIds: Vector[DefId]): F[Unit] = { val security = Option(openApi.getSecurity()) - .map(_.asScala) + .map(_.asScala.toSet) .getOrElse(Set.empty) .flatMap(_.keySet().asScala) val auth = security.flatMap(securitySchemes.get).toVector @@ -370,8 +372,9 @@ private class OpenApiToIModel[F[_]: Parallel: TellShape: TellError]( val schemes = securitySchemes.values.toVector val securityHint = if (schemes.nonEmpty) List(Hint.Security(schemes)) else Nil - val exts = GetExtensions.from(openApi) - val infoExts = GetExtensions.from(openApi.getInfo()) + val exts = GetExtensions.from(openApi.asInstanceOf[HasExtensions]) + val infoExts = + GetExtensions.from(openApi.getInfo().asInstanceOf[HasExtensions]) val externalDocs = Option(openApi.getExternalDocs()).map(e => Hint.ExternalDocs(Option(e.getDescription()), e.getUrl()) ) @@ -619,13 +622,13 @@ private class OpenApiToIModel[F[_]: Parallel: TellShape: TellError]( val externalDocs = getExternalDocsHint(local.schema) val hints = List( - length, - range, - pattern, - sensitive, + length.toList, + range.toList, + pattern.toList, + sensitive.toList, topLevel, - examples, - externalDocs + examples.toList, + externalDocs.toList ).flatten val errors = List(rangeError).flatten (hints, errors) diff --git a/modules/openapi/src/internals/ParseOperations.scala b/modules/openapi/src/internals/ParseOperations.scala index c802337..2907e13 100644 --- a/modules/openapi/src/internals/ParseOperations.scala +++ b/modules/openapi/src/internals/ParseOperations.scala @@ -21,9 +21,13 @@ import cats.syntax.all._ import io.swagger.v3.oas.models import io.swagger.v3.oas.models.OpenAPI import org.typelevel.ci._ +import smithytranslate.openapi.internals.GetExtensions.HasExtensions + import scala.jdk.CollectionConverters._ import smithytranslate.openapi.internals.Hint.Header +import scala.collection.compat._ + object ParseOperations extends ( ( @@ -77,7 +81,8 @@ private class ParseOperationsImpl( Option(item.getParameters()).toVector .flatMap(_.asScala.toVector) .map(getParam) - val (paramErrors, commonParams) = allCommonParams.partitionMap(identity) + val (paramErrors, commonParams) = + allCommonParams.partitionMap(identity(_)) ( paramErrors, Vector( @@ -95,8 +100,8 @@ private class ParseOperationsImpl( ) } - val allOperations = opsAndErrors.collect { _._2 }.flatten - val allParamErrrs = opsAndErrors.collect { _._1 }.flatten + val allOperations = opsAndErrors.collect { case (_, x) => x }.flatten + val allParamErrrs = opsAndErrors.collect { case (x, _) => x }.flatten val hasGlobalSecurity = Option(openApi.getSecurity().asScala).exists(_.nonEmpty) @@ -186,7 +191,9 @@ private class ParseOperationsImpl( Hint.ExternalDocs(Option(e.getDescription()), e.getUrl()) ) val hints = - GetExtensions.from(opInfo.op) ++ securityHint ++ descHint ++ exDocs + GetExtensions.from( + opInfo.op.asInstanceOf[HasExtensions] + ) ++ securityHint ++ descHint ++ exDocs val suppressions = getHeaderSuppressions(allValidInputParams).toVector ParseOperationsResult( errors ++ allInputParamsErrors, @@ -245,7 +252,7 @@ private class ParseOperationsImpl( Option( op.getRequestBody() ).flatMap { rb => - val exts = GetExtensions.from(rb) + val exts = GetExtensions.from(rb.asInstanceOf[HasExtensions]) val bodies = ContentToSchemaOpt(rb.getContent()) val (bodyHints, maybeSchema) = bodies.toList match { @@ -288,7 +295,7 @@ private class ParseOperationsImpl( maybeResolvedParam.flatMap { resolvedParam => val name = resolvedParam.getName() - val exts = GetExtensions.from(resolvedParam) + val exts = GetExtensions.from(resolvedParam.asInstanceOf[HasExtensions]) val httpBinding = resolvedParam.getIn() match { case "query" => Some(Hint.QueryParam(name)) case "path" => Some(Hint.PathParam(name)) diff --git a/modules/openapi/src/internals/postprocess/AllOfTransformer.scala b/modules/openapi/src/internals/postprocess/AllOfTransformer.scala index f2dd159..d7a6cbc 100644 --- a/modules/openapi/src/internals/postprocess/AllOfTransformer.scala +++ b/modules/openapi/src/internals/postprocess/AllOfTransformer.scala @@ -143,7 +143,12 @@ object AllOfTransformer extends IModelPostProcessor { all: Vector[Definition] ): Vector[Definition] = { val allShapes: mutable.LinkedHashMap[DefId, Definition] = - mutable.LinkedHashMap.from(all.map(a => a.id -> a)) + all + .map(a => a.id -> a) + .foldLeft(new mutable.LinkedHashMap[DefId, Definition]()) { + case (acc, (id, shape)) => + acc += (id -> shape) + } all.foreach { d => // get latest in case modifications have been made to this definition since the @@ -192,26 +197,37 @@ object AllOfTransformer extends IModelPostProcessor { case other => Vector(other) } } - removeUnusedMixins(allShapes).values.toVector + + removeUnusedMixins(allShapes) } private def removeUnusedMixins( allShapes: mutable.Map[DefId, Definition] - ): mutable.Map[DefId, Definition] = { - val usedAsMixins: Set[DefId] = allShapes.values.flatMap { v => + ): Vector[Definition] = { + val values = allShapes.values.foldLeft(Vector.empty[Structure]) { + case (acc, s: Structure) => + acc :+ s + case (acc, _) => acc + } + val usedAsMixins: Set[DefId] = values.flatMap { v => v.hints.collect { case Hint.HasMixin(id) => id } }.toSet - val isAMixin: Set[DefId] = allShapes.values.flatMap { v => + val isAMixin: Set[DefId] = values.flatMap { v => v.hints.collect { case Hint.IsMixin => v.id } }.toSet val unused = isAMixin.diff(usedAsMixins) - allShapes.map { case (id, shp) => - if (unused(id)) id -> shp.mapHints(_.filterNot(_ == Hint.IsMixin)) - else id -> shp - } + allShapes + .foldLeft(new mutable.LinkedHashMap[DefId, Definition]()) { + case (acc, (id, shp)) => + acc += (if (unused(id)) + (id, shp.mapHints(_.filterNot(_ == Hint.IsMixin))) + else (id, shp)) + } + .values + .toVector } private def transform(in: IModel): Vector[Definition] = { diff --git a/modules/openapi/src/internals/postprocess/DiscriminatedTransformer.scala b/modules/openapi/src/internals/postprocess/DiscriminatedTransformer.scala index bb2be66..910f819 100644 --- a/modules/openapi/src/internals/postprocess/DiscriminatedTransformer.scala +++ b/modules/openapi/src/internals/postprocess/DiscriminatedTransformer.scala @@ -44,7 +44,7 @@ object DiscriminatedTransformer extends IModelPostProcessor { u.altNames.exists(alt => definition.id == alt.tpe) def apply(in: IModel): IModel = { - val unionInfo = in.definitions.flatMap(getUnionInfo.lift) + val unionInfo = in.definitions.flatMap(x => getUnionInfo.lift(x).toList) val newDefs = in.definitions .map { definition => unionInfo diff --git a/modules/openapi/src/internals/postprocess/NewtypeTransformer.scala b/modules/openapi/src/internals/postprocess/NewtypeTransformer.scala index 517cb45..1ee204d 100644 --- a/modules/openapi/src/internals/postprocess/NewtypeTransformer.scala +++ b/modules/openapi/src/internals/postprocess/NewtypeTransformer.scala @@ -36,7 +36,7 @@ object NewtypeTransformer extends IModelPostProcessor { def apply(model: IModel): IModel = { val newtypes = model.definitions.collect { case Newtype(id, target, hints) => - id -> (target, hints) + (id, (target, hints)) }.toMap @tailrec diff --git a/modules/openapi/src/internals/postprocess/SimplifyNameTransformer.scala b/modules/openapi/src/internals/postprocess/SimplifyNameTransformer.scala index 9afc19c..24319c3 100644 --- a/modules/openapi/src/internals/postprocess/SimplifyNameTransformer.scala +++ b/modules/openapi/src/internals/postprocess/SimplifyNameTransformer.scala @@ -19,6 +19,7 @@ package postprocess import cats.data.NonEmptyChain import cats.syntax.all._ import org.typelevel.ci._ +import scala.collection.compat._ object SimplifyNameTransformer extends IModelPostProcessor { diff --git a/modules/openapi/src/internals/postprocess/TaggedUnionTransformer.scala b/modules/openapi/src/internals/postprocess/TaggedUnionTransformer.scala index 83f1834..cb66baa 100644 --- a/modules/openapi/src/internals/postprocess/TaggedUnionTransformer.scala +++ b/modules/openapi/src/internals/postprocess/TaggedUnionTransformer.scala @@ -16,6 +16,8 @@ package smithytranslate.openapi.internals package postprocess +import scala.collection.compat._ + object TaggedUnionTransformer extends IModelPostProcessor { private case class TaggedUnionInfo( @@ -57,9 +59,9 @@ object TaggedUnionTransformer extends IModelPostProcessor { val singleLocal = allFields.size == 1 val allLocalRequired = allFields.forall(_.hints.contains(Hint.Required)) - if (singleLocal && allLocalRequired) + if (singleLocal && allLocalRequired) { info.addFields(allFields) - else info.setNotTagged + } else info.setNotTagged } } @@ -74,7 +76,7 @@ object TaggedUnionTransformer extends IModelPostProcessor { private def transform(in: IModel): Vector[Definition] = { val toUpdate = - in.definitions.flatMap { + in.definitions.collect { case u @ Union(id, altNames, UnionKind.Untagged, _) => val info = getTaggedUnionInfo(altNames, in.definitions) val taggedFields = info.taggedFields @@ -92,7 +94,7 @@ object TaggedUnionTransformer extends IModelPostProcessor { ) ) ) - Set(newUnion) + newUnion } else { val newUnion = u.copy( alts = u.alts.map(alt => @@ -101,9 +103,8 @@ object TaggedUnionTransformer extends IModelPostProcessor { ) ) ) - Set(newUnion) + newUnion } - case _ => Set.empty } val toAddMap = toUpdate.map(d => d.id -> d).toMap in.definitions diff --git a/modules/openapi/tests/src/TestUtils.scala b/modules/openapi/tests/src/TestUtils.scala index cafb9e1..8ea2acf 100644 --- a/modules/openapi/tests/src/TestUtils.scala +++ b/modules/openapi/tests/src/TestUtils.scala @@ -23,7 +23,6 @@ import software.amazon.smithy.build.transforms.FilterSuppressions import software.amazon.smithy.build.TransformContext import cats.syntax.all._ import munit.Location -import smithytranslate.openapi.OpenApiCompiler import cats.data.NonEmptyList import software.amazon.smithy.model.node._ import smithytranslate.openapi.OpenApiCompiler.SmithyVersion @@ -33,7 +32,7 @@ import software.amazon.smithy.model.transform.ModelTransformer import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.model.traits.Trait import software.amazon.smithy.model.traits.BoxTrait -import scala.jdk.FunctionConverters._ +import scala.compat.java8.FunctionConverters._ object TestUtils { diff --git a/modules/proto/core/src/smithyproto/proto3/Compiler.scala b/modules/proto/core/src/smithyproto/proto3/Compiler.scala index 537e527..6ead37f 100644 --- a/modules/proto/core/src/smithyproto/proto3/Compiler.scala +++ b/modules/proto/core/src/smithyproto/proto3/Compiler.scala @@ -69,7 +69,6 @@ class Compiler() { def compile(model: Model): List[OutputFile] = { val allProtocOptions = MetadataProcessor.extractProtocOptions(model) - model.toShapeSet.toList .filterNot(ShapeFiltering.exclude) .groupBy(_.getId().getNamespace()) diff --git a/modules/proto/core/src/smithyproto/proto3/ModelPreProcessor.scala b/modules/proto/core/src/smithyproto/proto3/ModelPreProcessor.scala index 50ce1e5..8ed178d 100644 --- a/modules/proto/core/src/smithyproto/proto3/ModelPreProcessor.scala +++ b/modules/proto/core/src/smithyproto/proto3/ModelPreProcessor.scala @@ -16,7 +16,6 @@ package smithyproto.proto3 import java.util.stream.Collectors - import smithytranslate.closure.TransitiveModel import smithytranslate.UUID import software.amazon.smithy.build.{ProjectionTransformer, TransformContext} @@ -24,7 +23,9 @@ import software.amazon.smithy.model.Model import software.amazon.smithy.model.loader.Prelude import software.amazon.smithy.model.shapes._ -import scala.jdk.CollectionConverters.* +import java.util +import scala.jdk.CollectionConverters._ +import scala.collection.compat._ object ModelPreProcessor { @@ -72,9 +73,9 @@ object ModelPreProcessor { private val preludeModel = Model.assembler().assemble().unwrap() private val addIfUsed = Map( // format: off - classOf[BigIntegerShape] -> (smithytranslate.BigInteger.shape, smithytranslate.BigInteger.target), - classOf[BigDecimalShape] -> (smithytranslate.BigDecimal.shape, smithytranslate.BigDecimal.target), - classOf[TimestampShape] -> (smithytranslate.Timestamp.shape, smithytranslate.Timestamp.target) + (classOf[BigIntegerShape], (smithytranslate.BigInteger.shape, smithytranslate.BigInteger.target)), + (classOf[BigDecimalShape], (smithytranslate.BigDecimal.shape, smithytranslate.BigDecimal.target)), + (classOf[TimestampShape], (smithytranslate.Timestamp.shape, smithytranslate.Timestamp.target)) // format: on ) @@ -240,7 +241,7 @@ object ModelPreProcessor { .getAllMembers() .values() .stream() - .map(updateMember) + .map[MemberShape](updateMember) .collect(Collectors.toList()) ) .build() @@ -254,7 +255,7 @@ object ModelPreProcessor { .getAllMembers() .values() .stream() - .map(updateMember) + .map[MemberShape](updateMember) .collect(Collectors.toList()) ) .build() @@ -280,14 +281,14 @@ object ModelPreProcessor { .filter { _.getTarget() == uuidShapeId } .count() if (uuidUsage > 0) { - val updatedShapes = x + val updatedShapes: util.List[Shape] = x .getModel() .toSet() .stream() // remove reference to alloy#UUID .filter(_.getId() != uuidShapeId) - .map { _shape => - _shape.accept(updateMemberShapes) + .map[Shape] { _shape => + _shape.accept[Shape](updateMemberShapes) } .collect(Collectors.toList()) Model diff --git a/modules/transitive/src/closure/ModelOps.scala b/modules/transitive/src/closure/ModelOps.scala index 96bf504..f4aebed 100644 --- a/modules/transitive/src/closure/ModelOps.scala +++ b/modules/transitive/src/closure/ModelOps.scala @@ -15,12 +15,12 @@ package smithytranslate.closure -import smithytranslate.closure.TransitiveModel import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.{Shape, ShapeId} import scala.jdk.CollectionConverters._ import scala.collection.SortedSet +import scala.collection.immutable.TreeSet object ModelOps { implicit class ModelOps(model: Model) { @@ -40,8 +40,7 @@ object ModelOps { implicit val shapeOrdering: Ordering[Shape] = Ordering[Location].on[Shape](loc) - - SortedSet.from(model.shapes().iterator().asScala) + model.shapes().iterator().asScala.foldLeft(new TreeSet[Shape])(_ + _) } def debug: Model = { diff --git a/modules/transitive/src/closure/TransitiveModel.scala b/modules/transitive/src/closure/TransitiveModel.scala index 27c00b8..2f7cd8d 100644 --- a/modules/transitive/src/closure/TransitiveModel.scala +++ b/modules/transitive/src/closure/TransitiveModel.scala @@ -18,11 +18,10 @@ package smithytranslate.closure import scala.collection.mutable import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes._ -import scala.jdk.CollectionConverters.SetHasAsScala import software.amazon.smithy.model.neighbor.Walker import software.amazon.smithy.model.neighbor.NeighborProvider -import scala.jdk.CollectionConverters._ import scala.jdk.OptionConverters._ +import scala.jdk.CollectionConverters._ import software.amazon.smithy.model.traits.TraitDefinition import software.amazon.smithy.utils.ToSmithyBuilder diff --git a/modules/transitive/tests/src/ClosureSpec.scala b/modules/transitive/tests/src/ClosureSpec.scala index fe077b3..02e0810 100644 --- a/modules/transitive/tests/src/ClosureSpec.scala +++ b/modules/transitive/tests/src/ClosureSpec.scala @@ -42,7 +42,7 @@ class ClosureSpec extends munit.FunSuite { assertEquals( result .getMetadataProperty("some_key") - .flatMap(_.asStringNode().map(_.getValue)), + .flatMap[String](_.asStringNode().map[String](_.getValue)), java.util.Optional.of("some value") ) assertEquals(result.prettyPrint, model1.prettyPrint) From a7e3f9ada2abe2a990cb2cc4156c42d25f738f94 Mon Sep 17 00:00:00 2001 From: Dmytro Obodowsky Date: Mon, 4 Dec 2023 10:40:11 -0600 Subject: [PATCH 2/2] Address code review comments. Not all modules should be cross compiled --- build.sc | 48 ++++++++++++++----- .../src/internals/ApiResponseToParams.scala | 6 +-- .../openapi/src/internals/GetExtensions.scala | 5 +- .../src/internals/HeadersToParams.scala | 2 +- .../src/internals/IModelToSmithy.scala | 5 -- .../src/internals/OpenApiToIModel.scala | 4 +- .../src/internals/ParseOperations.scala | 6 +-- .../postprocess/AllOfTransformer.scala | 27 +++++------ 8 files changed, 62 insertions(+), 41 deletions(-) diff --git a/build.sc b/build.sc index 8c2cddf..90d361b 100644 --- a/build.sc +++ b/build.sc @@ -107,8 +107,16 @@ trait BasePublishModule extends BaseModule with CiReleaseModule { } } +trait Scala213VersionModule extends ScalaModule with ScalafmtModule { + override def scalaVersion = T.input("2.13.12") + + def scalacOptions = T { + super.scalacOptions() ++ scalacOptionsFor(scalaVersion()) + } +} + trait ScalaVersionModule extends CrossScalaModule with ScalafmtModule { -// override def scalaVersion = T.input("2.13.12") + override def scalaVersion = T.input("2.13.12") def scalacOptions = T { super.scalacOptions() ++ scalacOptionsFor(scalaVersion()) @@ -122,7 +130,20 @@ trait BaseScalaNoPublishModule extends BaseModule with ScalaVersionModule { ) } +trait BaseScala213NoPublishModule + extends BaseModule + with Scala213VersionModule { + + override def scalacPluginIvyDeps = super.scalacPluginIvyDeps() ++ Agg( + ivy"org.typelevel:::kind-projector:0.13.2" + ) +} + trait BaseScalaModule extends BaseScalaNoPublishModule with BasePublishModule +trait BaseScala213Module + extends BaseScala213NoPublishModule + with BasePublishModule + trait BaseScalaJSModule extends BaseScalaModule with ScalaJSModule { def scalaJSVersion = "1.11.0" def moduleKind = ModuleKind.CommonJSModule @@ -182,8 +203,7 @@ trait OpenApiModule extends BaseScalaModule { } } -object cli extends Cross[CliModule](scalaVersions) -trait CliModule extends BaseScalaModule with buildinfo.BuildInfo { +object cli extends BaseScala213Module with buildinfo.BuildInfo { def ivyDeps = Agg( Deps.decline, Deps.coursier, @@ -204,7 +224,12 @@ trait CliModule extends BaseScalaModule with buildinfo.BuildInfo { ) def moduleDeps = - Seq(openapi(), proto.core(), `json-schema`(), formatter.jvm()) + Seq( + openapi("2.13.12"), + proto.core("2.13.12"), + `json-schema`("2.13.12"), + formatter.jvm("2.13.12") + ) def runProtoAux = T.task { (inputs: List[Path], output: Path) => val inputArgs = inputs.flatMap { p => @@ -331,10 +356,11 @@ object traits extends BaseJavaModule { with BaseMunitTests } -object `readme-validator` - extends Cross[`readme-validator-module`](scalaVersions) -trait `readme-validator-module` extends BaseScalaNoPublishModule { - def moduleDeps = Seq(openapi(), proto.core(), `json-schema`()) +//object `readme-validator` +// extends Cross[`readme-validator-module`](scalaVersions) +object `readme-validator` extends BaseScala213NoPublishModule { + def moduleDeps = + Seq(openapi("2.13.12"), proto.core("2.13.12"), `json-schema`("2.13.12")) def ivyDeps = Agg( Deps.cats.parse, @@ -394,9 +420,7 @@ object proto extends Module { } } - object examples extends Cross[ExamplesModule](scalaVersions) - - trait ExamplesModule extends BaseScalaModule with ScalaPBModule { + object examples extends BaseScala213Module with ScalaPBModule { def scalaPBVersion = Deps.scalapb.version def smithyFiles = T.sources { @@ -415,7 +439,7 @@ object proto extends Module { os.remove.all(cliRunOutput) os.makeDir.all(cliRunOutput) val input = smithyFiles().toList.map(_.path) - val f = cli().runProtoAux() + val f = cli.runProtoAux() f(input, cliRunOutput) cliRunOutput } diff --git a/modules/openapi/src/internals/ApiResponseToParams.scala b/modules/openapi/src/internals/ApiResponseToParams.scala index 36be7ea..f7cc6c7 100644 --- a/modules/openapi/src/internals/ApiResponseToParams.scala +++ b/modules/openapi/src/internals/ApiResponseToParams.scala @@ -39,7 +39,7 @@ object ApiResponseToParams case (contentType, bodySchema: Schema[_]) :: Nil => // TODO: figure out how to deal with reflective calls in scala 2.12 val bodyExts = - GetExtensions.from(bodySchema.asInstanceOf[HasExtensions]) + GetExtensions.from(HasExtensions.unsafeFrom(bodySchema)) Some( Param( "body", @@ -54,7 +54,7 @@ object ApiResponseToParams case list => val bodySchema = ContentTypeDiscriminatedSchema(list.toMap) val bodyExts = - GetExtensions.from(bodySchema.asInstanceOf[HasExtensions]) + GetExtensions.from(HasExtensions.unsafeFrom(bodySchema)) Some( Param( "body", @@ -71,7 +71,7 @@ object ApiResponseToParams maybeRef match { case Some(ref) => Left(ref) case None => - val exts = GetExtensions.from(response.asInstanceOf[HasExtensions]) + val exts = GetExtensions.from(HasExtensions.unsafeFrom(response)) val httpMessageInfo = HttpMessageInfo(opName, allParams, exts) Right(httpMessageInfo) } diff --git a/modules/openapi/src/internals/GetExtensions.scala b/modules/openapi/src/internals/GetExtensions.scala index 8045668..cb63ee3 100644 --- a/modules/openapi/src/internals/GetExtensions.scala +++ b/modules/openapi/src/internals/GetExtensions.scala @@ -28,7 +28,7 @@ object GetExtensions { def transformPattern[A]( local: Local ): OpenApiPattern[A] => OpenApiPattern[A] = { - val maybeHints = from(local.schema.asInstanceOf[HasExtensions]) + val maybeHints = from(HasExtensions.unsafeFrom(local.schema)) (pattern: OpenApiPattern[A]) => pattern.mapContext(_.addHints(maybeHints, retainTopLevel = true)) } @@ -36,6 +36,9 @@ object GetExtensions { // Using reflective calls because openapi does not seem to have a common interface // that exposes the presence of extensions. type HasExtensions = { def getExtensions(): java.util.Map[String, Any] } + object HasExtensions { + def unsafeFrom(s: Any): HasExtensions = s.asInstanceOf[HasExtensions] + } def from(s: HasExtensions): List[Hint] = Option(s) diff --git a/modules/openapi/src/internals/HeadersToParams.scala b/modules/openapi/src/internals/HeadersToParams.scala index b3700fa..a85d6a0 100644 --- a/modules/openapi/src/internals/HeadersToParams.scala +++ b/modules/openapi/src/internals/HeadersToParams.scala @@ -26,7 +26,7 @@ object HeadersToParams extends (Iterable[(String, Header)] => Vector[Param]) { Option(headerMap).toVector.flatten.map { case (name, header) => val requiredHint = if (header.getRequired()) List(Hint.Required) else List.empty - val exts = GetExtensions.from(header.asInstanceOf[HasExtensions]) + val exts = GetExtensions.from(HasExtensions.unsafeFrom(header)) val hints = List(Hint.Header(name)) ++ requiredHint ++ exts val refOrSchema = Option(header.get$ref()) match { case Some(value) => Left(value) diff --git a/modules/openapi/src/internals/IModelToSmithy.scala b/modules/openapi/src/internals/IModelToSmithy.scala index a3221ac..050915c 100644 --- a/modules/openapi/src/internals/IModelToSmithy.scala +++ b/modules/openapi/src/internals/IModelToSmithy.scala @@ -60,11 +60,6 @@ final class IModelToSmithy(useEnumTraitSyntax: Boolean) List(Hint.JsonName(memName)) else List.empty -// ShapeBuilderOps[MemberShape.Builder, MemberShape](MemberShape -// .builder() -// .id(id.toSmithy) -// .target(tpe.toSmithy)).addHints(hints ++ jsonNameHint).build() - MemberShape .builder() .id(id.toSmithy) diff --git a/modules/openapi/src/internals/OpenApiToIModel.scala b/modules/openapi/src/internals/OpenApiToIModel.scala index 27edc84..b74b09d 100644 --- a/modules/openapi/src/internals/OpenApiToIModel.scala +++ b/modules/openapi/src/internals/OpenApiToIModel.scala @@ -372,9 +372,9 @@ private class OpenApiToIModel[F[_]: Parallel: TellShape: TellError]( val schemes = securitySchemes.values.toVector val securityHint = if (schemes.nonEmpty) List(Hint.Security(schemes)) else Nil - val exts = GetExtensions.from(openApi.asInstanceOf[HasExtensions]) + val exts = GetExtensions.from(HasExtensions.unsafeFrom(openApi)) val infoExts = - GetExtensions.from(openApi.getInfo().asInstanceOf[HasExtensions]) + GetExtensions.from(HasExtensions.unsafeFrom(openApi.getInfo())) val externalDocs = Option(openApi.getExternalDocs()).map(e => Hint.ExternalDocs(Option(e.getDescription()), e.getUrl()) ) diff --git a/modules/openapi/src/internals/ParseOperations.scala b/modules/openapi/src/internals/ParseOperations.scala index 2907e13..55903ea 100644 --- a/modules/openapi/src/internals/ParseOperations.scala +++ b/modules/openapi/src/internals/ParseOperations.scala @@ -192,7 +192,7 @@ private class ParseOperationsImpl( ) val hints = GetExtensions.from( - opInfo.op.asInstanceOf[HasExtensions] + HasExtensions.unsafeFrom(opInfo.op) ) ++ securityHint ++ descHint ++ exDocs val suppressions = getHeaderSuppressions(allValidInputParams).toVector ParseOperationsResult( @@ -252,7 +252,7 @@ private class ParseOperationsImpl( Option( op.getRequestBody() ).flatMap { rb => - val exts = GetExtensions.from(rb.asInstanceOf[HasExtensions]) + val exts = GetExtensions.from(HasExtensions.unsafeFrom(rb)) val bodies = ContentToSchemaOpt(rb.getContent()) val (bodyHints, maybeSchema) = bodies.toList match { @@ -295,7 +295,7 @@ private class ParseOperationsImpl( maybeResolvedParam.flatMap { resolvedParam => val name = resolvedParam.getName() - val exts = GetExtensions.from(resolvedParam.asInstanceOf[HasExtensions]) + val exts = GetExtensions.from(HasExtensions.unsafeFrom(resolvedParam)) val httpBinding = resolvedParam.getIn() match { case "query" => Some(Hint.QueryParam(name)) case "path" => Some(Hint.PathParam(name)) diff --git a/modules/openapi/src/internals/postprocess/AllOfTransformer.scala b/modules/openapi/src/internals/postprocess/AllOfTransformer.scala index d7a6cbc..a1951f3 100644 --- a/modules/openapi/src/internals/postprocess/AllOfTransformer.scala +++ b/modules/openapi/src/internals/postprocess/AllOfTransformer.scala @@ -142,13 +142,12 @@ object AllOfTransformer extends IModelPostProcessor { private def moveParentFieldsAndCreateMixins( all: Vector[Definition] ): Vector[Definition] = { - val allShapes: mutable.LinkedHashMap[DefId, Definition] = - all - .map(a => a.id -> a) - .foldLeft(new mutable.LinkedHashMap[DefId, Definition]()) { - case (acc, (id, shape)) => - acc += (id -> shape) - } + val allShapes = new mutable.LinkedHashMap[DefId, Definition]() + all + .map(a => a.id -> a) + .foreach { case (id, shape) => + allShapes += (id -> shape) + } all.foreach { d => // get latest in case modifications have been made to this definition since the @@ -219,15 +218,15 @@ object AllOfTransformer extends IModelPostProcessor { val unused = isAMixin.diff(usedAsMixins) + val idToDef = new mutable.ArrayBuffer[Definition]() allShapes - .foldLeft(new mutable.LinkedHashMap[DefId, Definition]()) { - case (acc, (id, shp)) => - acc += (if (unused(id)) - (id, shp.mapHints(_.filterNot(_ == Hint.IsMixin))) - else (id, shp)) + .foreach { case (id, shp) => + idToDef += (if (unused(id)) + shp.mapHints(_.filterNot(_ == Hint.IsMixin)) + else shp) } - .values - .toVector + + idToDef.toVector } private def transform(in: IModel): Vector[Definition] = {