diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 28a1db68e..08ca8ae68 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -479,6 +479,8 @@ object Keys { val bspBuildTargetResourcesItem = taskKey[ResourcesItem]("").withRank(DTask) val bspBuildTargetDependencySources = inputKey[Unit]("").withRank(DTask) val bspBuildTargetDependencySourcesItem = taskKey[DependencySourcesItem]("").withRank(DTask) + val bspBuildTargetDependencyModules = inputKey[Unit]("").withRank(DTask) + val bspBuildTargetDependencyModulesItem = taskKey[DependencyModulesItem]("").withRank(DTask) val bspBuildTargetOutputPaths = inputKey[Unit]("").withRank(DTask) val bspBuildTargetOutputPathsItem = taskKey[OutputPathsItem]("").withRank(DTask) val bspBuildTargetCompile = inputKey[Unit]("").withRank(DTask) diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index 29043daa2..fdd4115b6 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -166,6 +166,21 @@ object BuildServerProtocol { state.value.respondEvent(result) }.evaluated, bspBuildTargetDependencySources / aggregate := false, + bspBuildTargetDependencyModules := bspInputTask { (workspace, filter) => + val items = bspBuildTargetDependencyModulesItem.result.all(filter).value + val successfulItems = anyOrThrow(items) + val buildItems = workspace.builds + .map { case (targetId, loadedBuildUnit) => + val projRef = ProjectRef(loadedBuildUnit.unit.uri, loadedBuildUnit.root) + (projRef / updateSbtClassifiers).map(getDependencyModulesItem(targetId, _)) + } + .toSeq + .join + .value + val result = DependencyModulesResult((successfulItems ++ buildItems).toVector) + state.value.respondEvent(result) + }.evaluated, + bspBuildTargetDependencyModules / aggregate := false, bspBuildTargetCompile := bspInputTask { (workspace, filter) => val s = state.value workspace.warnIfBuildsNonEmpty(Method.Compile, s.log) @@ -306,6 +321,7 @@ object BuildServerProtocol { ResourcesItem(id, uris) }, bspBuildTargetDependencySourcesItem := dependencySourcesItemTask.value, + bspBuildTargetDependencyModulesItem := dependencyModulesItemTask.value, bspBuildTargetOutputPathsItem := { val id = bspTargetIdentifier.value OutputPathsItem(id, Vector(OutputPathItem(target.value.toURI, OutputPathItemKind.Directory))) @@ -374,6 +390,7 @@ object BuildServerProtocol { final val Resources = "buildTarget/resources" final val OutputPaths = "buildTarget/outputPaths" final val DependencySources = "buildTarget/dependencySources" + final val DependencyModules = "buildTarget/dependencyModules" final val Compile = "buildTarget/compile" final val Test = "buildTarget/test" final val Run = "buildTarget/run" @@ -439,6 +456,12 @@ object BuildServerProtocol { val command = Keys.bspBuildTargetDependencySources.key val _ = callback.appendExec(s"$command $targets", Some(r.id)) + case r if r.method == Method.DependencyModules => + val param = Converter.fromJson[DependencyModulesParams](json(r)).get + val targets = param.targets.map(_.uri).mkString(" ") + val command = Keys.bspBuildTargetDependencyModules.key + val _ = callback.appendExec(s"$command $targets", Some(r.id)) + case r if r.method == Method.Compile => val param = Converter.fromJson[CompileParams](json(r)).get val targets = param.targets.map(_.uri).mkString(" ") @@ -856,6 +879,13 @@ object BuildServerProtocol { ) } + private def dependencyModulesItemTask: Def.Initialize[Task[DependencyModulesItem]] = Def.task { + getDependencyModulesItem( + Keys.bspTargetIdentifier.value, + Keys.updateClassifiers.value + ) + } + private def getDependencySourceItem( targetId: BuildTargetIdentifier, updateReport: UpdateReport @@ -869,6 +899,25 @@ object BuildServerProtocol { DependencySourcesItem(targetId, sources.toVector.distinct) } + private def getDependencyModulesItem( + targetId: BuildTargetIdentifier, + updateReport: UpdateReport + ): DependencyModulesItem = { + val modules = for { + configuration <- updateReport.configurations.view + module <- configuration.modules.view + } yield { + val moduleId = module.module + DependencyModule( + name = s"${moduleId.organization}:${moduleId.name}", + version = moduleId.revision, + dataKind = None, + data = None, + ) + } + DependencyModulesItem(targetId, modules.toVector.distinct) + } + private def bspCompileState: Initialize[BuildServerProtocol.BspCompileState] = Def.setting { new BuildServerProtocol.BspCompileState() } diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/DependencyModule.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/DependencyModule.scala new file mode 100644 index 000000000..ad3d58842 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/DependencyModule.scala @@ -0,0 +1,57 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +/** + * @param name Module name + * @param version Module version + * @param dataKind Kind of data to expect in the `data` field. + * @param data Language-specific metadata about this module. + */ +final class DependencyModule private ( + val name: String, + val version: String, + val dataKind: Option[String], + val data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: DependencyModule => (this.name == x.name) && (this.version == x.version) && (this.dataKind == x.dataKind) && (this.data == x.data) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.bsp.DependencyModule".##) + name.##) + version.##) + dataKind.##) + data.##) + } + override def toString: String = { + "DependencyModule(" + name + ", " + version + ", " + dataKind + ", " + data + ")" + } + private def copy(name: String = name, version: String = version, dataKind: Option[String] = dataKind, data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue] = data): DependencyModule = { + new DependencyModule(name, version, dataKind, data) + } + def withName(name: String): DependencyModule = { + copy(name = name) + } + def withVersion(version: String): DependencyModule = { + copy(version = version) + } + def withDataKind(dataKind: Option[String]): DependencyModule = { + copy(dataKind = dataKind) + } + def withDataKind(dataKind: String): DependencyModule = { + copy(dataKind = Option(dataKind)) + } + def withData(data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): DependencyModule = { + copy(data = data) + } + def withData(data: sjsonnew.shaded.scalajson.ast.unsafe.JValue): DependencyModule = { + copy(data = Option(data)) + } +} +object DependencyModule { + + def apply(name: String, version: String, dataKind: Option[String], data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): DependencyModule = new DependencyModule(name, version, dataKind, data) + def apply(name: String, version: String, dataKind: String, data: sjsonnew.shaded.scalajson.ast.unsafe.JValue): DependencyModule = new DependencyModule(name, version, Option(dataKind), Option(data)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/DependencyModulesItem.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/DependencyModulesItem.scala new file mode 100644 index 000000000..38a977a3a --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/DependencyModulesItem.scala @@ -0,0 +1,40 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +final class DependencyModulesItem private ( + val target: Option[sbt.internal.bsp.BuildTargetIdentifier], + val modules: Vector[sbt.internal.bsp.DependencyModule]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: DependencyModulesItem => (this.target == x.target) && (this.modules == x.modules) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.bsp.DependencyModulesItem".##) + target.##) + modules.##) + } + override def toString: String = { + "DependencyModulesItem(" + target + ", " + modules + ")" + } + private def copy(target: Option[sbt.internal.bsp.BuildTargetIdentifier] = target, modules: Vector[sbt.internal.bsp.DependencyModule] = modules): DependencyModulesItem = { + new DependencyModulesItem(target, modules) + } + def withTarget(target: Option[sbt.internal.bsp.BuildTargetIdentifier]): DependencyModulesItem = { + copy(target = target) + } + def withTarget(target: sbt.internal.bsp.BuildTargetIdentifier): DependencyModulesItem = { + copy(target = Option(target)) + } + def withModules(modules: Vector[sbt.internal.bsp.DependencyModule]): DependencyModulesItem = { + copy(modules = modules) + } +} +object DependencyModulesItem { + + def apply(target: Option[sbt.internal.bsp.BuildTargetIdentifier], modules: Vector[sbt.internal.bsp.DependencyModule]): DependencyModulesItem = new DependencyModulesItem(target, modules) + def apply(target: sbt.internal.bsp.BuildTargetIdentifier, modules: Vector[sbt.internal.bsp.DependencyModule]): DependencyModulesItem = new DependencyModulesItem(Option(target), modules) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/DependencyModulesParams.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/DependencyModulesParams.scala new file mode 100644 index 000000000..3a0212faa --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/DependencyModulesParams.scala @@ -0,0 +1,33 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +/** Dependency Modules Request */ +final class DependencyModulesParams private ( + val targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: DependencyModulesParams => (this.targets == x.targets) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (17 + "sbt.internal.bsp.DependencyModulesParams".##) + targets.##) + } + override def toString: String = { + "DependencyModulesParams(" + targets + ")" + } + private def copy(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): DependencyModulesParams = { + new DependencyModulesParams(targets) + } + def withTargets(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): DependencyModulesParams = { + copy(targets = targets) + } +} +object DependencyModulesParams { + + def apply(targets: Vector[sbt.internal.bsp.BuildTargetIdentifier]): DependencyModulesParams = new DependencyModulesParams(targets) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/DependencyModulesResult.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/DependencyModulesResult.scala new file mode 100644 index 000000000..d7a6c6063 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/DependencyModulesResult.scala @@ -0,0 +1,33 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp +/** Dependency Modules Result */ +final class DependencyModulesResult private ( + val items: Vector[sbt.internal.bsp.DependencyModulesItem]) extends Serializable { + + + + override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match { + case x: DependencyModulesResult => (this.items == x.items) + case _ => false + }) + override def hashCode: Int = { + 37 * (37 * (17 + "sbt.internal.bsp.DependencyModulesResult".##) + items.##) + } + override def toString: String = { + "DependencyModulesResult(" + items + ")" + } + private def copy(items: Vector[sbt.internal.bsp.DependencyModulesItem]): DependencyModulesResult = { + new DependencyModulesResult(items) + } + def withItems(items: Vector[sbt.internal.bsp.DependencyModulesItem]): DependencyModulesResult = { + copy(items = items) + } +} +object DependencyModulesResult { + + def apply(items: Vector[sbt.internal.bsp.DependencyModulesItem]): DependencyModulesResult = new DependencyModulesResult(items) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DependencyModuleFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DependencyModuleFormats.scala new file mode 100644 index 000000000..e8a1548c5 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DependencyModuleFormats.scala @@ -0,0 +1,33 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait DependencyModuleFormats { self: sbt.internal.util.codec.JValueFormats & sjsonnew.BasicJsonProtocol => +given DependencyModuleFormat: JsonFormat[sbt.internal.bsp.DependencyModule] = new JsonFormat[sbt.internal.bsp.DependencyModule] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.DependencyModule = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val name = unbuilder.readField[String]("name") + val version = unbuilder.readField[String]("version") + val dataKind = unbuilder.readField[Option[String]]("dataKind") + val data = unbuilder.readField[Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]]("data") + unbuilder.endObject() + sbt.internal.bsp.DependencyModule(name, version, dataKind, data) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.DependencyModule, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("name", obj.name) + builder.addField("version", obj.version) + builder.addField("dataKind", obj.dataKind) + builder.addField("data", obj.data) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DependencyModulesItemFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DependencyModulesItemFormats.scala new file mode 100644 index 000000000..ae4a3fde6 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DependencyModulesItemFormats.scala @@ -0,0 +1,29 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait DependencyModulesItemFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats & sjsonnew.BasicJsonProtocol & sbt.internal.bsp.codec.DependencyModuleFormats & sbt.internal.util.codec.JValueFormats => +given DependencyModulesItemFormat: JsonFormat[sbt.internal.bsp.DependencyModulesItem] = new JsonFormat[sbt.internal.bsp.DependencyModulesItem] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.DependencyModulesItem = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val target = unbuilder.readField[Option[sbt.internal.bsp.BuildTargetIdentifier]]("target") + val modules = unbuilder.readField[Vector[sbt.internal.bsp.DependencyModule]]("modules") + unbuilder.endObject() + sbt.internal.bsp.DependencyModulesItem(target, modules) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.DependencyModulesItem, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("target", obj.target) + builder.addField("modules", obj.modules) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DependencyModulesParamsFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DependencyModulesParamsFormats.scala new file mode 100644 index 000000000..c617fd356 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DependencyModulesParamsFormats.scala @@ -0,0 +1,27 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait DependencyModulesParamsFormats { self: sbt.internal.bsp.codec.BuildTargetIdentifierFormats & sjsonnew.BasicJsonProtocol => +given DependencyModulesParamsFormat: JsonFormat[sbt.internal.bsp.DependencyModulesParams] = new JsonFormat[sbt.internal.bsp.DependencyModulesParams] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.DependencyModulesParams = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val targets = unbuilder.readField[Vector[sbt.internal.bsp.BuildTargetIdentifier]]("targets") + unbuilder.endObject() + sbt.internal.bsp.DependencyModulesParams(targets) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.DependencyModulesParams, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("targets", obj.targets) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DependencyModulesResultFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DependencyModulesResultFormats.scala new file mode 100644 index 000000000..be4d510b4 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/DependencyModulesResultFormats.scala @@ -0,0 +1,27 @@ +/** + * This code is generated using [[https://www.scala-sbt.org/contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.bsp.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait DependencyModulesResultFormats { self: sbt.internal.bsp.codec.DependencyModulesItemFormats & sbt.internal.bsp.codec.BuildTargetIdentifierFormats & sjsonnew.BasicJsonProtocol & sbt.internal.bsp.codec.DependencyModuleFormats & sbt.internal.util.codec.JValueFormats => +given DependencyModulesResultFormat: JsonFormat[sbt.internal.bsp.DependencyModulesResult] = new JsonFormat[sbt.internal.bsp.DependencyModulesResult] { + override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.bsp.DependencyModulesResult = { + __jsOpt match { + case Some(__js) => + unbuilder.beginObject(__js) + val items = unbuilder.readField[Vector[sbt.internal.bsp.DependencyModulesItem]]("items") + unbuilder.endObject() + sbt.internal.bsp.DependencyModulesResult(items) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.bsp.DependencyModulesResult, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("items", obj.items) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala index 5b601a070..0b0b567c8 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/bsp/codec/JsonProtocol.scala @@ -43,6 +43,10 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol with sbt.internal.bsp.codec.DependencySourcesParamsFormats with sbt.internal.bsp.codec.DependencySourcesItemFormats with sbt.internal.bsp.codec.DependencySourcesResultFormats + with sbt.internal.bsp.codec.DependencyModulesParamsFormats + with sbt.internal.bsp.codec.DependencyModuleFormats + with sbt.internal.bsp.codec.DependencyModulesItemFormats + with sbt.internal.bsp.codec.DependencyModulesResultFormats with sbt.internal.bsp.codec.TaskStartParamsFormats with sbt.internal.bsp.codec.TaskProgressParamsFormats with sbt.internal.bsp.codec.TaskFinishParamsFormats diff --git a/protocol/src/main/contraband/bsp.contra b/protocol/src/main/contraband/bsp.contra index e9e1c2fab..f6333dcaa 100644 --- a/protocol/src/main/contraband/bsp.contra +++ b/protocol/src/main/contraband/bsp.contra @@ -409,6 +409,35 @@ type DependencySourcesItem { sources: [java.net.URI] } +## Dependency Modules Request +type DependencyModulesParams { + targets: [sbt.internal.bsp.BuildTargetIdentifier] +} + +## Dependency Modules Result +type DependencyModulesResult { + items: [sbt.internal.bsp.DependencyModulesItem] +} + +type DependencyModulesItem { + target: sbt.internal.bsp.BuildTargetIdentifier + modules: [sbt.internal.bsp.DependencyModule] +} + +type DependencyModule { + ## Module name + name: String! + + ## Module version + version: String! + + ## Kind of data to expect in the `data` field. + dataKind: String + + ## Language-specific metadata about this module. + data: sjsonnew.shaded.scalajson.ast.unsafe.JValue +} + ## Task Notifications type TaskStartParams { diff --git a/server-test/src/test/scala/testpkg/BuildServerTest.scala b/server-test/src/test/scala/testpkg/BuildServerTest.scala index 30230e5a7..fba61c524 100644 --- a/server-test/src/test/scala/testpkg/BuildServerTest.scala +++ b/server-test/src/test/scala/testpkg/BuildServerTest.scala @@ -524,6 +524,19 @@ class BuildServerTest extends AbstractServerTest { ) } + test("buildTarget/dependencyModules") { + val buildTarget = buildTargetUri("util", "Compile") + val badBuildTarget = buildTargetUri("badBuildTarget", "Compile") + val targets = Vector(buildTarget, badBuildTarget).map(BuildTargetIdentifier.apply) + val id = dependencyModules(targets.map(_.uri)) + val res = svr.session.waitForResultInResponseMsg[DependencyModulesResult](10.seconds, id).get + val utilItem = res.items.find(_.target == BuildTargetIdentifier(buildTarget)).get + assert( + utilItem.modules.exists(_.name.contains("jsoniter-scala-core")), + s"dependencyModules should include jsoniter-scala-core, got: ${utilItem.modules.map(_.name)}" + ) + } + test("buildTarget/outputPaths") { val buildTarget = buildTargetUri("util", "Compile") val badBuildTarget = buildTargetUri("badBuildTarget", "Compile") @@ -753,6 +766,11 @@ class BuildServerTest extends AbstractServerTest { sendRequest("buildTarget/sources", SourcesParams(targets)) } + private def dependencyModules(buildTargets: Seq[URI]): String = { + val targets = buildTargets.map(BuildTargetIdentifier.apply).toVector + sendRequest("buildTarget/dependencyModules", DependencyModulesParams(targets)) + } + private def sendRequest(method: String): String = { val id = svr.session.nextId() svr.session.sendJsonRpc(id, method, "{}").get