-
Notifications
You must be signed in to change notification settings - Fork 5
New tapiro imports #373
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
New tapiro imports #373
Conversation
@lvolp testoni |
Ecco cosa mi ero dimenticato 🤣 |
I've tried it on our project, and it works for me, with a caveat: at first I got compile errors using the newly generated routes. This was because it was not only adding the controller imports, but also imports from other files (because Once I fixed I have a doubt on this approach when relative imports are used:
I'm not sure whether this is a serious problem though, so this is probably still OK for now and we'll deal with it if it arises. In practice, I suppose we normally use the same package (or sub-packages such that relative imports still work). |
You're right, I didn’t considered relative imports. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few comments on legibility. Maybe some of the complexity can be removed by just generating more imports, even if unneeded, and then eliminating them via scalafix?
Also, some files are not scalafmt-formatted. However, I noticed this is not checked in the CI (and also unrelated files are not formatted properly): I've opened a separate issue #377, so we can fix all formatting in that issue.
@@ -8,6 +8,29 @@ import scala.meta.contrib._ | |||
import cats.data.NonEmptyList | |||
|
|||
object Meta { | |||
|
|||
val controllerImports =(routes: List[TapiroRoute],imports: Set[Importer],outputPackage:String) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is a bit hard to read. I'll suggest a few small changes below, but also: how much of the complexity is done to avoid redundant imports? Since we're getting redundant imports anyway, maybe we can simplify a bit even if we get more of them? (and then either remove them with scalafix or suppress them during compilation)
@@ -8,6 +8,29 @@ import scala.meta.contrib._ | |||
import cats.data.NonEmptyList | |||
|
|||
object Meta { | |||
|
|||
val controllerImports =(routes: List[TapiroRoute],imports: Set[Importer],outputPackage:String) => { | |||
val types = routes.flatMap(tr => tr.route.params.map(r=> r.tpe) ++ (if (tr.route.error.isDefined) List(tr.route.error.get,tr.route.returns) else List(tr.route.returns))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
val types = routes.flatMap(tr => tr.route.params.map(r=> r.tpe) ++ (if (tr.route.error.isDefined) List(tr.route.error.get,tr.route.returns) else List(tr.route.returns))) | |
val types = routes.flatMap(tr => tr.route.params.map(_.tpe) ++ tr.route.error.toList ++ List(tr.route.returns))) |
should be equivalent I think?
|
||
val controllerImports =(routes: List[TapiroRoute],imports: Set[Importer],outputPackage:String) => { | ||
val types = routes.flatMap(tr => tr.route.params.map(r=> r.tpe) ++ (if (tr.route.error.isDefined) List(tr.route.error.get,tr.route.returns) else List(tr.route.returns))) | ||
val typeNameList = types.flatMap(typeNameExtractor(_)).toSet |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
val typeNameList = types.flatMap(typeNameExtractor(_)).toSet | |
val typeNameList = types.flatMap(typeNameExtractor).toSet |
val types = routes.flatMap(tr => tr.route.params.map(r=> r.tpe) ++ (if (tr.route.error.isDefined) List(tr.route.error.get,tr.route.returns) else List(tr.route.returns))) | ||
val typeNameList = types.flatMap(typeNameExtractor(_)).toSet | ||
val (wildcardImportList,importList) = imports.collect{ | ||
case i : Importer if i.syntax.endsWith("._") => List(i) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we could extract a function isWildcardImport
instead of repeating this check here and on line 18?
case Importer(ref,importees) => importees.filter(p=> typeNameList.contains(p.syntax)).map(p=> Importer(ref,List(p))) | ||
}.flatten.partition(_.syntax.endsWith("._")) | ||
val controllerPackageStrings = routes.map(r=> s"import ${r.route.controllerPackage.mkString(".")}._") | ||
val controllerPackage : List[Import] =controllerPackageStrings.flatMap(_.parse[Source].getOrElse(Source(List())).tree.children).collect{case i: Import => i} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bit strange since we're first building the strings and then constructing the imports by parsing the strings. I think it would be nicer to build the imports directly using quasiquotes (and maybe extract the strings from them). But I'm not sure if this is too cumbersome, otherwise it's fine to leave as is.
val importers = (if (importList.flatMap(i=> typeNameList.diff(i.importees.map(_.syntax).toSet)).isEmpty) importList else { | ||
(wildcardImportList ++ importList) | ||
}).map(i=>Import(List(i))) | ||
val result= if (controllerPackageStrings.filter(_.endsWith(outputPackage+"._")).isEmpty) controllerPackage ++ importers else importers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe use forall
or exists
instead of filter/isEmpty
?
Also, I'm not sure I've understood what the condition in the if
means, maybe we can rewrite to
val someMeaningfulNameForTheCondition = controllerPackageStrings.filter(_.endsWith(outputPackage+"._")
val result= if (someMeaningfulNameForTheCondition) controllerPackage ++ importers else importers
using some meaningful name to make this more understandable.
}).map(i=>Import(List(i))) | ||
val result= if (controllerPackageStrings.filter(_.endsWith(outputPackage+"._")).isEmpty) controllerPackage ++ importers else importers | ||
deduplicate(result.toList).toSet | ||
} : Set[Import] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move the type annotation to after the arguments
They're not used much, and anyway our endpoints are generated in the same package as the controller, so it's not an issue for now (though it would be best to support them in the future). But it could make sense to add scalafix first if it also allows us to simplify this code by not caring about generating too many imports. |
The idea is to generate imports from controller imports instead of model packages.
If is not possible to find a specific import for a type in a root, all the “._” imports present in the route paths will be included .
This will lead to some unused imports (that can be removed with Scalafix), but adds support to types not present in the model (such UUID,LocalDateTime, etc)