diff --git a/build.sbt b/build.sbt index 54f908fc4..4dcb8e004 100644 --- a/build.sbt +++ b/build.sbt @@ -542,12 +542,15 @@ lazy val example = projectMatrix .disablePlugins(HeaderPlugin) .settings( Compile / allowedNamespaces := Seq( - "smithy4s.example" + "smithy4s.example", + "smithy4s.example.import_test" ), smithySpecs := Seq( (ThisBuild / baseDirectory).value / "sampleSpecs" / "example.smithy", (ThisBuild / baseDirectory).value / "sampleSpecs" / "errors.smithy", - (ThisBuild / baseDirectory).value / "sampleSpecs" / "streaming.smithy" + (ThisBuild / baseDirectory).value / "sampleSpecs" / "streaming.smithy", + (ThisBuild / baseDirectory).value / "sampleSpecs" / "operation.smithy", + (ThisBuild / baseDirectory).value / "sampleSpecs" / "import.smithy" ), Compile / resourceDirectory := (ThisBuild / baseDirectory).value / "modules" / "example" / "resources", isCE3 := true, diff --git a/modules/codegen/src/smithy4s/codegen/Renderer.scala b/modules/codegen/src/smithy4s/codegen/Renderer.scala index c2084e070..d82813517 100644 --- a/modules/codegen/src/smithy4s/codegen/Renderer.scala +++ b/modules/codegen/src/smithy4s/codegen/Renderer.scala @@ -45,7 +45,11 @@ object Renderer { val p = s"package ${unit.namespace}" val allImports = - renderResult.imports.filterNot(_.startsWith(unit.namespace)) + renderResult.imports.filter( + _.replaceAll(unit.namespace, "") + .split('.') + .count(_.nonEmpty) > 1 + ) val allLines = List(p, "") ++ allImports.toList.sorted.map("import " + _) ++ @@ -57,7 +61,13 @@ object Renderer { Result(unit.namespace, decl.name, content) } - pack :: classes + val packageApplicableDecls = unit.declarations.filter { + case _: TypeAlias | _: Service => true + case _ => false + } + + if (packageApplicableDecls.isEmpty) classes + else pack :: classes } } diff --git a/modules/example/resources/smithy4s.example.ImportService.json b/modules/example/resources/smithy4s.example.ImportService.json new file mode 100644 index 000000000..177cda605 --- /dev/null +++ b/modules/example/resources/smithy4s.example.ImportService.json @@ -0,0 +1,33 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "ImportService", + "version": "1.0.0" + }, + "paths": { + "/test": { + "get": { + "operationId": "ImportOperation", + "responses": { + "200": { + "description": "ImportOperation 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportOperationOutputPayload" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "ImportOperationOutputPayload": { + "type": "string" + } + } + } +} \ No newline at end of file diff --git a/modules/example/src/smithy4s/example/ImportService.scala b/modules/example/src/smithy4s/example/ImportService.scala new file mode 100644 index 000000000..5859053e5 --- /dev/null +++ b/modules/example/src/smithy4s/example/ImportService.scala @@ -0,0 +1,66 @@ +package smithy4s.example + +import smithy4s.example.import_test.OpOutput +import smithy4s.syntax._ + +trait ImportServiceGen[F[_, _, _, _, _]] { + self => + + def importOperation() : F[Unit, Nothing, OpOutput, Nothing, Nothing] + + def transform[G[_, _, _, _, _]](transformation : smithy4s.Transformation[F, G]) : ImportServiceGen[G] = new Transformed(transformation) + class Transformed[G[_, _, _, _, _]](transformation : smithy4s.Transformation[F, G]) extends ImportServiceGen[G] { + def importOperation() = transformation[Unit, Nothing, OpOutput, Nothing, Nothing](self.importOperation()) + } +} + +object ImportServiceGen extends smithy4s.Service[ImportServiceGen, ImportServiceOperation] { + + def apply[F[_]](implicit F: smithy4s.Monadic[ImportServiceGen, F]): F.type = F + + val id: smithy4s.ShapeId = smithy4s.ShapeId("smithy4s.example", "ImportService") + + val hints : smithy4s.Hints = smithy4s.Hints( + id, + smithy4s.api.SimpleRestJson(), + ) + + val endpoints = List( + ImportOperation, + ) + + val version: String = "1.0.0" + + def endpoint[I, E, O, SI, SO](op : ImportServiceOperation[I, E, O, SI, SO]) = op match { + case ImportOperation() => ((), ImportOperation) + } + + object reified extends ImportServiceGen[ImportServiceOperation] { + def importOperation() = ImportOperation() + } + + def transform[P[_, _, _, _, _]](transformation: smithy4s.Transformation[ImportServiceOperation, P]): ImportServiceGen[P] = reified.transform(transformation) + + def transform[P[_, _, _, _, _], P1[_, _, _, _, _]](alg: ImportServiceGen[P], transformation: smithy4s.Transformation[P, P1]): ImportServiceGen[P1] = alg.transform(transformation) + + def asTransformation[P[_, _, _, _, _]](impl : ImportServiceGen[P]): smithy4s.Transformation[ImportServiceOperation, P] = new smithy4s.Transformation[ImportServiceOperation, P] { + def apply[I, E, O, SI, SO](op : ImportServiceOperation[I, E, O, SI, SO]) : P[I, E, O, SI, SO] = op match { + case ImportOperation() => impl.importOperation() + } + } + case class ImportOperation() extends ImportServiceOperation[Unit, Nothing, OpOutput, Nothing, Nothing] + object ImportOperation extends smithy4s.Endpoint[ImportServiceOperation, Unit, Nothing, OpOutput, Nothing, Nothing] { + val id: smithy4s.ShapeId = smithy4s.ShapeId("smithy4s.example.import_test", "ImportOperation") + val input: smithy4s.Schema[Unit] = unit.withHints(smithy4s.internals.InputOutput.Input) + val output: smithy4s.Schema[OpOutput] = OpOutput.schema.withHints(smithy4s.internals.InputOutput.Output) + val streamedInput : smithy4s.StreamingSchema[Nothing] = smithy4s.StreamingSchema.nothing + val streamedOutput : smithy4s.StreamingSchema[Nothing] = smithy4s.StreamingSchema.nothing + val hints : smithy4s.Hints = smithy4s.Hints( + id, + smithy.api.Http(smithy.api.NonEmptyString("GET"), smithy.api.NonEmptyString("/test"), Some(200)), + ) + def wrap(input: Unit) = ImportOperation() + } +} + +sealed trait ImportServiceOperation[Input, Err, Output, StreamedInput, StreamedOutput] diff --git a/modules/example/src/smithy4s/example/import_test/OpOutput.scala b/modules/example/src/smithy4s/example/import_test/OpOutput.scala new file mode 100644 index 000000000..689397cbe --- /dev/null +++ b/modules/example/src/smithy4s/example/import_test/OpOutput.scala @@ -0,0 +1,19 @@ +package smithy4s.example.import_test + +import smithy4s.syntax._ + +case class OpOutput(output: String) +object OpOutput extends smithy4s.ShapeTag.Companion[OpOutput] { + val id: smithy4s.ShapeId = smithy4s.ShapeId("smithy4s.example.import_test", "OpOutput") + + val hints : smithy4s.Hints = smithy4s.Hints( + id, + ) + + val schema: smithy4s.Schema[OpOutput] = struct( + string.required[OpOutput]("output", _.output).withHints(smithy.api.Required(), smithy.api.HttpPayload()), + ){ + OpOutput.apply + }.withHints(hints) + implicit val staticSchema : schematic.Static[smithy4s.Schema[OpOutput]] = schematic.Static(schema) +} \ No newline at end of file diff --git a/modules/example/src/smithy4s/example/package.scala b/modules/example/src/smithy4s/example/package.scala index 8b7c08e1b..ddd1d6003 100644 --- a/modules/example/src/smithy4s/example/package.scala +++ b/modules/example/src/smithy4s/example/package.scala @@ -13,6 +13,12 @@ package object example { def service : smithy4s.Service[FooServiceGen, FooServiceOperation] = FooServiceGen val id: smithy4s.ShapeId = service.id } + type ImportService[F[_]] = smithy4s.Monadic[ImportServiceGen, F] + object ImportService extends smithy4s.Service.Provider[ImportServiceGen, ImportServiceOperation] { + def apply[F[_]](implicit F: ImportService[F]): F.type = F + def service : smithy4s.Service[ImportServiceGen, ImportServiceOperation] = ImportServiceGen + val id: smithy4s.ShapeId = service.id + } type ObjectService[F[_]] = smithy4s.Monadic[ObjectServiceGen, F] object ObjectService extends smithy4s.Service.Provider[ObjectServiceGen, ObjectServiceOperation] { def apply[F[_]](implicit F: ObjectService[F]): F.type = F diff --git a/sampleSpecs/import.smithy b/sampleSpecs/import.smithy new file mode 100644 index 000000000..e2de39c46 --- /dev/null +++ b/sampleSpecs/import.smithy @@ -0,0 +1,11 @@ +namespace smithy4s.example + +use smithy4s.api#simpleRestJson +use smithy4s.example.import_test#ImportOperation + +@simpleRestJson +service ImportService { + version: "1.0.0", + operations: [ImportOperation] +} + diff --git a/sampleSpecs/operation.smithy b/sampleSpecs/operation.smithy new file mode 100644 index 000000000..7750ff370 --- /dev/null +++ b/sampleSpecs/operation.smithy @@ -0,0 +1,12 @@ +namespace smithy4s.example.import_test + +@http(method: "GET", uri: "/test", code: 200) +operation ImportOperation { + output: OpOutput +} + +structure OpOutput { + @httpPayload + @required + output: String +}