From 0c1c380f7100815d78143853dcb87ecbea9d9ced Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 2 Oct 2017 03:33:29 -0400 Subject: [PATCH 1/6] begins language server protocol This is the first cut for the Language Server Protocol on top of server that is still work in progress. With this change, sbt is able to invoke `compile` task on saving files in VS Code. --- .gitignore | 5 + build.sbt | 35 + .../scala/sbt/internal/CommandChannel.scala | 1 + .../scala/sbt/internal/ConsoleChannel.scala | 2 + main/src/main/scala/sbt/Defaults.scala | 11 +- .../scala/sbt/internal/CommandExchange.scala | 79 +- .../scala/sbt/internal/RelayAppender.scala | 17 +- .../server/LanguageServerProtocol.scala | 127 + .../server/LanguageServerReporter.scala | 122 + .../sbt/internal/server/NetworkChannel.scala | 267 +- project/Dependencies.scala | 4 +- project/plugins.sbt | 2 +- .../InitializeResultFormats.scala | 26 + .../ServerCapabilitiesFormats.scala | 26 + .../langserver/ClientCapabilities.scala | 29 + .../sbt/internal/langserver/Diagnostic.scala | 73 + .../langserver/InitializeParams.scala | 72 + .../langserver/InitializeResult.scala | 33 + .../sbt/internal/langserver/Location.scala | 37 + .../sbt/internal/langserver/Position.scala | 42 + .../langserver/PublishDiagnosticsParams.scala | 39 + .../sbt/internal/langserver/Range.scala | 42 + .../sbt/internal/langserver/SaveOptions.scala | 37 + .../langserver/ServerCapabilities.scala | 44 + .../langserver/TextDocumentSyncOptions.scala | 64 + .../codec/ClientCapabilitiesFormats.scala | 27 + .../langserver/codec/DiagnosticFormats.scala | 35 + .../codec/InitializeParamsFormats.scala | 37 + .../codec/InitializeResultFormats.scala | 27 + .../langserver/codec/JsonProtocol.scala | 20 + .../langserver/codec/LocationFormats.scala | 29 + .../langserver/codec/PositionFormats.scala | 29 + .../PublishDiagnosticsParamsFormats.scala | 29 + .../langserver/codec/RangeFormats.scala | 29 + .../langserver/codec/SaveOptionsFormats.scala | 27 + .../codec/ServerCapabilitiesFormats.scala | 29 + .../TextDocumentSyncOptionsFormats.scala | 35 + .../internal/protocol/InitializeOption.scala | 36 + .../internal/protocol/JsonRpcMessage.scala | 27 + .../protocol/JsonRpcNotificationMessage.scala | 46 + .../protocol/JsonRpcRequestMessage.scala | 51 + .../protocol/JsonRpcResponseError.scala | 50 + .../protocol/JsonRpcResponseMessage.scala | 60 + .../codec/InitializeOptionFormats.scala | 27 + protocol/src/main/contraband/jsonrpc.contra | 74 + protocol/src/main/contraband/lsp.contra | 112 + protocol/src/main/contraband/portfile.contra | 4 + .../langserver/DiagnosticSeverity.scala | 26 + .../sbt/internal/langserver/ErrorCodes.scala | 19 + .../protocol/codec/JsonRPCProtocol.scala | 13 + .../JsonRpcNotificationMessageFormats.scala | 40 + .../codec/JsonRpcRequestMessageFormats.scala | 45 + .../codec/JsonRpcResponseErrorFormats.scala | 39 + .../codec/JsonRpcResponseMessageFormats.scala | 52 + .../scala/sbt/protocol/Serialization.scala | 62 + .../sbt-test/server/handshake/Client.scala | 40 +- sbt/src/sbt-test/server/handshake/test | 2 +- vscode-sbt-scala/.vscode/launch.json | 33 + vscode-sbt-scala/.vscode/settings.json | 10 + vscode-sbt-scala/.vscode/tasks.json | 79 + vscode-sbt-scala/client/.vscodeignore | 9 + vscode-sbt-scala/client/README.md | 6 + .../client/images/sbt-logo-455x262.png | Bin 0 -> 6715 bytes vscode-sbt-scala/client/images/sbt-logo.svg | 26 + vscode-sbt-scala/client/package-lock.json | 2256 +++++++++++++++++ vscode-sbt-scala/client/package.json | 35 + vscode-sbt-scala/client/src/extension.ts | 45 + vscode-sbt-scala/client/tsconfig.json | 19 + vscode-sbt-scala/package-lock.json | 26 + vscode-sbt-scala/package.json | 26 + vscode-sbt-scala/server/package-lock.json | 41 + vscode-sbt-scala/server/package.json | 24 + vscode-sbt-scala/server/src/server.ts | 33 + vscode-sbt-scala/server/tsconfig.json | 17 + 74 files changed, 5035 insertions(+), 64 deletions(-) create mode 100644 main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala create mode 100644 main/src/main/scala/sbt/internal/server/LanguageServerReporter.scala create mode 100644 protocol/src/main/contraband-scala/InitializeResultFormats.scala create mode 100644 protocol/src/main/contraband-scala/ServerCapabilitiesFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/ClientCapabilities.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/Diagnostic.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/InitializeParams.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/InitializeResult.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/Location.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/Position.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/PublishDiagnosticsParams.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/Range.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/SaveOptions.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/ServerCapabilities.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/TextDocumentSyncOptions.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/codec/ClientCapabilitiesFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/codec/DiagnosticFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/codec/InitializeParamsFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/codec/InitializeResultFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/codec/JsonProtocol.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/codec/LocationFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/codec/PositionFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/codec/PublishDiagnosticsParamsFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/codec/RangeFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/codec/SaveOptionsFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/codec/ServerCapabilitiesFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/codec/TextDocumentSyncOptionsFormats.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/protocol/InitializeOption.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcMessage.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcNotificationMessage.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcRequestMessage.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcResponseError.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcResponseMessage.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/protocol/codec/InitializeOptionFormats.scala create mode 100644 protocol/src/main/contraband/jsonrpc.contra create mode 100644 protocol/src/main/contraband/lsp.contra create mode 100644 protocol/src/main/scala/sbt/internal/langserver/DiagnosticSeverity.scala create mode 100644 protocol/src/main/scala/sbt/internal/langserver/ErrorCodes.scala create mode 100644 protocol/src/main/scala/sbt/internal/protocol/codec/JsonRPCProtocol.scala create mode 100644 protocol/src/main/scala/sbt/internal/protocol/codec/JsonRpcNotificationMessageFormats.scala create mode 100644 protocol/src/main/scala/sbt/internal/protocol/codec/JsonRpcRequestMessageFormats.scala create mode 100644 protocol/src/main/scala/sbt/internal/protocol/codec/JsonRpcResponseErrorFormats.scala create mode 100644 protocol/src/main/scala/sbt/internal/protocol/codec/JsonRpcResponseMessageFormats.scala create mode 100644 vscode-sbt-scala/.vscode/launch.json create mode 100644 vscode-sbt-scala/.vscode/settings.json create mode 100644 vscode-sbt-scala/.vscode/tasks.json create mode 100644 vscode-sbt-scala/client/.vscodeignore create mode 100644 vscode-sbt-scala/client/README.md create mode 100644 vscode-sbt-scala/client/images/sbt-logo-455x262.png create mode 100644 vscode-sbt-scala/client/images/sbt-logo.svg create mode 100644 vscode-sbt-scala/client/package-lock.json create mode 100644 vscode-sbt-scala/client/package.json create mode 100644 vscode-sbt-scala/client/src/extension.ts create mode 100644 vscode-sbt-scala/client/tsconfig.json create mode 100644 vscode-sbt-scala/package-lock.json create mode 100644 vscode-sbt-scala/package.json create mode 100644 vscode-sbt-scala/server/package-lock.json create mode 100644 vscode-sbt-scala/server/package.json create mode 100644 vscode-sbt-scala/server/src/server.ts create mode 100644 vscode-sbt-scala/server/tsconfig.json diff --git a/.gitignore b/.gitignore index 9dfa96975..3996caad8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ target/ __pycache__ toolbox.classpath +out +node_modules +vscode-sbt-scala/client/server +npm-debug.log +*.vsix diff --git a/build.sbt b/build.sbt index 5e695c989..fec97e6be 100644 --- a/build.sbt +++ b/build.sbt @@ -407,6 +407,41 @@ lazy val sbtProj = (project in file("sbt")) ) .configure(addSbtCompilerBridge) +lazy val vscodePlugin = (project in file("vscode-sbt-scala")) + .settings( + crossPaths := false, + crossScalaVersions := Seq(baseScalaVersion), + skip in publish := true, + compile in Compile := { + val u = update.value + import sbt.internal.inc.Analysis + import scala.sys.process._ + Process(s"npm run compile", Option(baseDirectory.value)).! + Analysis.empty + }, + update := { + val old = update.value + val t = target.value / "updated" + val base = baseDirectory.value + if (t.exists) () + else { + import scala.sys.process._ + Process("npm install", Option(base)).! + IO.touch(t) + } + old + }, + cleanFiles ++= { + val base = baseDirectory.value + Vector( + target.value / "updated", + base / "node_modules", base / "client" / "node_modules", + base / "client" / "server", + base / "client" / "out", + base / "server" / "node_modules") filter { _.exists } + } + ) + lazy val sbtIgnoredProblems = { Seq( // Added more items to Import trait. diff --git a/main-command/src/main/scala/sbt/internal/CommandChannel.scala b/main-command/src/main/scala/sbt/internal/CommandChannel.scala index 0f9eb963e..ec46a0738 100644 --- a/main-command/src/main/scala/sbt/internal/CommandChannel.scala +++ b/main-command/src/main/scala/sbt/internal/CommandChannel.scala @@ -16,6 +16,7 @@ abstract class CommandChannel { commandQueue.add(exec) def poll: Option[Exec] = Option(commandQueue.poll) + def publishEvent[A: JsonFormat](event: A, execId: Option[String]): Unit def publishEvent[A: JsonFormat](event: A): Unit def publishEventMessage(event: EventMessage): Unit def publishBytes(bytes: Array[Byte]): Unit diff --git a/main-command/src/main/scala/sbt/internal/ConsoleChannel.scala b/main-command/src/main/scala/sbt/internal/ConsoleChannel.scala index ddbf747e1..eff9abf9e 100644 --- a/main-command/src/main/scala/sbt/internal/ConsoleChannel.scala +++ b/main-command/src/main/scala/sbt/internal/ConsoleChannel.scala @@ -31,6 +31,8 @@ private[sbt] final class ConsoleChannel(val name: String) extends CommandChannel def publishBytes(bytes: Array[Byte]): Unit = () + def publishEvent[A: JsonFormat](event: A, execId: Option[String]): Unit = () + def publishEvent[A: JsonFormat](event: A): Unit = () def publishEventMessage(event: EventMessage): Unit = diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 428d1046d..851c25f8b 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -23,6 +23,7 @@ import sbt.internal.librarymanagement.mavenint.{ PomExtraDependencyAttributes, SbtPomExtraProperties } +import sbt.internal.server.LanguageServerReporter import sbt.internal.testing.TestLogger import sbt.internal.util._ import sbt.internal.util.Attributed.data @@ -1402,6 +1403,14 @@ object Defaults extends BuildCommon { val compilers: Compilers = ci.compilers val i = ci.withCompilers(onArgs(compilers)) try { + val prev = i.previousResult + prev.analysis.toOption map { analysis => + i.setup.reporter match { + case r: LanguageServerReporter => + r.resetPrevious(analysis) + case _ => () + } + } incCompiler.compile(i, s.log) } finally x.close() // workaround for #937 } @@ -1441,7 +1450,7 @@ object Defaults extends BuildCommon { compileOrder.value ), compilerReporter := { - new ManagedLoggedReporter( + new LanguageServerReporter( maxErrors.value, streams.value.log, foldMappers(sourcePositionMappers.value) diff --git a/main/src/main/scala/sbt/internal/CommandExchange.scala b/main/src/main/scala/sbt/internal/CommandExchange.scala index 574dfd8ce..66702e677 100644 --- a/main/src/main/scala/sbt/internal/CommandExchange.scala +++ b/main/src/main/scala/sbt/internal/CommandExchange.scala @@ -4,19 +4,21 @@ package internal import java.net.SocketException import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.atomic.AtomicInteger -import sbt.internal.server._ -import sbt.internal.util.StringEvent -import sbt.protocol.{ EventMessage, Serialization } import scala.collection.mutable.ListBuffer import scala.annotation.tailrec import BasicKeys.{ serverHost, serverPort, serverAuthentication } import java.net.Socket import sjsonnew.JsonFormat +import sjsonnew.shaded.scalajson.ast.unsafe._ import scala.concurrent.Await import scala.concurrent.duration.Duration import scala.util.{ Success, Failure } import sbt.io.syntax._ import sbt.io.Hash +import sbt.internal.server._ +import sbt.internal.util.{ StringEvent, ObjectEvent } +import sbt.internal.util.codec.JValueFormats +import sbt.protocol.{ EventMessage, Serialization, ChannelAcceptedEvent } /** * The command exchange merges multiple command channels (e.g. network and console), @@ -34,6 +36,8 @@ private[sbt] final class CommandExchange { private val commandQueue: ConcurrentLinkedQueue[Exec] = new ConcurrentLinkedQueue() private val channelBuffer: ListBuffer[CommandChannel] = new ListBuffer() private val nextChannelId: AtomicInteger = new AtomicInteger(0) + private lazy val jsonFormat = new sjsonnew.BasicJsonProtocol with JValueFormats {} + def channels: List[CommandChannel] = channelBuffer.toList def subscribe(c: CommandChannel): Unit = lock.synchronized { @@ -121,9 +125,31 @@ private[sbt] final class CommandExchange { server = None } + // This is an interface to directly notify events. + private[sbt] def notifyEvent[A: JsonFormat](method: String, params: A): Unit = { + val toDel: ListBuffer[CommandChannel] = ListBuffer.empty + channels.foreach { + case c: ConsoleChannel => + // c.publishEvent(event) + case c: NetworkChannel => + try { + c.notifyEvent(method, params) + } catch { + case e: SocketException => + toDel += c + } + } + toDel.toList match { + case Nil => // do nothing + case xs => + lock.synchronized { + channelBuffer --= xs + } + } + } + def publishEvent[A: JsonFormat](event: A): Unit = { val toDel: ListBuffer[CommandChannel] = ListBuffer.empty - val bytes = Serialization.serializeEvent(event) event match { case entry: StringEvent => channels.foreach { @@ -134,7 +160,7 @@ private[sbt] final class CommandExchange { case c: NetworkChannel => try { if (entry.channelName == Some(c.name)) { - c.publishBytes(bytes) + c.publishEvent(event) } } catch { case e: SocketException => @@ -147,7 +173,7 @@ private[sbt] final class CommandExchange { c.publishEvent(event) case c: NetworkChannel => try { - c.publishBytes(bytes) + c.publishEvent(event) } catch { case e: SocketException => toDel += c @@ -163,6 +189,43 @@ private[sbt] final class CommandExchange { } } + /** + * This publishes object events. The type information has been + * erased because it went through logging. + */ + private[sbt] def publishObjectEvent(event: ObjectEvent[_]): Unit = { + import jsonFormat._ + val toDel: ListBuffer[CommandChannel] = ListBuffer.empty + def json: JValue = JObject( + JField("type", JString(event.contentType)), + (Vector(JField("message", event.json), JField("level", JString(event.level.toString))) ++ + (event.channelName.toVector map { channelName => + JField("channelName", JString(channelName)) + }) ++ + (event.execId.toVector map { execId => + JField("execId", JString(execId)) + })): _* + ) + channels.foreach { + case c: ConsoleChannel => + c.publishEvent(json) + case c: NetworkChannel => + try { + c.publishObjectEvent(event) + } catch { + case e: SocketException => + toDel += c + } + } + toDel.toList match { + case Nil => // do nothing + case xs => + lock.synchronized { + channelBuffer --= xs + } + } + } + // fanout publishEvent def publishEventMessage(event: EventMessage): Unit = { val toDel: ListBuffer[CommandChannel] = ListBuffer.empty @@ -177,14 +240,12 @@ private[sbt] final class CommandExchange { case c: ConsoleChannel => c.publishEventMessage(e) } case _ => - // TODO do not do this on the calling thread - val bytes = Serialization.serializeEventMessage(event) channels.foreach { case c: ConsoleChannel => c.publishEventMessage(event) case c: NetworkChannel => try { - c.publishBytes(bytes) + c.publishEventMessage(event) } catch { case e: SocketException => toDel += c diff --git a/main/src/main/scala/sbt/internal/RelayAppender.scala b/main/src/main/scala/sbt/internal/RelayAppender.scala index 8f833d376..7509ecbae 100644 --- a/main/src/main/scala/sbt/internal/RelayAppender.scala +++ b/main/src/main/scala/sbt/internal/RelayAppender.scala @@ -10,12 +10,10 @@ import sbt.util.Level import sbt.internal.util._ import sbt.protocol.LogEvent import sbt.internal.util.codec._ -import sjsonnew.shaded.scalajson.ast.unsafe._ class RelayAppender(name: String) extends AbstractAppender(name, null, PatternLayout.createDefaultLayout(), true) { lazy val exchange = StandardMain.exchange - lazy val jsonFormat = new sjsonnew.BasicJsonProtocol with JValueFormats {} def append(event: XLogEvent): Unit = { val level = ConsoleAppender.toLevel(event.getLevel) @@ -36,20 +34,7 @@ class RelayAppender(name: String) import JsonProtocol._ exchange.publishEvent(x: AbstractEntry) } - case x: ObjectEvent[_] => { - import jsonFormat._ - val json = JObject( - JField("type", JString(x.contentType)), - (Vector(JField("message", x.json), JField("level", JString(x.level.toString))) ++ - (x.channelName.toVector map { channelName => - JField("channelName", JString(channelName)) - }) ++ - (x.execId.toVector map { execId => - JField("execId", JString(execId)) - })): _* - ) - exchange.publishEvent(json: JValue) - } + case x: ObjectEvent[_] => exchange.publishObjectEvent(x) case _ => println(s"appendEvent: ${event.getClass}") () diff --git a/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala b/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala new file mode 100644 index 000000000..988d5678c --- /dev/null +++ b/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala @@ -0,0 +1,127 @@ +package sbt +package internal +package server + +import sjsonnew.JsonFormat +import sjsonnew.support.scalajson.unsafe.Converter +import sbt.protocol.Serialization +import sbt.internal.protocol._ +import sbt.internal.protocol.codec._ +import sbt.internal.langserver._ +import sbt.internal.util.ObjectEvent + +private[sbt] case class LangServerError(code: Long, message: String) extends Throwable(message) + +/** + * Implements Language Server Protocol . + */ +private[sbt] trait LanguageServerProtocol extends CommandChannel { + + lazy val internalJsonProtocol = new InitializeOptionFormats with sjsonnew.BasicJsonProtocol {} + + protected def authenticate(token: String): Boolean + protected def authOptions: Set[ServerAuthentication] + protected def setInitialized(value: Boolean): Unit + + protected def onRequestMessage(request: JsonRpcRequestMessage): Unit = { + + import sbt.internal.langserver.codec.JsonProtocol._ + import internalJsonProtocol._ + + println(s"onRequestMessage: $request") + request.method match { + case "initialize" => + if (authOptions(ServerAuthentication.Token)) { + val json = + request.params.getOrElse( + throw LangServerError(ErrorCodes.InvalidParams, + "param is expected on 'initialize' method.")) + val param = Converter.fromJson[InitializeParams](json).get + val optionJson = param.initializationOptions.getOrElse( + throw LangServerError(ErrorCodes.InvalidParams, + "initializationOptions is expected on 'initialize' param.")) + val opt = Converter.fromJson[InitializeOption](optionJson).get + val token = opt.token.getOrElse(sys.error("'token' is missing.")) + if (authenticate(token)) () + else throw LangServerError(ErrorCodes.InvalidRequest, "invalid token") + } else () + setInitialized(true) + langRespond(InitializeResult(serverCapabilities), Option(request.id)) + case "textDocument/didSave" => + append(Exec("compile", Some(request.id), Some(CommandSource(name)))) + case _ => () + } + } + + /** + * This reacts to various events that happens inside sbt, sometime + * in response to the previous requests. + * The type information has been erased because it went through logging. + */ + protected def onObjectEvent(event: ObjectEvent[_]): Unit = { + // import sbt.internal.langserver.codec.JsonProtocol._ + + val msgContentType = event.contentType + msgContentType match { + // LanguageServerReporter sends PublishDiagnosticsParams + case "sbt.internal.langserver.PublishDiagnosticsParams" => + // val p = event.message.asInstanceOf[PublishDiagnosticsParams] + // langNotify("textDocument/publishDiagnostics", p) + case "xsbti.Problem" => + () // ignore + case _ => + // println(event) + () + } + } + + /** + * Respond back to Language Server's client. + */ + private[sbt] def langRespond[A: JsonFormat](event: A, execId: Option[String]): Unit = { + val m = + JsonRpcResponseMessage("2.0", execId, Option(Converter.toJson[A](event).get), None) + val bytes = Serialization.serializeResponseMessage(m) + publishBytes(bytes) + } + + /** + * Respond back to Language Server's client. + */ + private[sbt] def langError(execId: Option[String], code: Long, message: String): Unit = { + val e = JsonRpcResponseError(code, message, None) + val m = JsonRpcResponseMessage("2.0", execId, None, Option(e)) + val bytes = Serialization.serializeResponseMessage(m) + publishBytes(bytes) + } + + /** + * Respond back to Language Server's client. + */ + private[sbt] def langError[A: JsonFormat](execId: Option[String], + code: Long, + message: String, + data: A): Unit = { + val e = JsonRpcResponseError(code, message, Option(Converter.toJson[A](data).get)) + val m = JsonRpcResponseMessage("2.0", execId, None, Option(e)) + val bytes = Serialization.serializeResponseMessage(m) + publishBytes(bytes) + } + + /** + * Notify to Language Server's client. + */ + private[sbt] def langNotify[A: JsonFormat](method: String, params: A): Unit = { + val m = + JsonRpcNotificationMessage("2.0", method, Option(Converter.toJson[A](params).get)) + println(s"langNotify: $m") + val bytes = Serialization.serializeNotificationMessage(m) + publishBytes(bytes) + } + + private[sbt] lazy val serverCapabilities: ServerCapabilities = { + ServerCapabilities(textDocumentSync = + TextDocumentSyncOptions(true, 0, false, false, SaveOptions(false)), + hoverProvider = false) + } +} diff --git a/main/src/main/scala/sbt/internal/server/LanguageServerReporter.scala b/main/src/main/scala/sbt/internal/server/LanguageServerReporter.scala new file mode 100644 index 000000000..5d550c41f --- /dev/null +++ b/main/src/main/scala/sbt/internal/server/LanguageServerReporter.scala @@ -0,0 +1,122 @@ +package sbt +package internal +package server + +import java.io.File +import sbt.internal.inc.ManagedLoggedReporter +import sbt.internal.util.ManagedLogger +import xsbti.{ Problem, Position => XPosition, Severity } +import xsbti.compile.CompileAnalysis +import sbt.internal.langserver.{ + PublishDiagnosticsParams, + Position, + Diagnostic, + Range, + DiagnosticSeverity +} +import sbt.internal.inc.JavaInterfaceUtil._ +import scala.collection.mutable +import scala.collection.JavaConverters._ + +/** + * Defines a compiler reporter that uses event logging provided by a [[ManagedLogger]]. + * + * @param maximumErrors The maximum errors. + * @param logger The event managed logger. + * @param sourcePositionMapper The position mapper. + */ +class LanguageServerReporter( + maximumErrors: Int, + logger: ManagedLogger, + sourcePositionMapper: XPosition => XPosition = identity[XPosition] +) extends ManagedLoggedReporter(maximumErrors, logger, sourcePositionMapper) { + lazy val exchange = StandardMain.exchange + + private[sbt] lazy val problemsByFile = new mutable.HashMap[File, List[Problem]] + + override def reset(): Unit = { + super.reset() + problemsByFile.clear() + } + + override def log(problem: Problem): Unit = { + val pos = problem.position + pos.sourceFile.toOption foreach { sourceFile: File => + problemsByFile.get(sourceFile) match { + case Some(xs: List[Problem]) => problemsByFile(sourceFile) = problem :: xs + case _ => problemsByFile(sourceFile) = List(problem) + } + } + super.log(problem) + } + + override def logError(problem: Problem): Unit = { + aggregateProblems(problem) + + // console channel can keep using the xsbi.Problem + super.logError(problem) + } + + override def logWarning(problem: Problem): Unit = { + aggregateProblems(problem) + + // console channel can keep using the xsbi.Problem + super.logWarning(problem) + } + + override def logInfo(problem: Problem): Unit = { + aggregateProblems(problem) + + // console channel can keep using the xsbi.Problem + super.logInfo(problem) + } + + private[sbt] def resetPrevious(analysis: CompileAnalysis): Unit = { + import sbt.internal.langserver.codec.JsonProtocol._ + val files = analysis.readSourceInfos.getAllSourceInfos.keySet.asScala + println(files) + files foreach { f => + val params = PublishDiagnosticsParams(f.toURI.toString, Vector()) + exchange.notifyEvent("textDocument/publishDiagnostics", params) + } + } + + private[sbt] def aggregateProblems(problem: Problem): Unit = { + import sbt.internal.langserver.codec.JsonProtocol._ + val pos = problem.position + pos.sourceFile.toOption foreach { sourceFile: File => + problemsByFile.get(sourceFile) match { + case Some(xs: List[Problem]) => + val ds = toDiagnostics(xs) + val params = PublishDiagnosticsParams(sourceFile.toURI.toString, ds) + exchange.notifyEvent("textDocument/publishDiagnostics", params) + case _ => + } + } + } + + private[sbt] def toDiagnostics(ps: List[Problem]): Vector[Diagnostic] = { + for { + problem <- ps.toVector + pos = problem.position + line0 <- pos.line.toOption.toVector + pointer0 <- pos.pointer.toOption.toVector + } yield { + val line = line0.toLong - 1L + val pointer = pointer0.toLong + Diagnostic( + Range(start = Position(line, pointer), end = Position(line, pointer + 1)), + Option(toDiagnosticSeverity(problem.severity)), + None, + Option("sbt"), + problem.message + ) + } + } + + private[sbt] def toDiagnosticSeverity(severity: Severity): Long = severity match { + case Severity.Info => DiagnosticSeverity.Information + case Severity.Warn => DiagnosticSeverity.Warning + case Severity.Error => DiagnosticSeverity.Error + } +} diff --git a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala index eeaa8ed7c..ca1de8ea8 100644 --- a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala +++ b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala @@ -7,21 +7,58 @@ package server import java.net.{ Socket, SocketTimeoutException } import java.util.concurrent.atomic.AtomicBoolean -import sbt.protocol._ + import sjsonnew._ +import sjsonnew.support.scalajson.unsafe.Converter +import scala.annotation.tailrec +import sbt.protocol._ +import sbt.internal.langserver.ErrorCodes +import sbt.internal.protocol.JsonRpcResponseMessage +import sbt.internal.util.ObjectEvent +import sbt.internal.util.codec.JValueFormats final class NetworkChannel(val name: String, connection: Socket, structure: BuildStructure, auth: Set[ServerAuthentication], instance: ServerInstance) - extends CommandChannel { + extends CommandChannel + with LanguageServerProtocol { + import NetworkChannel._ + private val running = new AtomicBoolean(true) private val delimiter: Byte = '\n'.toByte + private val RetByte = '\r'.toByte private val out = connection.getOutputStream private var initialized = false + private val Curly = '{'.toByte + private val ContentLength = """^Content\-Length\:\s*(\d+)""".r + private val ContentType = """^Content\-Type\:\s*(.+)""".r + private var _contentType: String = "" + private val SbtX1Protocol = "application/sbt-x1" + private val VsCode = sbt.protocol.Serialization.VsCode + private val VsCodeOld = "application/vscode-jsonrpc; charset=utf8" + private lazy val jsonFormat = new sjsonnew.BasicJsonProtocol with JValueFormats {} + + def setContentType(ct: String): Unit = synchronized { + _contentType = ct + } + def contentType: String = _contentType + + protected def authenticate(token: String): Boolean = { + instance.authenticate(token) + } + + protected def setInitialized(value: Boolean): Unit = { + initialized = value + } + + protected def authOptions: Set[ServerAuthentication] = auth val thread = new Thread(s"sbt-networkchannel-${connection.getPort}") { + var contentLength: Int = 0 + var state: ChannelState = SingleLine + override def run(): Unit = { try { val readBuffer = new Array[Byte](4096) @@ -29,48 +66,221 @@ final class NetworkChannel(val name: String, connection.setSoTimeout(5000) var buffer: Vector[Byte] = Vector.empty var bytesRead = 0 + def resetChannelState(): Unit = { + contentLength = 0 + // contentType = "" + state = SingleLine + } + + def tillEndOfLine: Option[Vector[Byte]] = { + val delimPos = buffer.indexOf(delimiter) + if (delimPos > 0) { + val chunk0 = buffer.take(delimPos) + buffer = buffer.drop(delimPos + 1) + // remove \r at the end of line. + if (chunk0.size > 0 && chunk0.indexOf(RetByte) == chunk0.size - 1) + Some(chunk0.dropRight(1)) + else Some(chunk0) + } else None // no EOL yet, so skip this turn. + } + + def tillContentLength: Option[Vector[Byte]] = { + if (contentLength <= buffer.size) { + val chunk = buffer.take(contentLength) + buffer = buffer.drop(contentLength) + resetChannelState() + Some(chunk) + } else None // have not read enough yet, so skip this turn. + } + + @tailrec def process(): Unit = { + // handle un-framing + state match { + case SingleLine => + tillEndOfLine match { + case Some(chunk) => + chunk.headOption match { + case None => // ignore blank line + case Some(Curly) => + Serialization + .deserializeCommand(chunk) + .fold( + errorDesc => + println( + s"Got invalid chunk from client (${new String(chunk.toArray, "UTF-8")}): " + errorDesc), + onCommand + ) + resetChannelState() + case Some(_) => + val str = (new String(chunk.toArray, "UTF-8")).trim + handleHeader(str) match { + case Some(_) => + state = InHeader + process() + case _ => println("Got invalid chunk from client: " + str) + } + } + case _ => () + } + case InHeader => + tillEndOfLine match { + case Some(chunk) => + val str = (new String(chunk.toArray, "UTF-8")).trim + if (str == "") { + state = InBody + process() + } else + handleHeader(str) match { + case Some(_) => process() + case _ => + println("Got invalid header from client: " + str) + resetChannelState() + } + case _ => () + } + case InBody => + tillContentLength match { + case Some(chunk) => + handleBody(chunk) + process() + case _ => () + } + } + } + + // keep going unless the socket has closed while (bytesRead != -1 && running.get) { try { bytesRead = in.read(readBuffer) - buffer = buffer ++ readBuffer.toVector.take(bytesRead) - // handle un-framing - var delimPos = buffer.indexOf(delimiter) - while (delimPos > -1) { - val chunk = buffer.take(delimPos) - buffer = buffer.drop(delimPos + 1) - - Serialization - .deserializeCommand(chunk) - .fold( - errorDesc => println("Got invalid chunk from client: " + errorDesc), - onCommand - ) - delimPos = buffer.indexOf(delimiter) + println(s"bytesRead: $bytesRead") + if (bytesRead > 0) { + buffer = buffer ++ readBuffer.toVector.take(bytesRead) } + process() } catch { case _: SocketTimeoutException => // its ok } - } + } // while } finally { shutdown() } } + + def handleBody(chunk: Vector[Byte]): Unit = { + if (isLanguageServerProtocol) { + Serialization.deserializeJsonRequest(chunk) match { + case Right(req) => + try { + onRequestMessage(req) + } catch { + case LangServerError(code, message) => + println(s"sending error: $code: $message") + langError(Option(req.id), code, message) + } + case Left(errorDesc) => + val msg = s"Got invalid chunk from client (${new String(chunk.toArray, "UTF-8")}): " + errorDesc + langError(None, ErrorCodes.ParseError, msg) + } + } else { + contentType match { + case SbtX1Protocol => + Serialization + .deserializeCommand(chunk) + .fold( + errorDesc => + println( + s"Got invalid chunk from client (${new String(chunk.toArray, "UTF-8")}): " + errorDesc), + onCommand + ) + case _ => + println(s"Unknown Content-Type: $contentType") + } + } // if-else + } + + def handleHeader(str: String): Option[Unit] = { + str match { + case ContentLength(len) => + contentLength = len.toInt + Some(()) + case ContentType(ct) => + setContentType(ct) + Some(()) + case _ => None + } + } } thread.start() - def publishEvent[A: JsonFormat](event: A): Unit = { - val bytes = Serialization.serializeEvent(event) - publishBytes(bytes) + private[sbt] def isLanguageServerProtocol: Boolean = { + contentType match { + case "" | VsCode | VsCodeOld => true + case _ => false + } } + private[sbt] def notifyEvent[A: JsonFormat](method: String, params: A): Unit = { + if (isLanguageServerProtocol) { + langNotify(method, params) + } else { + () + } + } + + def publishEvent[A: JsonFormat](event: A, execId: Option[String]): Unit = { + if (isLanguageServerProtocol) { + langRespond(event, execId) + } else { + contentType match { + case SbtX1Protocol => + val bytes = Serialization.serializeEvent(event) + publishBytes(bytes, true) + case _ => + } + } + } + + def publishEvent[A: JsonFormat](event: A): Unit = publishEvent(event, None) + def publishEventMessage(event: EventMessage): Unit = { - val bytes = Serialization.serializeEventMessage(event) - publishBytes(bytes) + contentType match { + case SbtX1Protocol => + val bytes = Serialization.serializeEventMessage(event) + publishBytes(bytes, true) + case _ => + } } - def publishBytes(event: Array[Byte]): Unit = { + /** + * This publishes object events. The type information has been + * erased because it went through logging. + */ + private[sbt] def publishObjectEvent(event: ObjectEvent[_]): Unit = { + import sjsonnew.shaded.scalajson.ast.unsafe._ + if (isLanguageServerProtocol) onObjectEvent(event) + else { + import jsonFormat._ + val json: JValue = JObject( + JField("type", JString(event.contentType)), + (Vector(JField("message", event.json), JField("level", JString(event.level.toString))) ++ + (event.channelName.toVector map { channelName => + JField("channelName", JString(channelName)) + }) ++ + (event.execId.toVector map { execId => + JField("execId", JString(execId)) + })): _* + ) + publishEvent(json) + } + } + + def publishBytes(event: Array[Byte]): Unit = publishBytes(event, false) + + def publishBytes(event: Array[Byte], delimit: Boolean): Unit = { out.write(event) - out.write(delimiter.toInt) + if (delimit) { + out.write(delimiter.toInt) + } out.flush() } @@ -84,7 +294,7 @@ final class NetworkChannel(val name: String, if (auth(ServerAuthentication.Token)) { cmd.token match { case Some(x) => - instance.authenticate(x) match { + authenticate(x) match { case true => initialized = true publishEventMessage(ChannelAcceptedEvent(name)) @@ -120,3 +330,10 @@ final class NetworkChannel(val name: String, out.close() } } + +object NetworkChannel { + sealed trait ChannelState + case object SingleLine extends ChannelState + case object InHeader extends ChannelState + case object InBody extends ChannelState +} diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 8745f1dfb..f714cbc82 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -13,9 +13,9 @@ object Dependencies { // sbt modules private val ioVersion = "1.1.0" - private val utilVersion = "1.0.1" + private val utilVersion = "1.0.2" private val lmVersion = "1.0.2" - private val zincVersion = "1.0.1" + private val zincVersion = "1.0.2" private val sbtIO = "org.scala-sbt" %% "io" % ioVersion diff --git a/project/plugins.sbt b/project/plugins.sbt index 2eec0f9bd..f9064f32f 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -8,6 +8,6 @@ addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.1.17") // addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.2.0") addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.1") -addSbtPlugin("org.scala-sbt" % "sbt-contraband" % "0.3.0") +addSbtPlugin("org.scala-sbt" % "sbt-contraband" % "0.3.1") addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.0-M1") addSbtPlugin("com.lucidchart" % "sbt-scalafmt" % "1.10") diff --git a/protocol/src/main/contraband-scala/InitializeResultFormats.scala b/protocol/src/main/contraband-scala/InitializeResultFormats.scala new file mode 100644 index 000000000..33827daee --- /dev/null +++ b/protocol/src/main/contraband-scala/InitializeResultFormats.scala @@ -0,0 +1,26 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait InitializeResultFormats { self: ServerCapabilitiesFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val InitializeResultFormat: JsonFormat[sbt.internal.langserver.InitializeResult] = new JsonFormat[sbt.internal.langserver.InitializeResult] { + override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.langserver.InitializeResult = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val capabilities = unbuilder.readField[Option[sbt.internal.langserver.ServerCapabilities]]("capabilities") + unbuilder.endObject() + sbt.internal.langserver.InitializeResult(capabilities) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.langserver.InitializeResult, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("capabilities", obj.capabilities) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/ServerCapabilitiesFormats.scala b/protocol/src/main/contraband-scala/ServerCapabilitiesFormats.scala new file mode 100644 index 000000000..3dbef6ccc --- /dev/null +++ b/protocol/src/main/contraband-scala/ServerCapabilitiesFormats.scala @@ -0,0 +1,26 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait ServerCapabilitiesFormats { self: sjsonnew.BasicJsonProtocol => +implicit lazy val ServerCapabilitiesFormat: JsonFormat[sbt.internal.langserver.ServerCapabilities] = new JsonFormat[sbt.internal.langserver.ServerCapabilities] { + override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.langserver.ServerCapabilities = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val hoverProvider = unbuilder.readField[Option[Boolean]]("hoverProvider") + unbuilder.endObject() + sbt.internal.langserver.ServerCapabilities(hoverProvider) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.langserver.ServerCapabilities, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("hoverProvider", obj.hoverProvider) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/ClientCapabilities.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/ClientCapabilities.scala new file mode 100644 index 000000000..7bbfe152a --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/ClientCapabilities.scala @@ -0,0 +1,29 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver +final class ClientCapabilities private () extends Serializable { + + + +override def equals(o: Any): Boolean = o match { + case x: ClientCapabilities => true + case _ => false +} +override def hashCode: Int = { + 37 * (17 + "sbt.internal.langserver.ClientCapabilities".##) +} +override def toString: String = { + "ClientCapabilities()" +} +protected[this] def copy(): ClientCapabilities = { + new ClientCapabilities() +} + +} +object ClientCapabilities { + + def apply(): ClientCapabilities = new ClientCapabilities() +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/Diagnostic.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/Diagnostic.scala new file mode 100644 index 000000000..c28bc9b38 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/Diagnostic.scala @@ -0,0 +1,73 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver +/** + * Represents a diagnostic, such as a compiler error or warning. + * Diagnostic objects are only valid in the scope of a resource. + */ +final class Diagnostic private ( + /** The range at which the message applies. */ + val range: sbt.internal.langserver.Range, + /** + * The diagnostic's severity. Can be omitted. If omitted it is up to the + * client to interpret diagnostics as error, warning, info or hint. + */ + val severity: Option[Long], + /** The diagnostic's code. Can be omitted. */ + val code: Option[String], + /** + * A human-readable string describing the source of this + * diagnostic, e.g. 'typescript' or 'super lint'. + */ + val source: Option[String], + /** The diagnostic's message. */ + val message: String) extends Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: Diagnostic => (this.range == x.range) && (this.severity == x.severity) && (this.code == x.code) && (this.source == x.source) && (this.message == x.message) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.langserver.Diagnostic".##) + range.##) + severity.##) + code.##) + source.##) + message.##) + } + override def toString: String = { + "Diagnostic(" + range + ", " + severity + ", " + code + ", " + source + ", " + message + ")" + } + protected[this] def copy(range: sbt.internal.langserver.Range = range, severity: Option[Long] = severity, code: Option[String] = code, source: Option[String] = source, message: String = message): Diagnostic = { + new Diagnostic(range, severity, code, source, message) + } + def withRange(range: sbt.internal.langserver.Range): Diagnostic = { + copy(range = range) + } + def withSeverity(severity: Option[Long]): Diagnostic = { + copy(severity = severity) + } + def withSeverity(severity: Long): Diagnostic = { + copy(severity = Option(severity)) + } + def withCode(code: Option[String]): Diagnostic = { + copy(code = code) + } + def withCode(code: String): Diagnostic = { + copy(code = Option(code)) + } + def withSource(source: Option[String]): Diagnostic = { + copy(source = source) + } + def withSource(source: String): Diagnostic = { + copy(source = Option(source)) + } + def withMessage(message: String): Diagnostic = { + copy(message = message) + } +} +object Diagnostic { + + def apply(range: sbt.internal.langserver.Range, severity: Option[Long], code: Option[String], source: Option[String], message: String): Diagnostic = new Diagnostic(range, severity, code, source, message) + def apply(range: sbt.internal.langserver.Range, severity: Long, code: String, source: String, message: String): Diagnostic = new Diagnostic(range, Option(severity), Option(code), Option(source), message) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/InitializeParams.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/InitializeParams.scala new file mode 100644 index 000000000..b96dc9478 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/InitializeParams.scala @@ -0,0 +1,72 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver +final class InitializeParams private ( + val processId: Option[Long], + /** The rootPath of the workspace. */ + val rootPath: Option[String], + val rootUri: Option[String], + val initializationOptions: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue], + val capabilities: Option[sbt.internal.langserver.ClientCapabilities], + val trace: Option[String]) extends Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: InitializeParams => (this.processId == x.processId) && (this.rootPath == x.rootPath) && (this.rootUri == x.rootUri) && (this.initializationOptions == x.initializationOptions) && (this.capabilities == x.capabilities) && (this.trace == x.trace) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.langserver.InitializeParams".##) + processId.##) + rootPath.##) + rootUri.##) + initializationOptions.##) + capabilities.##) + trace.##) + } + override def toString: String = { + "InitializeParams(" + processId + ", " + rootPath + ", " + rootUri + ", " + initializationOptions + ", " + capabilities + ", " + trace + ")" + } + protected[this] def copy(processId: Option[Long] = processId, rootPath: Option[String] = rootPath, rootUri: Option[String] = rootUri, initializationOptions: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue] = initializationOptions, capabilities: Option[sbt.internal.langserver.ClientCapabilities] = capabilities, trace: Option[String] = trace): InitializeParams = { + new InitializeParams(processId, rootPath, rootUri, initializationOptions, capabilities, trace) + } + def withProcessId(processId: Option[Long]): InitializeParams = { + copy(processId = processId) + } + def withProcessId(processId: Long): InitializeParams = { + copy(processId = Option(processId)) + } + def withRootPath(rootPath: Option[String]): InitializeParams = { + copy(rootPath = rootPath) + } + def withRootPath(rootPath: String): InitializeParams = { + copy(rootPath = Option(rootPath)) + } + def withRootUri(rootUri: Option[String]): InitializeParams = { + copy(rootUri = rootUri) + } + def withRootUri(rootUri: String): InitializeParams = { + copy(rootUri = Option(rootUri)) + } + def withInitializationOptions(initializationOptions: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): InitializeParams = { + copy(initializationOptions = initializationOptions) + } + def withInitializationOptions(initializationOptions: sjsonnew.shaded.scalajson.ast.unsafe.JValue): InitializeParams = { + copy(initializationOptions = Option(initializationOptions)) + } + def withCapabilities(capabilities: Option[sbt.internal.langserver.ClientCapabilities]): InitializeParams = { + copy(capabilities = capabilities) + } + def withCapabilities(capabilities: sbt.internal.langserver.ClientCapabilities): InitializeParams = { + copy(capabilities = Option(capabilities)) + } + def withTrace(trace: Option[String]): InitializeParams = { + copy(trace = trace) + } + def withTrace(trace: String): InitializeParams = { + copy(trace = Option(trace)) + } +} +object InitializeParams { + + def apply(processId: Option[Long], rootPath: Option[String], rootUri: Option[String], initializationOptions: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue], capabilities: Option[sbt.internal.langserver.ClientCapabilities], trace: Option[String]): InitializeParams = new InitializeParams(processId, rootPath, rootUri, initializationOptions, capabilities, trace) + def apply(processId: Long, rootPath: String, rootUri: String, initializationOptions: sjsonnew.shaded.scalajson.ast.unsafe.JValue, capabilities: sbt.internal.langserver.ClientCapabilities, trace: String): InitializeParams = new InitializeParams(Option(processId), Option(rootPath), Option(rootUri), Option(initializationOptions), Option(capabilities), Option(trace)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/InitializeResult.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/InitializeResult.scala new file mode 100644 index 000000000..440844dd6 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/InitializeResult.scala @@ -0,0 +1,33 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver +final class InitializeResult private ( + /** The capabilities the language server provides. */ + val capabilities: sbt.internal.langserver.ServerCapabilities) extends Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: InitializeResult => (this.capabilities == x.capabilities) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (17 + "sbt.internal.langserver.InitializeResult".##) + capabilities.##) + } + override def toString: String = { + "InitializeResult(" + capabilities + ")" + } + protected[this] def copy(capabilities: sbt.internal.langserver.ServerCapabilities = capabilities): InitializeResult = { + new InitializeResult(capabilities) + } + def withCapabilities(capabilities: sbt.internal.langserver.ServerCapabilities): InitializeResult = { + copy(capabilities = capabilities) + } +} +object InitializeResult { + + def apply(capabilities: sbt.internal.langserver.ServerCapabilities): InitializeResult = new InitializeResult(capabilities) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/Location.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/Location.scala new file mode 100644 index 000000000..900a426d4 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/Location.scala @@ -0,0 +1,37 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver +/** Represents a location inside a resource, such as a line inside a text file. */ +final class Location private ( + val uri: String, + val range: sbt.internal.langserver.Range) extends Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: Location => (this.uri == x.uri) && (this.range == x.range) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.langserver.Location".##) + uri.##) + range.##) + } + override def toString: String = { + "Location(" + uri + ", " + range + ")" + } + protected[this] def copy(uri: String = uri, range: sbt.internal.langserver.Range = range): Location = { + new Location(uri, range) + } + def withUri(uri: String): Location = { + copy(uri = uri) + } + def withRange(range: sbt.internal.langserver.Range): Location = { + copy(range = range) + } +} +object Location { + + def apply(uri: String, range: sbt.internal.langserver.Range): Location = new Location(uri, range) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/Position.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/Position.scala new file mode 100644 index 000000000..f36a278f1 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/Position.scala @@ -0,0 +1,42 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver +/** + * Position in a text document expressed as zero-based line and zero-based character offset. + * A position is between two characters like an 'insert' cursor in a editor. + */ +final class Position private ( + /** Line position in a document (zero-based). */ + val line: Long, + /** Character offset on a line in a document (zero-based). */ + val character: Long) extends Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: Position => (this.line == x.line) && (this.character == x.character) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.langserver.Position".##) + line.##) + character.##) + } + override def toString: String = { + "Position(" + line + ", " + character + ")" + } + protected[this] def copy(line: Long = line, character: Long = character): Position = { + new Position(line, character) + } + def withLine(line: Long): Position = { + copy(line = line) + } + def withCharacter(character: Long): Position = { + copy(character = character) + } +} +object Position { + + def apply(line: Long, character: Long): Position = new Position(line, character) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/PublishDiagnosticsParams.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/PublishDiagnosticsParams.scala new file mode 100644 index 000000000..25f7ab729 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/PublishDiagnosticsParams.scala @@ -0,0 +1,39 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver +/** Diagnostics notification are sent from the server to the client to signal results of validation runs. */ +final class PublishDiagnosticsParams private ( + /** The URI for which diagnostic information is reported. */ + val uri: String, + /** An array of diagnostic information items. */ + val diagnostics: Vector[sbt.internal.langserver.Diagnostic]) extends Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: PublishDiagnosticsParams => (this.uri == x.uri) && (this.diagnostics == x.diagnostics) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.langserver.PublishDiagnosticsParams".##) + uri.##) + diagnostics.##) + } + override def toString: String = { + "PublishDiagnosticsParams(" + uri + ", " + diagnostics + ")" + } + protected[this] def copy(uri: String = uri, diagnostics: Vector[sbt.internal.langserver.Diagnostic] = diagnostics): PublishDiagnosticsParams = { + new PublishDiagnosticsParams(uri, diagnostics) + } + def withUri(uri: String): PublishDiagnosticsParams = { + copy(uri = uri) + } + def withDiagnostics(diagnostics: Vector[sbt.internal.langserver.Diagnostic]): PublishDiagnosticsParams = { + copy(diagnostics = diagnostics) + } +} +object PublishDiagnosticsParams { + + def apply(uri: String, diagnostics: Vector[sbt.internal.langserver.Diagnostic]): PublishDiagnosticsParams = new PublishDiagnosticsParams(uri, diagnostics) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/Range.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/Range.scala new file mode 100644 index 000000000..929bbec5b --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/Range.scala @@ -0,0 +1,42 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver +/** + * A range in a text document expressed as (zero-based) start and end positions. A range is comparable to a selection in an editor. + * Therefore the end position is exclusive. + */ +final class Range private ( + /** The range's start position. */ + val start: sbt.internal.langserver.Position, + /** The range's end position. */ + val end: sbt.internal.langserver.Position) extends Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: Range => (this.start == x.start) && (this.end == x.end) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.langserver.Range".##) + start.##) + end.##) + } + override def toString: String = { + "Range(" + start + ", " + end + ")" + } + protected[this] def copy(start: sbt.internal.langserver.Position = start, end: sbt.internal.langserver.Position = end): Range = { + new Range(start, end) + } + def withStart(start: sbt.internal.langserver.Position): Range = { + copy(start = start) + } + def withEnd(end: sbt.internal.langserver.Position): Range = { + copy(end = end) + } +} +object Range { + + def apply(start: sbt.internal.langserver.Position, end: sbt.internal.langserver.Position): Range = new Range(start, end) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/SaveOptions.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/SaveOptions.scala new file mode 100644 index 000000000..347dfca25 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/SaveOptions.scala @@ -0,0 +1,37 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver +final class SaveOptions private ( + /** The client is supposed to include the content on save. */ + val includeText: Option[Boolean]) extends Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: SaveOptions => (this.includeText == x.includeText) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (17 + "sbt.internal.langserver.SaveOptions".##) + includeText.##) + } + override def toString: String = { + "SaveOptions(" + includeText + ")" + } + protected[this] def copy(includeText: Option[Boolean] = includeText): SaveOptions = { + new SaveOptions(includeText) + } + def withIncludeText(includeText: Option[Boolean]): SaveOptions = { + copy(includeText = includeText) + } + def withIncludeText(includeText: Boolean): SaveOptions = { + copy(includeText = Option(includeText)) + } +} +object SaveOptions { + + def apply(includeText: Option[Boolean]): SaveOptions = new SaveOptions(includeText) + def apply(includeText: Boolean): SaveOptions = new SaveOptions(Option(includeText)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/ServerCapabilities.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/ServerCapabilities.scala new file mode 100644 index 000000000..c40b895e5 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/ServerCapabilities.scala @@ -0,0 +1,44 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver +final class ServerCapabilities private ( + val textDocumentSync: Option[sbt.internal.langserver.TextDocumentSyncOptions], + /** The server provides hover support. */ + val hoverProvider: Option[Boolean]) extends Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: ServerCapabilities => (this.textDocumentSync == x.textDocumentSync) && (this.hoverProvider == x.hoverProvider) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (17 + "sbt.internal.langserver.ServerCapabilities".##) + textDocumentSync.##) + hoverProvider.##) + } + override def toString: String = { + "ServerCapabilities(" + textDocumentSync + ", " + hoverProvider + ")" + } + protected[this] def copy(textDocumentSync: Option[sbt.internal.langserver.TextDocumentSyncOptions] = textDocumentSync, hoverProvider: Option[Boolean] = hoverProvider): ServerCapabilities = { + new ServerCapabilities(textDocumentSync, hoverProvider) + } + def withTextDocumentSync(textDocumentSync: Option[sbt.internal.langserver.TextDocumentSyncOptions]): ServerCapabilities = { + copy(textDocumentSync = textDocumentSync) + } + def withTextDocumentSync(textDocumentSync: sbt.internal.langserver.TextDocumentSyncOptions): ServerCapabilities = { + copy(textDocumentSync = Option(textDocumentSync)) + } + def withHoverProvider(hoverProvider: Option[Boolean]): ServerCapabilities = { + copy(hoverProvider = hoverProvider) + } + def withHoverProvider(hoverProvider: Boolean): ServerCapabilities = { + copy(hoverProvider = Option(hoverProvider)) + } +} +object ServerCapabilities { + + def apply(textDocumentSync: Option[sbt.internal.langserver.TextDocumentSyncOptions], hoverProvider: Option[Boolean]): ServerCapabilities = new ServerCapabilities(textDocumentSync, hoverProvider) + def apply(textDocumentSync: sbt.internal.langserver.TextDocumentSyncOptions, hoverProvider: Boolean): ServerCapabilities = new ServerCapabilities(Option(textDocumentSync), Option(hoverProvider)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/TextDocumentSyncOptions.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/TextDocumentSyncOptions.scala new file mode 100644 index 000000000..d94f50428 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/TextDocumentSyncOptions.scala @@ -0,0 +1,64 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver +final class TextDocumentSyncOptions private ( + val openClose: Option[Boolean], + val change: Option[Long], + val willSave: Option[Boolean], + val willSaveWaitUntil: Option[Boolean], + val save: Option[sbt.internal.langserver.SaveOptions]) extends Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: TextDocumentSyncOptions => (this.openClose == x.openClose) && (this.change == x.change) && (this.willSave == x.willSave) && (this.willSaveWaitUntil == x.willSaveWaitUntil) && (this.save == x.save) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.langserver.TextDocumentSyncOptions".##) + openClose.##) + change.##) + willSave.##) + willSaveWaitUntil.##) + save.##) + } + override def toString: String = { + "TextDocumentSyncOptions(" + openClose + ", " + change + ", " + willSave + ", " + willSaveWaitUntil + ", " + save + ")" + } + protected[this] def copy(openClose: Option[Boolean] = openClose, change: Option[Long] = change, willSave: Option[Boolean] = willSave, willSaveWaitUntil: Option[Boolean] = willSaveWaitUntil, save: Option[sbt.internal.langserver.SaveOptions] = save): TextDocumentSyncOptions = { + new TextDocumentSyncOptions(openClose, change, willSave, willSaveWaitUntil, save) + } + def withOpenClose(openClose: Option[Boolean]): TextDocumentSyncOptions = { + copy(openClose = openClose) + } + def withOpenClose(openClose: Boolean): TextDocumentSyncOptions = { + copy(openClose = Option(openClose)) + } + def withChange(change: Option[Long]): TextDocumentSyncOptions = { + copy(change = change) + } + def withChange(change: Long): TextDocumentSyncOptions = { + copy(change = Option(change)) + } + def withWillSave(willSave: Option[Boolean]): TextDocumentSyncOptions = { + copy(willSave = willSave) + } + def withWillSave(willSave: Boolean): TextDocumentSyncOptions = { + copy(willSave = Option(willSave)) + } + def withWillSaveWaitUntil(willSaveWaitUntil: Option[Boolean]): TextDocumentSyncOptions = { + copy(willSaveWaitUntil = willSaveWaitUntil) + } + def withWillSaveWaitUntil(willSaveWaitUntil: Boolean): TextDocumentSyncOptions = { + copy(willSaveWaitUntil = Option(willSaveWaitUntil)) + } + def withSave(save: Option[sbt.internal.langserver.SaveOptions]): TextDocumentSyncOptions = { + copy(save = save) + } + def withSave(save: sbt.internal.langserver.SaveOptions): TextDocumentSyncOptions = { + copy(save = Option(save)) + } +} +object TextDocumentSyncOptions { + + def apply(openClose: Option[Boolean], change: Option[Long], willSave: Option[Boolean], willSaveWaitUntil: Option[Boolean], save: Option[sbt.internal.langserver.SaveOptions]): TextDocumentSyncOptions = new TextDocumentSyncOptions(openClose, change, willSave, willSaveWaitUntil, save) + def apply(openClose: Boolean, change: Long, willSave: Boolean, willSaveWaitUntil: Boolean, save: sbt.internal.langserver.SaveOptions): TextDocumentSyncOptions = new TextDocumentSyncOptions(Option(openClose), Option(change), Option(willSave), Option(willSaveWaitUntil), Option(save)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/ClientCapabilitiesFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/ClientCapabilitiesFormats.scala new file mode 100644 index 000000000..56686a509 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/ClientCapabilitiesFormats.scala @@ -0,0 +1,27 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait ClientCapabilitiesFormats { self: sjsonnew.BasicJsonProtocol => +implicit lazy val ClientCapabilitiesFormat: JsonFormat[sbt.internal.langserver.ClientCapabilities] = new JsonFormat[sbt.internal.langserver.ClientCapabilities] { + override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.langserver.ClientCapabilities = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + + unbuilder.endObject() + sbt.internal.langserver.ClientCapabilities() + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.langserver.ClientCapabilities, builder: Builder[J]): Unit = { + builder.beginObject() + + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/DiagnosticFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/DiagnosticFormats.scala new file mode 100644 index 000000000..84db48020 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/DiagnosticFormats.scala @@ -0,0 +1,35 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait DiagnosticFormats { self: sbt.internal.langserver.codec.RangeFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val DiagnosticFormat: JsonFormat[sbt.internal.langserver.Diagnostic] = new JsonFormat[sbt.internal.langserver.Diagnostic] { + override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.langserver.Diagnostic = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val range = unbuilder.readField[sbt.internal.langserver.Range]("range") + val severity = unbuilder.readField[Option[Long]]("severity") + val code = unbuilder.readField[Option[String]]("code") + val source = unbuilder.readField[Option[String]]("source") + val message = unbuilder.readField[String]("message") + unbuilder.endObject() + sbt.internal.langserver.Diagnostic(range, severity, code, source, message) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.langserver.Diagnostic, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("range", obj.range) + builder.addField("severity", obj.severity) + builder.addField("code", obj.code) + builder.addField("source", obj.source) + builder.addField("message", obj.message) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/InitializeParamsFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/InitializeParamsFormats.scala new file mode 100644 index 000000000..1172ead12 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/InitializeParamsFormats.scala @@ -0,0 +1,37 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait InitializeParamsFormats { self: sbt.internal.util.codec.JValueFormats with sbt.internal.langserver.codec.ClientCapabilitiesFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val InitializeParamsFormat: JsonFormat[sbt.internal.langserver.InitializeParams] = new JsonFormat[sbt.internal.langserver.InitializeParams] { + override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.langserver.InitializeParams = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val processId = unbuilder.readField[Option[Long]]("processId") + val rootPath = unbuilder.readField[Option[String]]("rootPath") + val rootUri = unbuilder.readField[Option[String]]("rootUri") + val initializationOptions = unbuilder.readField[Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]]("initializationOptions") + val capabilities = unbuilder.readField[Option[sbt.internal.langserver.ClientCapabilities]]("capabilities") + val trace = unbuilder.readField[Option[String]]("trace") + unbuilder.endObject() + sbt.internal.langserver.InitializeParams(processId, rootPath, rootUri, initializationOptions, capabilities, trace) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.langserver.InitializeParams, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("processId", obj.processId) + builder.addField("rootPath", obj.rootPath) + builder.addField("rootUri", obj.rootUri) + builder.addField("initializationOptions", obj.initializationOptions) + builder.addField("capabilities", obj.capabilities) + builder.addField("trace", obj.trace) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/InitializeResultFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/InitializeResultFormats.scala new file mode 100644 index 000000000..bcad303fe --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/InitializeResultFormats.scala @@ -0,0 +1,27 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait InitializeResultFormats { self: sbt.internal.langserver.codec.ServerCapabilitiesFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val InitializeResultFormat: JsonFormat[sbt.internal.langserver.InitializeResult] = new JsonFormat[sbt.internal.langserver.InitializeResult] { + override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.langserver.InitializeResult = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val capabilities = unbuilder.readField[sbt.internal.langserver.ServerCapabilities]("capabilities") + unbuilder.endObject() + sbt.internal.langserver.InitializeResult(capabilities) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.langserver.InitializeResult, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("capabilities", obj.capabilities) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/JsonProtocol.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/JsonProtocol.scala new file mode 100644 index 000000000..24ca637e4 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/JsonProtocol.scala @@ -0,0 +1,20 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver.codec +trait JsonProtocol extends sjsonnew.BasicJsonProtocol + with sbt.internal.langserver.codec.PositionFormats + with sbt.internal.langserver.codec.RangeFormats + with sbt.internal.langserver.codec.LocationFormats + with sbt.internal.langserver.codec.DiagnosticFormats + with sbt.internal.util.codec.JValueFormats + with sbt.internal.langserver.codec.ClientCapabilitiesFormats + with sbt.internal.langserver.codec.InitializeParamsFormats + with sbt.internal.langserver.codec.SaveOptionsFormats + with sbt.internal.langserver.codec.TextDocumentSyncOptionsFormats + with sbt.internal.langserver.codec.ServerCapabilitiesFormats + with sbt.internal.langserver.codec.InitializeResultFormats + with sbt.internal.langserver.codec.PublishDiagnosticsParamsFormats +object JsonProtocol extends JsonProtocol \ No newline at end of file diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/LocationFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/LocationFormats.scala new file mode 100644 index 000000000..28a116054 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/LocationFormats.scala @@ -0,0 +1,29 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait LocationFormats { self: sbt.internal.langserver.codec.RangeFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val LocationFormat: JsonFormat[sbt.internal.langserver.Location] = new JsonFormat[sbt.internal.langserver.Location] { + override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.langserver.Location = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val uri = unbuilder.readField[String]("uri") + val range = unbuilder.readField[sbt.internal.langserver.Range]("range") + unbuilder.endObject() + sbt.internal.langserver.Location(uri, range) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.langserver.Location, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("uri", obj.uri) + builder.addField("range", obj.range) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/PositionFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/PositionFormats.scala new file mode 100644 index 000000000..0b5b4b6d9 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/PositionFormats.scala @@ -0,0 +1,29 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait PositionFormats { self: sjsonnew.BasicJsonProtocol => +implicit lazy val PositionFormat: JsonFormat[sbt.internal.langserver.Position] = new JsonFormat[sbt.internal.langserver.Position] { + override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.langserver.Position = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val line = unbuilder.readField[Long]("line") + val character = unbuilder.readField[Long]("character") + unbuilder.endObject() + sbt.internal.langserver.Position(line, character) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.langserver.Position, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("line", obj.line) + builder.addField("character", obj.character) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/PublishDiagnosticsParamsFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/PublishDiagnosticsParamsFormats.scala new file mode 100644 index 000000000..42e3d710f --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/PublishDiagnosticsParamsFormats.scala @@ -0,0 +1,29 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait PublishDiagnosticsParamsFormats { self: sbt.internal.langserver.codec.DiagnosticFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val PublishDiagnosticsParamsFormat: JsonFormat[sbt.internal.langserver.PublishDiagnosticsParams] = new JsonFormat[sbt.internal.langserver.PublishDiagnosticsParams] { + override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.langserver.PublishDiagnosticsParams = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val uri = unbuilder.readField[String]("uri") + val diagnostics = unbuilder.readField[Vector[sbt.internal.langserver.Diagnostic]]("diagnostics") + unbuilder.endObject() + sbt.internal.langserver.PublishDiagnosticsParams(uri, diagnostics) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.langserver.PublishDiagnosticsParams, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("uri", obj.uri) + builder.addField("diagnostics", obj.diagnostics) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/RangeFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/RangeFormats.scala new file mode 100644 index 000000000..5541227fb --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/RangeFormats.scala @@ -0,0 +1,29 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait RangeFormats { self: sbt.internal.langserver.codec.PositionFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val RangeFormat: JsonFormat[sbt.internal.langserver.Range] = new JsonFormat[sbt.internal.langserver.Range] { + override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.langserver.Range = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val start = unbuilder.readField[sbt.internal.langserver.Position]("start") + val end = unbuilder.readField[sbt.internal.langserver.Position]("end") + unbuilder.endObject() + sbt.internal.langserver.Range(start, end) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.langserver.Range, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("start", obj.start) + builder.addField("end", obj.end) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/SaveOptionsFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/SaveOptionsFormats.scala new file mode 100644 index 000000000..c59938a0b --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/SaveOptionsFormats.scala @@ -0,0 +1,27 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait SaveOptionsFormats { self: sjsonnew.BasicJsonProtocol => +implicit lazy val SaveOptionsFormat: JsonFormat[sbt.internal.langserver.SaveOptions] = new JsonFormat[sbt.internal.langserver.SaveOptions] { + override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.langserver.SaveOptions = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val includeText = unbuilder.readField[Option[Boolean]]("includeText") + unbuilder.endObject() + sbt.internal.langserver.SaveOptions(includeText) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.langserver.SaveOptions, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("includeText", obj.includeText) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/ServerCapabilitiesFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/ServerCapabilitiesFormats.scala new file mode 100644 index 000000000..4bac79256 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/ServerCapabilitiesFormats.scala @@ -0,0 +1,29 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait ServerCapabilitiesFormats { self: sbt.internal.langserver.codec.TextDocumentSyncOptionsFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val ServerCapabilitiesFormat: JsonFormat[sbt.internal.langserver.ServerCapabilities] = new JsonFormat[sbt.internal.langserver.ServerCapabilities] { + override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.langserver.ServerCapabilities = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val textDocumentSync = unbuilder.readField[Option[sbt.internal.langserver.TextDocumentSyncOptions]]("textDocumentSync") + val hoverProvider = unbuilder.readField[Option[Boolean]]("hoverProvider") + unbuilder.endObject() + sbt.internal.langserver.ServerCapabilities(textDocumentSync, hoverProvider) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.langserver.ServerCapabilities, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("textDocumentSync", obj.textDocumentSync) + builder.addField("hoverProvider", obj.hoverProvider) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/TextDocumentSyncOptionsFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/TextDocumentSyncOptionsFormats.scala new file mode 100644 index 000000000..e1130ee5d --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/TextDocumentSyncOptionsFormats.scala @@ -0,0 +1,35 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait TextDocumentSyncOptionsFormats { self: sbt.internal.langserver.codec.SaveOptionsFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val TextDocumentSyncOptionsFormat: JsonFormat[sbt.internal.langserver.TextDocumentSyncOptions] = new JsonFormat[sbt.internal.langserver.TextDocumentSyncOptions] { + override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.langserver.TextDocumentSyncOptions = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val openClose = unbuilder.readField[Option[Boolean]]("openClose") + val change = unbuilder.readField[Option[Long]]("change") + val willSave = unbuilder.readField[Option[Boolean]]("willSave") + val willSaveWaitUntil = unbuilder.readField[Option[Boolean]]("willSaveWaitUntil") + val save = unbuilder.readField[Option[sbt.internal.langserver.SaveOptions]]("save") + unbuilder.endObject() + sbt.internal.langserver.TextDocumentSyncOptions(openClose, change, willSave, willSaveWaitUntil, save) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.langserver.TextDocumentSyncOptions, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("openClose", obj.openClose) + builder.addField("change", obj.change) + builder.addField("willSave", obj.willSave) + builder.addField("willSaveWaitUntil", obj.willSaveWaitUntil) + builder.addField("save", obj.save) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/protocol/InitializeOption.scala b/protocol/src/main/contraband-scala/sbt/internal/protocol/InitializeOption.scala new file mode 100644 index 000000000..eeda8fa2c --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/protocol/InitializeOption.scala @@ -0,0 +1,36 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.protocol +final class InitializeOption private ( + val token: Option[String]) extends Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: InitializeOption => (this.token == x.token) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (17 + "sbt.internal.protocol.InitializeOption".##) + token.##) + } + override def toString: String = { + "InitializeOption(" + token + ")" + } + protected[this] def copy(token: Option[String] = token): InitializeOption = { + new InitializeOption(token) + } + def withToken(token: Option[String]): InitializeOption = { + copy(token = token) + } + def withToken(token: String): InitializeOption = { + copy(token = Option(token)) + } +} +object InitializeOption { + + def apply(token: Option[String]): InitializeOption = new InitializeOption(token) + def apply(token: String): InitializeOption = new InitializeOption(Option(token)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcMessage.scala b/protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcMessage.scala new file mode 100644 index 000000000..6ae2a51ab --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcMessage.scala @@ -0,0 +1,27 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.protocol +/** A general message as defined by JSON-RPC. */ +abstract class JsonRpcMessage( + val jsonrpc: String) extends Serializable { + + + + + override def equals(o: Any): Boolean = o match { + case x: JsonRpcMessage => (this.jsonrpc == x.jsonrpc) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (17 + "sbt.internal.protocol.JsonRpcMessage".##) + jsonrpc.##) + } + override def toString: String = { + "JsonRpcMessage(" + jsonrpc + ")" + } +} +object JsonRpcMessage { + +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcNotificationMessage.scala b/protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcNotificationMessage.scala new file mode 100644 index 000000000..aa55a3639 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcNotificationMessage.scala @@ -0,0 +1,46 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.protocol +final class JsonRpcNotificationMessage private ( + jsonrpc: String, + /** The method to be invoked. */ + val method: String, + /** The method's params. */ + val params: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]) extends sbt.internal.protocol.JsonRpcMessage(jsonrpc) with Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: JsonRpcNotificationMessage => (this.jsonrpc == x.jsonrpc) && (this.method == x.method) && (this.params == x.params) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (37 * (17 + "sbt.internal.protocol.JsonRpcNotificationMessage".##) + jsonrpc.##) + method.##) + params.##) + } + override def toString: String = { + s"""JsonRpcNotificationMessage($jsonrpc, $method, ${sbt.protocol.Serialization.compactPrintJsonOpt(params)})""" + } + protected[this] def copy(jsonrpc: String = jsonrpc, method: String = method, params: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue] = params): JsonRpcNotificationMessage = { + new JsonRpcNotificationMessage(jsonrpc, method, params) + } + def withJsonrpc(jsonrpc: String): JsonRpcNotificationMessage = { + copy(jsonrpc = jsonrpc) + } + def withMethod(method: String): JsonRpcNotificationMessage = { + copy(method = method) + } + def withParams(params: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): JsonRpcNotificationMessage = { + copy(params = params) + } + def withParams(params: sjsonnew.shaded.scalajson.ast.unsafe.JValue): JsonRpcNotificationMessage = { + copy(params = Option(params)) + } +} +object JsonRpcNotificationMessage { + + def apply(jsonrpc: String, method: String, params: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): JsonRpcNotificationMessage = new JsonRpcNotificationMessage(jsonrpc, method, params) + def apply(jsonrpc: String, method: String, params: sjsonnew.shaded.scalajson.ast.unsafe.JValue): JsonRpcNotificationMessage = new JsonRpcNotificationMessage(jsonrpc, method, Option(params)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcRequestMessage.scala b/protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcRequestMessage.scala new file mode 100644 index 000000000..f5943e1f7 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcRequestMessage.scala @@ -0,0 +1,51 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.protocol +final class JsonRpcRequestMessage private ( + jsonrpc: String, + /** The request id. */ + val id: String, + /** The method to be invoked. */ + val method: String, + /** The method's params. */ + val params: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]) extends sbt.internal.protocol.JsonRpcMessage(jsonrpc) with Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: JsonRpcRequestMessage => (this.jsonrpc == x.jsonrpc) && (this.id == x.id) && (this.method == x.method) && (this.params == x.params) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.protocol.JsonRpcRequestMessage".##) + jsonrpc.##) + id.##) + method.##) + params.##) + } + override def toString: String = { + s"""JsonRpcRequestMessage($jsonrpc, $id, $method, ${sbt.protocol.Serialization.compactPrintJsonOpt(params)}})""" + } + protected[this] def copy(jsonrpc: String = jsonrpc, id: String = id, method: String = method, params: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue] = params): JsonRpcRequestMessage = { + new JsonRpcRequestMessage(jsonrpc, id, method, params) + } + def withJsonrpc(jsonrpc: String): JsonRpcRequestMessage = { + copy(jsonrpc = jsonrpc) + } + def withId(id: String): JsonRpcRequestMessage = { + copy(id = id) + } + def withMethod(method: String): JsonRpcRequestMessage = { + copy(method = method) + } + def withParams(params: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): JsonRpcRequestMessage = { + copy(params = params) + } + def withParams(params: sjsonnew.shaded.scalajson.ast.unsafe.JValue): JsonRpcRequestMessage = { + copy(params = Option(params)) + } +} +object JsonRpcRequestMessage { + + def apply(jsonrpc: String, id: String, method: String, params: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): JsonRpcRequestMessage = new JsonRpcRequestMessage(jsonrpc, id, method, params) + def apply(jsonrpc: String, id: String, method: String, params: sjsonnew.shaded.scalajson.ast.unsafe.JValue): JsonRpcRequestMessage = new JsonRpcRequestMessage(jsonrpc, id, method, Option(params)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcResponseError.scala b/protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcResponseError.scala new file mode 100644 index 000000000..9ece99852 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcResponseError.scala @@ -0,0 +1,50 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.protocol +final class JsonRpcResponseError private ( + /** A number indicating the error type that occurred. */ + val code: Long, + /** A string providing a short description of the error. */ + val message: String, + /** + * A Primitive or Structured value that contains additional + * information about the error. Can be omitted. + */ + val data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]) extends Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: JsonRpcResponseError => (this.code == x.code) && (this.message == x.message) && (this.data == x.data) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (37 * (17 + "sbt.internal.protocol.JsonRpcResponseError".##) + code.##) + message.##) + data.##) + } + override def toString: String = { + s"""JsonRpcResponseError($code, $message, ${sbt.protocol.Serialization.compactPrintJsonOpt(data)})""" + } + protected[this] def copy(code: Long = code, message: String = message, data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue] = data): JsonRpcResponseError = { + new JsonRpcResponseError(code, message, data) + } + def withCode(code: Long): JsonRpcResponseError = { + copy(code = code) + } + def withMessage(message: String): JsonRpcResponseError = { + copy(message = message) + } + def withData(data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): JsonRpcResponseError = { + copy(data = data) + } + def withData(data: sjsonnew.shaded.scalajson.ast.unsafe.JValue): JsonRpcResponseError = { + copy(data = Option(data)) + } +} +object JsonRpcResponseError { + + def apply(code: Long, message: String, data: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): JsonRpcResponseError = new JsonRpcResponseError(code, message, data) + def apply(code: Long, message: String, data: sjsonnew.shaded.scalajson.ast.unsafe.JValue): JsonRpcResponseError = new JsonRpcResponseError(code, message, Option(data)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcResponseMessage.scala b/protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcResponseMessage.scala new file mode 100644 index 000000000..dd01ae0d3 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/protocol/JsonRpcResponseMessage.scala @@ -0,0 +1,60 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.protocol +final class JsonRpcResponseMessage private ( + jsonrpc: String, + /** The request id. */ + val id: Option[String], + /** + * The result of a request. This can be omitted in + * the case of an error. + */ + val result: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue], + /** The error object in case a request fails. */ + val error: Option[sbt.internal.protocol.JsonRpcResponseError]) extends sbt.internal.protocol.JsonRpcMessage(jsonrpc) with Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: JsonRpcResponseMessage => (this.jsonrpc == x.jsonrpc) && (this.id == x.id) && (this.result == x.result) && (this.error == x.error) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.protocol.JsonRpcResponseMessage".##) + jsonrpc.##) + id.##) + result.##) + error.##) + } + override def toString: String = { + s"""JsonRpcResponseMessage($jsonrpc, $id, ${sbt.protocol.Serialization.compactPrintJsonOpt(result)}, $error)""" + } + protected[this] def copy(jsonrpc: String = jsonrpc, id: Option[String] = id, result: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue] = result, error: Option[sbt.internal.protocol.JsonRpcResponseError] = error): JsonRpcResponseMessage = { + new JsonRpcResponseMessage(jsonrpc, id, result, error) + } + def withJsonrpc(jsonrpc: String): JsonRpcResponseMessage = { + copy(jsonrpc = jsonrpc) + } + def withId(id: Option[String]): JsonRpcResponseMessage = { + copy(id = id) + } + def withId(id: String): JsonRpcResponseMessage = { + copy(id = Option(id)) + } + def withResult(result: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue]): JsonRpcResponseMessage = { + copy(result = result) + } + def withResult(result: sjsonnew.shaded.scalajson.ast.unsafe.JValue): JsonRpcResponseMessage = { + copy(result = Option(result)) + } + def withError(error: Option[sbt.internal.protocol.JsonRpcResponseError]): JsonRpcResponseMessage = { + copy(error = error) + } + def withError(error: sbt.internal.protocol.JsonRpcResponseError): JsonRpcResponseMessage = { + copy(error = Option(error)) + } +} +object JsonRpcResponseMessage { + + def apply(jsonrpc: String, id: Option[String], result: Option[sjsonnew.shaded.scalajson.ast.unsafe.JValue], error: Option[sbt.internal.protocol.JsonRpcResponseError]): JsonRpcResponseMessage = new JsonRpcResponseMessage(jsonrpc, id, result, error) + def apply(jsonrpc: String, id: String, result: sjsonnew.shaded.scalajson.ast.unsafe.JValue, error: sbt.internal.protocol.JsonRpcResponseError): JsonRpcResponseMessage = new JsonRpcResponseMessage(jsonrpc, Option(id), Option(result), Option(error)) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/protocol/codec/InitializeOptionFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/protocol/codec/InitializeOptionFormats.scala new file mode 100644 index 000000000..0329d19cd --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/protocol/codec/InitializeOptionFormats.scala @@ -0,0 +1,27 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.protocol.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait InitializeOptionFormats { self: sjsonnew.BasicJsonProtocol => +implicit lazy val InitializeOptionFormat: JsonFormat[sbt.internal.protocol.InitializeOption] = new JsonFormat[sbt.internal.protocol.InitializeOption] { + override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.protocol.InitializeOption = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val token = unbuilder.readField[Option[String]]("token") + unbuilder.endObject() + sbt.internal.protocol.InitializeOption(token) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.protocol.InitializeOption, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("token", obj.token) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband/jsonrpc.contra b/protocol/src/main/contraband/jsonrpc.contra new file mode 100644 index 000000000..9495b4a7a --- /dev/null +++ b/protocol/src/main/contraband/jsonrpc.contra @@ -0,0 +1,74 @@ +package sbt.internal.protocol +@target(Scala) + +## A general message as defined by JSON-RPC. +interface JsonRpcMessage +@generateCodec(false) +{ + jsonrpc: String! +} + +type JsonRpcRequestMessage implements JsonRpcMessage +@generateCodec(false) +{ + jsonrpc: String! + + ## The request id. + id: String! + + ## The method to be invoked. + method: String! + + ## The method's params. + params: sjsonnew.shaded.scalajson.ast.unsafe.JValue + + #xtostring s"""JsonRpcRequestMessage($jsonrpc, $id, $method, ${sbt.protocol.Serialization.compactPrintJsonOpt(params)}})""" +} + +type JsonRpcResponseMessage implements JsonRpcMessage +@generateCodec(false) +{ + jsonrpc: String! + + ## The request id. + id: String + + ## The result of a request. This can be omitted in + ## the case of an error. + result: sjsonnew.shaded.scalajson.ast.unsafe.JValue + + ## The error object in case a request fails. + error: sbt.internal.protocol.JsonRpcResponseError + + #xtostring s"""JsonRpcResponseMessage($jsonrpc, $id, ${sbt.protocol.Serialization.compactPrintJsonOpt(result)}, $error)""" +} + +type JsonRpcResponseError +@generateCodec(false) +{ + ## A number indicating the error type that occurred. + code: Long! + + ## A string providing a short description of the error. + message: String! + + ## A Primitive or Structured value that contains additional + ## information about the error. Can be omitted. + data: sjsonnew.shaded.scalajson.ast.unsafe.JValue + + #xtostring s"""JsonRpcResponseError($code, $message, ${sbt.protocol.Serialization.compactPrintJsonOpt(data)})""" +} + +type JsonRpcNotificationMessage implements JsonRpcMessage +@generateCodec(false) +{ + jsonrpc: String! + + ## The method to be invoked. + method: String! + + ## The method's params. + params: sjsonnew.shaded.scalajson.ast.unsafe.JValue + + #xtostring s"""JsonRpcNotificationMessage($jsonrpc, $method, ${sbt.protocol.Serialization.compactPrintJsonOpt(params)})""" +} diff --git a/protocol/src/main/contraband/lsp.contra b/protocol/src/main/contraband/lsp.contra new file mode 100644 index 000000000..cfc43ae69 --- /dev/null +++ b/protocol/src/main/contraband/lsp.contra @@ -0,0 +1,112 @@ +package sbt.internal.langserver +@target(Scala) +@codecPackage("sbt.internal.langserver.codec") +@fullCodec("JsonProtocol") + +# Basic structure + +## Position in a text document expressed as zero-based line and zero-based character offset. +## A position is between two characters like an 'insert' cursor in a editor. +type Position { + ## Line position in a document (zero-based). + line: Long! + + ## Character offset on a line in a document (zero-based). + character: Long! +} + +## A range in a text document expressed as (zero-based) start and end positions. A range is comparable to a selection in an editor. +## Therefore the end position is exclusive. +type Range { + ## The range's start position. + start: sbt.internal.langserver.Position! + + ## The range's end position. + end: sbt.internal.langserver.Position! +} + +## Represents a location inside a resource, such as a line inside a text file. +type Location { + uri: String! + range: sbt.internal.langserver.Range! +} + +## Represents a diagnostic, such as a compiler error or warning. +## Diagnostic objects are only valid in the scope of a resource. +type Diagnostic { + ## The range at which the message applies. + range: sbt.internal.langserver.Range! + + ## The diagnostic's severity. Can be omitted. If omitted it is up to the + ## client to interpret diagnostics as error, warning, info or hint. + severity: Long + + ## The diagnostic's code. Can be omitted. + code: String + + ## A human-readable string describing the source of this + ## diagnostic, e.g. 'typescript' or 'super lint'. + source: String + + ## The diagnostic's message. + message: String! +} + +# initialize request +# https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#initialize-request + +type InitializeParams { + processId: Long + + ## The rootPath of the workspace. + rootPath: String + + rootUri: String + + initializationOptions: sjsonnew.shaded.scalajson.ast.unsafe.JValue + + capabilities: sbt.internal.langserver.ClientCapabilities + + trace: String +} + +type ClientCapabilities { +} + +type InitializeResult { + ## The capabilities the language server provides. + capabilities: sbt.internal.langserver.ServerCapabilities! +} + +type ServerCapabilities { + textDocumentSync: sbt.internal.langserver.TextDocumentSyncOptions + + ## The server provides hover support. + hoverProvider: Boolean +} + +type TextDocumentSyncOptions { + openClose: Boolean + change: Long + willSave: Boolean + willSaveWaitUntil: Boolean + save: sbt.internal.langserver.SaveOptions +} + +type SaveOptions { + ## The client is supposed to include the content on save. + includeText: Boolean +} + +# Document + +# PublishDiagnostics Notification https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#textDocument_publishDiagnostics + +## Diagnostics notification are sent from the server to the client to signal results of validation runs. +type PublishDiagnosticsParams { + ## The URI for which diagnostic information is reported. + uri: String! + + ## An array of diagnostic information items. + diagnostics: [sbt.internal.langserver.Diagnostic] +} diff --git a/protocol/src/main/contraband/portfile.contra b/protocol/src/main/contraband/portfile.contra index 82f6567ef..d27df166b 100644 --- a/protocol/src/main/contraband/portfile.contra +++ b/protocol/src/main/contraband/portfile.contra @@ -15,3 +15,7 @@ type TokenFile { uri: String! token: String! } + +type InitializeOption { + token: String +} diff --git a/protocol/src/main/scala/sbt/internal/langserver/DiagnosticSeverity.scala b/protocol/src/main/scala/sbt/internal/langserver/DiagnosticSeverity.scala new file mode 100644 index 000000000..7f208114e --- /dev/null +++ b/protocol/src/main/scala/sbt/internal/langserver/DiagnosticSeverity.scala @@ -0,0 +1,26 @@ +package sbt +package internal +package langserver + +object DiagnosticSeverity { + + /** + * Reports an error. + */ + val Error = 1L + + /** + * Reports a warning. + */ + val Warning = 2L + + /** + * Reports an information. + */ + val Information = 3L + + /** + * Reports a hint. + */ + val Hint = 4L +} diff --git a/protocol/src/main/scala/sbt/internal/langserver/ErrorCodes.scala b/protocol/src/main/scala/sbt/internal/langserver/ErrorCodes.scala new file mode 100644 index 000000000..b6483d032 --- /dev/null +++ b/protocol/src/main/scala/sbt/internal/langserver/ErrorCodes.scala @@ -0,0 +1,19 @@ +package sbt +package internal +package langserver + +object ErrorCodes { + // Defined by JSON RPC + val ParseError = -32700L + val InvalidRequest = -32600L + val MethodNotFound = -32601L + val InvalidParams = -32602L + val InternalError = -32603L + val serverErrorStart = -32099L + val serverErrorEnd = -32000L + val ServerNotInitialized = -32002L + val UnknownErrorCode = -32001L + + // Defined by the protocol. + val RequestCancelled = -32800L +} diff --git a/protocol/src/main/scala/sbt/internal/protocol/codec/JsonRPCProtocol.scala b/protocol/src/main/scala/sbt/internal/protocol/codec/JsonRPCProtocol.scala new file mode 100644 index 000000000..5a8a96aaa --- /dev/null +++ b/protocol/src/main/scala/sbt/internal/protocol/codec/JsonRPCProtocol.scala @@ -0,0 +1,13 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ +package sbt.internal.protocol.codec +trait JsonRPCProtocol + extends sbt.internal.util.codec.JValueFormats + with sjsonnew.BasicJsonProtocol + with sbt.internal.protocol.codec.JsonRpcRequestMessageFormats + with sbt.internal.protocol.codec.JsonRpcResponseErrorFormats + with sbt.internal.protocol.codec.JsonRpcResponseMessageFormats + with sbt.internal.protocol.codec.JsonRpcNotificationMessageFormats + +object JsonRPCProtocol extends JsonRPCProtocol diff --git a/protocol/src/main/scala/sbt/internal/protocol/codec/JsonRpcNotificationMessageFormats.scala b/protocol/src/main/scala/sbt/internal/protocol/codec/JsonRpcNotificationMessageFormats.scala new file mode 100644 index 000000000..387a45e03 --- /dev/null +++ b/protocol/src/main/scala/sbt/internal/protocol/codec/JsonRpcNotificationMessageFormats.scala @@ -0,0 +1,40 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ +package sbt.internal.protocol.codec + +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +import sjsonnew.shaded.scalajson.ast.unsafe.JValue + +trait JsonRpcNotificationMessageFormats { + self: sbt.internal.util.codec.JValueFormats with sjsonnew.BasicJsonProtocol => + implicit lazy val JsonRpcNotificationMessageFormat + : JsonFormat[sbt.internal.protocol.JsonRpcNotificationMessage] = + new JsonFormat[sbt.internal.protocol.JsonRpcNotificationMessage] { + override def read[J]( + jsOpt: Option[J], + unbuilder: Unbuilder[J]): sbt.internal.protocol.JsonRpcNotificationMessage = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val jsonrpc = unbuilder.readField[String]("jsonrpc") + val method = unbuilder.readField[String]("method") + val params = unbuilder.lookupField("params") map { + case x: JValue => x + } + unbuilder.endObject() + sbt.internal.protocol.JsonRpcNotificationMessage(jsonrpc, method, params) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.protocol.JsonRpcNotificationMessage, + builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("jsonrpc", obj.jsonrpc) + builder.addField("method", obj.method) + builder.addField("params", obj.params) + builder.endObject() + } + } +} diff --git a/protocol/src/main/scala/sbt/internal/protocol/codec/JsonRpcRequestMessageFormats.scala b/protocol/src/main/scala/sbt/internal/protocol/codec/JsonRpcRequestMessageFormats.scala new file mode 100644 index 000000000..5ef60b221 --- /dev/null +++ b/protocol/src/main/scala/sbt/internal/protocol/codec/JsonRpcRequestMessageFormats.scala @@ -0,0 +1,45 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ +package sbt.internal.protocol.codec + +import sjsonnew.shaded.scalajson.ast.unsafe.JValue +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } + +trait JsonRpcRequestMessageFormats { + self: sbt.internal.util.codec.JValueFormats with sjsonnew.BasicJsonProtocol => + implicit lazy val JsonRpcRequestMessageFormat + : JsonFormat[sbt.internal.protocol.JsonRpcRequestMessage] = + new JsonFormat[sbt.internal.protocol.JsonRpcRequestMessage] { + override def read[J](jsOpt: Option[J], + unbuilder: Unbuilder[J]): sbt.internal.protocol.JsonRpcRequestMessage = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val jsonrpc = unbuilder.readField[String]("jsonrpc") + val id = try { + unbuilder.readField[String]("id") + } catch { + case _ => unbuilder.readField[Long]("id").toString + } + val method = unbuilder.readField[String]("method") + val params = unbuilder.lookupField("params") map { + case x: JValue => x + } + unbuilder.endObject() + sbt.internal.protocol.JsonRpcRequestMessage(jsonrpc, id, method, params) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.protocol.JsonRpcRequestMessage, + builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("jsonrpc", obj.jsonrpc) + builder.addField("id", obj.id) + builder.addField("method", obj.method) + builder.addField("params", obj.params) + builder.endObject() + } + } +} diff --git a/protocol/src/main/scala/sbt/internal/protocol/codec/JsonRpcResponseErrorFormats.scala b/protocol/src/main/scala/sbt/internal/protocol/codec/JsonRpcResponseErrorFormats.scala new file mode 100644 index 000000000..6db41174f --- /dev/null +++ b/protocol/src/main/scala/sbt/internal/protocol/codec/JsonRpcResponseErrorFormats.scala @@ -0,0 +1,39 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ +package sbt.internal.protocol.codec + +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +import sjsonnew.shaded.scalajson.ast.unsafe.JValue + +trait JsonRpcResponseErrorFormats { + self: sbt.internal.util.codec.JValueFormats with sjsonnew.BasicJsonProtocol => + implicit lazy val JsonRpcResponseErrorFormat + : JsonFormat[sbt.internal.protocol.JsonRpcResponseError] = + new JsonFormat[sbt.internal.protocol.JsonRpcResponseError] { + override def read[J](jsOpt: Option[J], + unbuilder: Unbuilder[J]): sbt.internal.protocol.JsonRpcResponseError = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val code = unbuilder.readField[Long]("code") + val message = unbuilder.readField[String]("message") + val data = unbuilder.lookupField("data") map { + case x: JValue => x + } + unbuilder.endObject() + sbt.internal.protocol.JsonRpcResponseError(code, message, data) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.protocol.JsonRpcResponseError, + builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("code", obj.code) + builder.addField("message", obj.message) + builder.addField("data", obj.data) + builder.endObject() + } + } +} diff --git a/protocol/src/main/scala/sbt/internal/protocol/codec/JsonRpcResponseMessageFormats.scala b/protocol/src/main/scala/sbt/internal/protocol/codec/JsonRpcResponseMessageFormats.scala new file mode 100644 index 000000000..b786d7f2a --- /dev/null +++ b/protocol/src/main/scala/sbt/internal/protocol/codec/JsonRpcResponseMessageFormats.scala @@ -0,0 +1,52 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ +package sbt.internal.protocol.codec + +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +import sjsonnew.shaded.scalajson.ast.unsafe.JValue + +trait JsonRpcResponseMessageFormats { + self: sbt.internal.util.codec.JValueFormats + with sbt.internal.protocol.codec.JsonRpcResponseErrorFormats + with sjsonnew.BasicJsonProtocol => + implicit lazy val JsonRpcResponseMessageFormat + : JsonFormat[sbt.internal.protocol.JsonRpcResponseMessage] = + new JsonFormat[sbt.internal.protocol.JsonRpcResponseMessage] { + override def read[J]( + jsOpt: Option[J], + unbuilder: Unbuilder[J]): sbt.internal.protocol.JsonRpcResponseMessage = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val jsonrpc = unbuilder.readField[String]("jsonrpc") + val id = try { + unbuilder.readField[Option[String]]("id") + } catch { + case _ => unbuilder.readField[Option[Long]]("id") map { _.toString } + } + + val result = unbuilder.lookupField("result") map { + case x: JValue => x + } + + val error = + unbuilder.readField[Option[sbt.internal.protocol.JsonRpcResponseError]]("error") + + unbuilder.endObject() + sbt.internal.protocol.JsonRpcResponseMessage(jsonrpc, id, result, error) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.protocol.JsonRpcResponseMessage, + builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("jsonrpc", obj.jsonrpc) + builder.addField("id", obj.id) + builder.addField("result", obj.result) + builder.addField("error", obj.error) + builder.endObject() + } + } +} diff --git a/protocol/src/main/scala/sbt/protocol/Serialization.scala b/protocol/src/main/scala/sbt/protocol/Serialization.scala index 422d9bb51..d363b31ec 100644 --- a/protocol/src/main/scala/sbt/protocol/Serialization.scala +++ b/protocol/src/main/scala/sbt/protocol/Serialization.scala @@ -10,8 +10,15 @@ import sjsonnew.shaded.scalajson.ast.unsafe.{ JValue, JObject, JString } import java.nio.ByteBuffer import scala.util.{ Success, Failure } import sbt.internal.util.StringEvent +import sbt.internal.protocol.{ + JsonRpcRequestMessage, + JsonRpcResponseMessage, + JsonRpcNotificationMessage +} object Serialization { + private[sbt] val VsCode = "application/vscode-jsonrpc; charset=utf-8" + def serializeEvent[A: JsonFormat](event: A): Array[Byte] = { val json: JValue = Converter.toJson[A](event).get CompactPrinter(json).getBytes("UTF-8") @@ -29,6 +36,39 @@ object Serialization { CompactPrinter(json).getBytes("UTF-8") } + /** + * This formats the message according to JSON-RPC. + * http://www.jsonrpc.org/specification + */ + private[sbt] def serializeResponseMessage(message: JsonRpcResponseMessage): Array[Byte] = { + import sbt.internal.protocol.codec.JsonRPCProtocol._ + val json: JValue = Converter.toJson[JsonRpcResponseMessage](message).get + val body = CompactPrinter(json) + val bodyBytes = body.getBytes("UTF-8") + + (s"Content-Length: ${bodyBytes.size}\r\n" + + s"Content-Type: $VsCode\r\n" + + "\r\n" + + body).getBytes("UTF-8") + } + + /** + * This formats the message according to JSON-RPC. + * http://www.jsonrpc.org/specification + */ + private[sbt] def serializeNotificationMessage( + message: JsonRpcNotificationMessage): Array[Byte] = { + import sbt.internal.protocol.codec.JsonRPCProtocol._ + val json: JValue = Converter.toJson[JsonRpcNotificationMessage](message).get + val body = CompactPrinter(json) + val bodyBytes = body.getBytes("UTF-8") + + (s"Content-Length: ${bodyBytes.size}\r\n" + + s"Content-Type: $VsCode\r\n" + + "\r\n" + + body).getBytes("UTF-8") + } + /** * @return A command or an invalid input description */ @@ -98,4 +138,26 @@ object Serialization { Left(s"Parse error: ${e.getMessage}") } } + + private[sbt] def deserializeJsonRequest( + bytes: Seq[Byte]): Either[String, JsonRpcRequestMessage] = { + val buffer = ByteBuffer.wrap(bytes.toArray) + Parser.parseFromByteBuffer(buffer) match { + case Success(json) => + import sbt.internal.protocol.codec.JsonRPCProtocol._ + Converter.fromJson[JsonRpcRequestMessage](json) match { + case Success(msg) => Right(msg) + case Failure(e) => throw e + } + case Failure(e) => + Left(s"Parse error: ${e.getMessage}") + } + } + + private[sbt] def compactPrintJsonOpt(jsonOpt: Option[JValue]): String = { + jsonOpt match { + case Some(x) => CompactPrinter(x) + case _ => "" + } + } } diff --git a/sbt/src/sbt-test/server/handshake/Client.scala b/sbt/src/sbt-test/server/handshake/Client.scala index 2acbdb9bb..2f41f4c18 100644 --- a/sbt/src/sbt-test/server/handshake/Client.scala +++ b/sbt/src/sbt-test/server/handshake/Client.scala @@ -11,19 +11,25 @@ object Client extends App { val host = "127.0.0.1" val delimiter: Byte = '\n'.toByte - println("hello") - Thread.sleep(1000) + lazy val connection = getConnection + lazy val out = connection.getOutputStream + lazy val in = connection.getInputStream - val connection = getConnection - val out = connection.getOutputStream - val in = connection.getInputStream + val t = getToken + val msg0 = s"""{ "type": "InitCommand", "token": "$t" }""" - out.write(s"""{ "type": "InitCommand", "token": "$getToken" }""".getBytes("utf-8")) - out.write(delimiter.toInt) + writeLine(s"Content-Length: ${ msg0.size + 2 }") + writeLine("Content-Type: application/sbt-x1") + writeLine("") + writeLine(msg0) out.flush - out.write("""{ "type": "ExecCommand", "commandLine": "exit" }""".getBytes("utf-8")) - out.write(delimiter.toInt) + writeLine("Content-Length: 49") + writeLine("Content-Type: application/sbt-x1") + writeLine("") + // 12345678901234567890123456789012345678901234567890 + writeLine("""{ "type": "ExecCommand", "commandLine": "exit" }""") + writeLine("") out.flush val baseDirectory = new File(args(0)) @@ -81,4 +87,20 @@ object Client extends App { Thread.sleep(1000) getConnection } + + def writeLine(s: String): Unit = { + if (s != "") { + out.write(s.getBytes("UTF-8")) + } + writeEndLine + } + + def writeEndLine(): Unit = { + val retByte: Byte = '\r'.toByte + val delimiter: Byte = '\n'.toByte + + out.write(retByte.toInt) + out.write(delimiter.toInt) + out.flush + } } diff --git a/sbt/src/sbt-test/server/handshake/test b/sbt/src/sbt-test/server/handshake/test index 9c2ba1cc1..703942376 100644 --- a/sbt/src/sbt-test/server/handshake/test +++ b/sbt/src/sbt-test/server/handshake/test @@ -1,6 +1,6 @@ > show serverPort > runClient + -> shell -$ sleep 1000 $ exists ok.txt diff --git a/vscode-sbt-scala/.vscode/launch.json b/vscode-sbt-scala/.vscode/launch.json new file mode 100644 index 000000000..5201e0897 --- /dev/null +++ b/vscode-sbt-scala/.vscode/launch.json @@ -0,0 +1,33 @@ +{ + "version": "0.2.0", + // List of configurations. Add new configurations or edit existing ones. + "configurations": [ + { + "name": "Launch Client", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--extensionDevelopmentPath=${workspaceRoot}/client" + ], + "stopOnEntry": false, + "sourceMaps": true, + "outFiles": [ + "${workspaceRoot}/client/out/**/*.js" + ] + // "preLaunchTask": "Client Watch" + }, + { + "name": "Attach to Server", + "type": "node", + "request": "attach", + "port": 6009, + "sourceMaps": true, + "outFiles": [ + "${workspaceRoot}/client/server/**/*.js" + ], + "protocol": "legacy" + // "preLaunchTask": "Server Watch" + } + ] +} \ No newline at end of file diff --git a/vscode-sbt-scala/.vscode/settings.json b/vscode-sbt-scala/.vscode/settings.json new file mode 100644 index 000000000..ed40daef9 --- /dev/null +++ b/vscode-sbt-scala/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "files.exclude": { + "out": false // set this to true to hide the "out" folder with the compiled JS files + }, + "search.exclude": { + "out": true // set this to false to include "out" folder in search results + }, + "typescript.tsdk": "./node_modules/typescript/lib", + "typescript.tsc.autoDetect": "off" +} \ No newline at end of file diff --git a/vscode-sbt-scala/.vscode/tasks.json b/vscode-sbt-scala/.vscode/tasks.json new file mode 100644 index 000000000..51026cd2d --- /dev/null +++ b/vscode-sbt-scala/.vscode/tasks.json @@ -0,0 +1,79 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "taskName": "compile", + "dependsOn": [ + "compile:client", + "compile:server" + ], + "problemMatcher": [] + }, + { + "label": "compile:client", + "type": "npm", + "script": "compile:client", + "group": "build", + "presentation": { + "panel": "dedicated", + "reveal": "never" + }, + "problemMatcher": [ + "$tsc" + ] + }, + { + "label": "compile:server", + "type": "npm", + "script": "compile:server", + "group": "build", + "presentation": { + "panel": "dedicated", + "reveal": "never" + }, + "problemMatcher": [ + "$tsc" + ] + }, + { + "taskName": "watch", + "dependsOn": [ + "watch:client", + "watch:server" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [] + }, + { + "label": "watch:client", + "type": "npm", + "script": "watch:client", + "isBackground": true, + "group": "build", + "presentation": { + "panel": "dedicated", + "reveal": "never" + }, + "problemMatcher": [ + "$tsc-watch" + ] + }, + { + "label": "watch:server", + "type": "npm", + "script": "watch:server", + "isBackground": true, + "group": "build", + "presentation": { + "panel": "dedicated", + "reveal": "never" + }, + "problemMatcher": [ + "$tsc-watch" + ] + } + ] +} \ No newline at end of file diff --git a/vscode-sbt-scala/client/.vscodeignore b/vscode-sbt-scala/client/.vscodeignore new file mode 100644 index 000000000..93e28ff2f --- /dev/null +++ b/vscode-sbt-scala/client/.vscodeignore @@ -0,0 +1,9 @@ +.vscode/** +typings/** +out/test/** +test/** +src/** +**/*.map +.gitignore +tsconfig.json +vsc-extension-quickstart.md diff --git a/vscode-sbt-scala/client/README.md b/vscode-sbt-scala/client/README.md new file mode 100644 index 000000000..5c1838a76 --- /dev/null +++ b/vscode-sbt-scala/client/README.md @@ -0,0 +1,6 @@ +Scala language support using sbt +================================ + +This is an experimental Scala language support using sbt as the language server. + +To try this, use sbt 1.1.0-M1 and above. Saving `*.scala` will trigger `compile` task. diff --git a/vscode-sbt-scala/client/images/sbt-logo-455x262.png b/vscode-sbt-scala/client/images/sbt-logo-455x262.png new file mode 100644 index 0000000000000000000000000000000000000000..82f485ef9692ede8f09d296bce9df0ae9c23aa80 GIT binary patch literal 6715 zcmZ`;2T)T{m!=z<5(3f!h9q4Xl303slvBhrzkqOs76ph74ip$bxzCQYP>qBKQH zD1sE}2$)c$2-2nQ(|>k$XLdF-nPkrW?)koR?!D)|cOL$VsR26+KMM^F4ZD#c8cRb% z+W~x;Kumyz!_YAw_~E;!Z+p+e@A^G|7n}!;uDhSB2h8ZEi>C+H!^J)DPN#skhkuVkCt5->`O_$;Kt)aVscyWB=|J^N$%wY9AKbp2wt_Zf=JVEYVdrq25e`q>{# zuB~0p{m6CU;KkQCCMNnJs)CcfcWe^5hup&ho<4;f`c<0Lxp(kGzai${X+X*U_i^Su zj)K#S_GusQj0~Ra_cb3LHJ|LBR7kK#ya~_)(@aWr$j&9=kE@C`%fgSBr&UroXmAXM z=7eyq^+cQdE^uQSDu@`#>r}dTn$eC9W)QJB7hrw-^xYnJsZ#B0^^!cj$0T z);R9kHg(5K|Fzu49oA5q>Hf`l-WsqHmTzWf-CgNa!W=OhfB|@g1!mTu>1K|Qt?Odd z=rkHMfhGz=XxbGBy^=l`dBb+pyGE8hto(T&J;ETOp8iX2yY>$dN{{BIved*+t74D+ zlB(IGu8s|5>fm+EmD#Wm_-Kvn@^4T%Mt+| z_517gb~^JvFA=$&|BKpL`($sz$tgt}^F$kdknqn9sTllEz&|NO#6S6%|0@K*04lsL z(HtZYjxaGXM&xrsC^~b5IYNggUhjCF4E{S8VE!uyK!QA)f5&G2)rU?1Qa}bs;C~Yk z0sWW5%2NRSzx@4A_y7i2Xp8>@pfd#Wu6_Xm#N!zDGPw2sJBJaXmD7K-7y-!E_$@tK z{G;{ewB>pF#ejuCwz0#C;k}W4%c!X*@7^Oi=v{I_G^k9Xi*>N*`LLuh#tSJ`Sd8YO%c=I6Pui72W3pr`p8?=uCycCmH$+(hg zWc5}@>)t|g>LY9vfdL}&$FOY`NPqcabZu*t*F7+MetujHg_&-05A=uXt! zxDPMu2Ug@ETYyx2MSK#PBN|qPXnnX@Z7lSVcNdSP){)jql4(>!THHgofh_aR8^vJD z^U6Sv_jp#r+HGf;r8%>kRctKp=V{}c}YX%!3)JQi*~i59;Pb6Va!>T?Jm4deba*3iZ(-D#d~&ZBtN z&%9to-_+uRx7hp?FzTZO7@x2>pP4MUpUtL`e* z=dx7EwmToUuQ1;&UG-b7Q{a8#A(#RMyZMnL)Fryr;~a?dhz`xr8T9f(u%N!ZEWB%} z*I6R!Zi2Yc9&HT{x{`%(T@mC97_tA=4;~N8cf29&Pw!`WHu=%`tlk9NpDD_YiG*;4 zvPrDLvAXt&{3F%7qI^X`6NC2oZ7CD31SBmAjxmlJxFoBIA!v40NpEVuS@l%>oU4;W zd<(6eMPLM^;Sl$;9~UT32PjDnKkYmt6sflLr%%hl$ugqX+)5Q#nx^?2hJUIwQfXlO zdV{_iDreL6>h_i)+FwbArElByX25yv$dB6nXRC^J(i|U1or`Ohpp4c3P8^d+(A5D!u zt}PIA4T0Dl=o2cX3~kGzj5i#3w!!{12Le;!}LUtapN7}W3WFQGY9H`&uH|_F5k$uKMWq8IH=&RI zX_vo@Re@bEx;QT06dD|l;yohvht7g^E8fV$4OIF4m{F3n%Qb%j$LzwEvGKv^K!n2R zM&R77>98hrJQ=L^a%QgcLLHQzw|oP8b}jmlMm-N&ze-A%xt?eqCr8BdvL#-|q))c7 zn5@4q_X(`bw3`SQ*Y2yG_+{QCtG-r(NzqEX=9b8d=dZu`7V2)5e|tip!u4qc+21y$ zPbw<+)g`9*TC?&kb^AZk2ESV=H;!xiStO}9oM7Poy9uH%E9}~RSzJ?a`!hdOEsm~C-cT;ZN9(sjiV{4hGv64yB zTTKOq+COgUe$9ol_er`feyvX`_y46aAIe1yxbV0_#?W#r?sA%<)PB3oL7XA+z34|; z4RQ^+d0MEFoobB--{DVA-ex(l4CjgEn3Xk6UI zO)`9?HJldpS$S5w88FYGD8qHF#aiD*Jo{%6NNsC@#A-fV!hNXi#nr_T*02uqh)MuzBq zJH?Y~D|nmdgJn=gkmk2E+lvhc$_s5|Vl`Asx1x)%p1CCEv!$cEjYg1BN+5~u-yQMI zTvP-3Z$vj^zS}W}w=zQ5Es5yF2xwXFb91V3CLIpxgC-Kvy`ub3KAyIxY?<8NO+_E- zaCx7h0GClYE#3Ke`WbZ`TWIA|)D9faPjXv|Ov!pAp>(Qgu8yri0~wprNbZxag?G?1 zh3yDXxTqQ*T^;)e*t*RJ$3{qOWX2>k0i9sPf`d9YPk-&YVL)hsS3l%4I?Zs90K)0u zeArO%4hphU@D&>13)8J$i-9((94{L(+OZFJV~NwqJJIED@6D0J+_oa2q^xLYy|Yl@ z`-J;+mBVoibp)C7C{Cp!VZ%HFs^Qk?y$3&U$#U-LDgHdOBLFU7L=EJU+<1B%?D;Gq z*&H_%Gu{2FLj&y@QAG%HyuBWwNubd|N5kxmgGgpdW9Ny>m{OB2{;0ixp>seIw^GpW zgw*P;kgX3Jlv;`r|D1*}ce9T~6UbGA;<5Cl6Udw~Q*>Zg4ik=HFcMm|5e2RHSsx+L z*Y4`4;HJJ~`plXNA-CkhX6bO3&4_$T|Hg5zCQ)ri&I`#KC23CDqG5={u}?8a?MTLd zly5#Y-}Q#Bd3D?7cj@W>QT|kDQ--7B78Ds#FEB*65%yzt`kwy0l$h!dH(;snQm&@D z=_apSBffu_*wTc+t=ycsNHln0Du~QW2R3UZf^3Y4Le&G+%W|(d?a?t0<{J%uoyz zalKfiS57|>8qGmXRSx33Kdvw$F8?N@!U|PAZK%$N?E?0%6>(&4^BF~1FxQ;w?VOuY z4F2UYQ@9KM>oJY0-XUN1y0?MNB_s6+19GO*2b7zDuxWN3w}MeBZ`>*t;OEc%A+v=m zQw`OH0r^D?5*?b3?^oNJeM`%@-%orW@v$OW1Dgo3%0SGwGwR~TRu{;)MOC{Pv^ zw)=CC$l4SV=0Dj#jv-nTdTa%^M*YwP;JCj*&ar&B^QQ-jSMMNpcc<`e#qht%KS+@F zrNiBT8QI-x6wh^1lH@e+`i}GzIX53dMxWXdcvuXU-jHsWE%f6^U&vFYF>IoSf1EuJvJ5DcuyXW>!bJL)G`Ft|1Uw@U_;wulO$fAc(T9oKRndY#8 z_z@B&nG;pmbf|W2F%MT3<@jmcnSMur7PTXL38fw=!K^vA$(pyao5c8!m*~b@-B9k) zG%wRwIMT4N*uU{S8o1Mk8H_^At&Ly9yHW@-TYQ@K|B3Jbrpt=bGfAm8K%bTQBMjlOutA+ciWB7hZP=R2SGQ)cUXBhe?vZ9vLy3O!An4R!Lv-`!|F~bJ zL+KftJ1z;n{+8s+7T-<&^@h^?dC7xqMdk0^{i1o&w#W!C5@mAlD?;r;|E43ZkYX52O;8J!(n6Y+^>(DYTu5F((19PYJ4 zYOGX5_k^0M#+jfM6}=dUII!_vycEZ(g@d}wGk#AmKsaTH2#A;tfu42a(y55r?L|3Z zl#F6EBXw`E0PhZ^f{s`=%DOsmtw~s_Dpoh=t6Fr_5k`lwek7^p8I1on0plhc`!f>3{Mc-*T*5bcbuD?6YIpXoR zMLAs*oJ@P6Zkn6~)T~BGgQ&u~>DHcvHHxWvItGU4_m?QjGi)%Hnw!)b(N*LIOp z=#3t#j#y^UEs_GBqo|{0yqn`EA|;#Wiet~&_SkP%Ej(p(lm*FaqGXhwL5XfJu^JM& zeYZ}o&U?;jAGCagJVv`7JA$ew+`ATF7Jc*nnCh& zS%HYCRKxpd^&EC718%q3Oxc%4pNi7HWd3gCaL+S;Qh3zPjw_hfUM+snd`qG|b_u?y z&B+&01U?-kx2ggsE9SAKS@QKAcAK}=t!uz82^&}UdbcVpSa?cVB#t2>FV|*gSqO&h z>yxj#InEX172^n6W#k7E9lG$TxGbPV`ch+H5E3P}-m+2N%#jdO7yjKs%)Tw9ztlY6 z0}nG`81p#LzVjf>3eSI(6wTkGu{~7h@7MT~9}h2!A5I6evBmKQ>(c?(IQfcV5<2S^ z2p8fjV$irfZ`|iPslsst{;^W<0Hs$>*U2f!#^L^Sm6`>hmfo$f`X!UxZaTlKgknWj zLO>om^44LARTu(Do)#rj9Q#XD=!IanFS6ro^g;dgq9lzP4e@Wi5l?W2XHm*L$Y9$< zGtTo{QTlvJjuwciv^$28A>+^GZ0HY07yb8}&e_Ewa|Hz0dgD!{8@lBBkJ>}2AH>eQ z6}xh`G*3l0jLk)VP8{X4VGJfeS1Hv`Iu~s^*`KZ+&iV$T9N6LBt{MTO_ZCAZXzreR zr+LR&En{O$E~=i@-$ZMK_7WUsH*dew&!-sFwau&)JFcj)tK`B~hcL8Bn-hp_$pRiM z4?I`i25&qLYMXq8Hsj==Tk@uqL^9G27OF{63Qw zpoO*0 zbRa8tSd6S*8K&BVix&FDnN&$huiii;Yd%{eUl9^=d=Ldn@>3=xmE>{It?dNRM8EkjPK3 z-u2-uF|9CWBemIHnb0rAO7?bFg^=BA``tNxp=UqBaGrD!^7f6hURgviy_#L-m6MLm zo{s4X<8qvf3J>F>i@#hF_H~C|8)ayG@+o0;$5CxvTjL%x4;Wj0^cSlx2%R4uR zMq~#-j~3-jh=vGip2hS%=~WkYSJp%Q4mY0&A5aS_p^?-5xoC#`o62;U8X); z&7H>X@MD6q0Hg2C1r@Hg?9@}^yF}b17+J%uuJF@nWTAn&+l@_&#Zhmi(?vTPsag)d z2Yhca&v428T79PS#*ZFXE}0+Vh#IbsF8Z3Wb$>eBJk3wU&bS6GHh$KcKK0X!WVJL( z3%6TZm+ncLE^DMlgjndINKnS_fjjf1e!chKf8|p53tps1e>d;$gqpA<#rF(FP3*E} zUm$q#(05lU!(^cEl(&@PdM^fgWAqC#ct?E%58hE9?rK z?{!n3C^X&}JZnDJ@UyXM+|-7!N>jF~dB&U5>rHs}B3f~{YV^2zNt1hX{AORe+}<0? z!PT?yaJ=szYwbi+u6*H92C>y}BVoE}`%_y+{MjO?uR{8JgmESFV+_Uy|6tK#cQ2UP z;HJd^80mVsSo=KOcVV{cj+msXKXL`yGX5v<#Px=`hbF!C`p&#RgLh;qB_jOXk=N`G zyX)*ugxapa5|TT{VoE?Fr=}0LE;DpR+D zT0)X|8CUol<#xB^Z>egH{ zZ^t6xFglL@ z7q*zo&V?3ut5Au&3-3IK&8k^D4fHf6&6^(l7Sh*?1zN|?Q;|+}6BD_vPPl8uT%9_M zKqvlG+=itHU$VH3WE&%18327u7gyl_>KjwVeE;~CJjfJ0AA;Iv3oPXCfRVl_x + + + + + + + + + + + + + diff --git a/vscode-sbt-scala/client/package-lock.json b/vscode-sbt-scala/client/package-lock.json new file mode 100644 index 000000000..4d7cb9f41 --- /dev/null +++ b/vscode-sbt-scala/client/package-lock.json @@ -0,0 +1,2256 @@ +{ + "name": "vscode-sbt-scala", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "requires": { + "arr-flatten": "1.1.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "array-differ": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=" + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "beeper": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", + "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=" + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "requires": { + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.2" + } + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=" + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "clone": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz", + "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=" + }, + "clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=" + }, + "clone-stats": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=" + }, + "cloneable-readable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.0.0.tgz", + "integrity": "sha1-pikNQT8hemEjL5XkWP84QYz7ARc=", + "requires": { + "inherits": "2.0.3", + "process-nextick-args": "1.0.7", + "through2": "2.0.3" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "convert-source-map": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", + "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "requires": { + "boom": "2.10.1" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "dateformat": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.0.0.tgz", + "integrity": "sha1-J0Pjq7XD/CRi5SfcpEXgTp9N7hc=" + }, + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "requires": { + "ms": "2.0.0" + } + }, + "deep-assign": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/deep-assign/-/deep-assign-1.0.0.tgz", + "integrity": "sha1-sJJ0O+hCfcYh6gBnzex+cN0Z83s=", + "requires": { + "is-obj": "1.0.1" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "diff": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=" + }, + "duplexer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" + }, + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "requires": { + "readable-stream": "1.1.14" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "duplexify": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.1.tgz", + "integrity": "sha512-j5goxHTwVED1Fpe5hh3q9R93Kip0Bg2KVAt4f8CEYM3UEwYcPSvWbXaUQOzdX/HtiNomipv+gU7ASQPDbV7pGQ==", + "requires": { + "end-of-stream": "1.4.0", + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "stream-shift": "1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "end-of-stream": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", + "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", + "requires": { + "once": "1.4.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "event-stream": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "requires": { + "duplexer": "0.1.1", + "from": "0.1.7", + "map-stream": "0.1.0", + "pause-stream": "0.0.11", + "split": "0.3.3", + "stream-combiner": "0.0.4", + "through": "2.3.8" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "requires": { + "is-posix-bracket": "0.1.1" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "requires": { + "fill-range": "2.2.3" + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "0.1.1" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "requires": { + "is-extglob": "1.0.0" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fancy-log": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.0.tgz", + "integrity": "sha1-Rb4X0Cu5kX1gzP/UmVyZnmyMmUg=", + "requires": { + "chalk": "1.1.3", + "time-stamp": "1.1.0" + } + }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "requires": { + "pend": "1.2.0" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=" + }, + "fill-range": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.7", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + } + }, + "first-chunk-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", + "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=" + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "requires": { + "for-in": "1.0.2" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.2" + } + }, + "generate-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=" + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "requires": { + "is-property": "1.0.2" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + }, + "dependencies": { + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "requires": { + "is-glob": "2.0.1" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "requires": { + "is-extglob": "1.0.0" + } + } + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "requires": { + "is-glob": "3.1.0", + "path-dirname": "1.0.2" + } + }, + "glob-stream": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-5.3.5.tgz", + "integrity": "sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=", + "requires": { + "extend": "3.0.1", + "glob": "5.0.15", + "glob-parent": "3.1.0", + "micromatch": "2.3.11", + "ordered-read-streams": "0.3.0", + "through2": "0.6.5", + "to-absolute-glob": "0.1.1", + "unique-stream": "2.2.1" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "requires": { + "readable-stream": "1.0.34", + "xtend": "4.0.1" + } + } + } + }, + "glogg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz", + "integrity": "sha1-f+DxmfV6yQbPUS/urY+Q7kooT8U=", + "requires": { + "sparkles": "1.0.0" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=" + }, + "gulp-chmod": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/gulp-chmod/-/gulp-chmod-2.0.0.tgz", + "integrity": "sha1-AMOQuSigeZslGsz2MaoJ4BzGKZw=", + "requires": { + "deep-assign": "1.0.0", + "stat-mode": "0.2.2", + "through2": "2.0.3" + } + }, + "gulp-filter": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/gulp-filter/-/gulp-filter-5.0.1.tgz", + "integrity": "sha512-5olRzAhFdXB2klCu1lnazP65aO9YdA/5WfC9VdInIc8PrUeDIoZfaA3Edb0yUBGhVdHv4eHKL9Fg5tUoEJ9z5A==", + "requires": { + "gulp-util": "3.0.8", + "multimatch": "2.1.0", + "streamfilter": "1.0.5" + } + }, + "gulp-gunzip": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/gulp-gunzip/-/gulp-gunzip-0.0.3.tgz", + "integrity": "sha1-e24HsPWP09QlFcSOrVpj3wVy9i8=", + "requires": { + "through2": "0.6.5", + "vinyl": "0.4.6" + }, + "dependencies": { + "clone": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", + "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "requires": { + "readable-stream": "1.0.34", + "xtend": "4.0.1" + } + }, + "vinyl": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", + "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", + "requires": { + "clone": "0.2.0", + "clone-stats": "0.0.1" + } + } + } + }, + "gulp-remote-src": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/gulp-remote-src/-/gulp-remote-src-0.4.3.tgz", + "integrity": "sha1-VyjP1kNDPdSEXd7wlp8PlxoqtKE=", + "requires": { + "event-stream": "3.3.4", + "node.extend": "1.1.6", + "request": "2.79.0", + "through2": "2.0.3", + "vinyl": "2.0.2" + }, + "dependencies": { + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=" + }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=" + }, + "request": { + "version": "2.79.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", + "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.11.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "2.0.6", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "qs": "6.3.2", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.4.3", + "uuid": "3.1.0" + } + }, + "vinyl": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.0.2.tgz", + "integrity": "sha1-CjcT2NTpIhxY8QyhbAEWyeJe2nw=", + "requires": { + "clone": "1.0.2", + "clone-buffer": "1.0.0", + "clone-stats": "1.0.0", + "cloneable-readable": "1.0.0", + "is-stream": "1.1.0", + "remove-trailing-separator": "1.1.0", + "replace-ext": "1.0.0" + } + } + } + }, + "gulp-sourcemaps": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz", + "integrity": "sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=", + "requires": { + "convert-source-map": "1.5.0", + "graceful-fs": "4.1.11", + "strip-bom": "2.0.0", + "through2": "2.0.3", + "vinyl": "1.2.0" + }, + "dependencies": { + "vinyl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", + "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", + "requires": { + "clone": "1.0.2", + "clone-stats": "0.0.1", + "replace-ext": "0.0.1" + } + } + } + }, + "gulp-symdest": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/gulp-symdest/-/gulp-symdest-1.1.0.tgz", + "integrity": "sha1-wWUyBzLRks5W/ZQnH/oSMjS/KuA=", + "requires": { + "event-stream": "3.3.4", + "mkdirp": "0.5.1", + "queue": "3.1.0", + "vinyl-fs": "2.4.4" + } + }, + "gulp-untar": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/gulp-untar/-/gulp-untar-0.0.6.tgz", + "integrity": "sha1-1r3v3n6ajgVMnxYjhaB4LEvnQAA=", + "requires": { + "event-stream": "3.3.4", + "gulp-util": "3.0.8", + "streamifier": "0.1.1", + "tar": "2.2.1", + "through2": "2.0.3" + } + }, + "gulp-util": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", + "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", + "requires": { + "array-differ": "1.0.0", + "array-uniq": "1.0.3", + "beeper": "1.1.1", + "chalk": "1.1.3", + "dateformat": "2.0.0", + "fancy-log": "1.3.0", + "gulplog": "1.0.0", + "has-gulplog": "0.1.0", + "lodash._reescape": "3.0.0", + "lodash._reevaluate": "3.0.0", + "lodash._reinterpolate": "3.0.0", + "lodash.template": "3.6.2", + "minimist": "1.2.0", + "multipipe": "0.1.2", + "object-assign": "3.0.0", + "replace-ext": "0.0.1", + "through2": "2.0.3", + "vinyl": "0.5.3" + } + }, + "gulp-vinyl-zip": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/gulp-vinyl-zip/-/gulp-vinyl-zip-1.4.0.tgz", + "integrity": "sha1-VjgvLMtXIxuwR4x4c3zNVylzvuE=", + "requires": { + "event-stream": "3.3.4", + "queue": "3.1.0", + "through2": "0.6.5", + "vinyl": "0.4.6", + "vinyl-fs": "2.4.4", + "yauzl": "2.8.0", + "yazl": "2.4.2" + }, + "dependencies": { + "clone": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", + "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "requires": { + "readable-stream": "1.0.34", + "xtend": "4.0.1" + } + }, + "vinyl": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", + "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", + "requires": { + "clone": "0.2.0", + "clone-stats": "0.0.1" + } + } + } + }, + "gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "requires": { + "glogg": "1.0.0" + } + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=" + }, + "har-validator": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "requires": { + "chalk": "1.1.3", + "commander": "2.11.0", + "is-my-json-valid": "2.16.1", + "pinkie-promise": "2.0.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" + }, + "has-gulplog": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", + "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", + "requires": { + "sparkles": "1.0.0" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "is": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is/-/is-3.2.1.tgz", + "integrity": "sha1-0Kwq1V63sL7JJqUmb2xmKqqD3KU=" + }, + "is-buffer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", + "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=" + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=" + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "requires": { + "is-primitive": "2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "2.1.1" + } + }, + "is-my-json-valid": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz", + "integrity": "sha512-ochPsqWS1WXj8ZnMIV0vnNXooaMhp7cyL4FMSIPKTtnV0Ha/T19G2b9kkhcNsabV9bxYkze7/aLZJb/bYuFduQ==", + "requires": { + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "jsonpointer": "4.0.1", + "xtend": "4.0.1" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "requires": { + "kind-of": "3.2.2" + } + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=" + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "is-valid-glob": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-0.3.0.tgz", + "integrity": "sha1-1LVcafUYhvm2XHDWwmItN+KfSP4=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=" + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "1.1.5" + } + }, + "lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "requires": { + "readable-stream": "2.3.3" + } + }, + "lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "requires": { + "lodash._basecopy": "3.0.1", + "lodash.keys": "3.1.2" + } + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=" + }, + "lodash._basecreate": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=" + }, + "lodash._basetostring": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", + "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=" + }, + "lodash._basevalues": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", + "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=" + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=" + }, + "lodash._reescape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", + "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=" + }, + "lodash._reevaluate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", + "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=" + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" + }, + "lodash._root": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", + "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=" + }, + "lodash.create": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "requires": { + "lodash._baseassign": "3.2.0", + "lodash._basecreate": "3.0.3", + "lodash._isiterateecall": "3.0.9" + } + }, + "lodash.escape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", + "requires": { + "lodash._root": "3.0.1" + } + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "requires": { + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" + } + }, + "lodash.restparam": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=" + }, + "lodash.template": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", + "requires": { + "lodash._basecopy": "3.0.1", + "lodash._basetostring": "3.0.1", + "lodash._basevalues": "3.0.0", + "lodash._isiterateecall": "3.0.9", + "lodash._reinterpolate": "3.0.0", + "lodash.escape": "3.2.0", + "lodash.keys": "3.1.2", + "lodash.restparam": "3.6.1", + "lodash.templatesettings": "3.1.1" + } + }, + "lodash.templatesettings": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", + "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "requires": { + "lodash._reinterpolate": "3.0.0", + "lodash.escape": "3.2.0" + } + }, + "map-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=" + }, + "merge-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", + "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", + "requires": { + "readable-stream": "2.3.3" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "requires": { + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.2.2", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.4" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "requires": { + "is-extglob": "1.0.0" + } + } + } + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "requires": { + "mime-db": "1.30.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "mocha": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz", + "integrity": "sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg==", + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "debug": "2.6.8", + "diff": "3.2.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.1", + "growl": "1.9.2", + "he": "1.1.1", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + }, + "dependencies": { + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "supports-color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "multimatch": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", + "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", + "requires": { + "array-differ": "1.0.0", + "array-union": "1.0.2", + "arrify": "1.0.1", + "minimatch": "3.0.4" + } + }, + "multipipe": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", + "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "requires": { + "duplexer2": "0.0.2" + } + }, + "node.extend": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/node.extend/-/node.extend-1.1.6.tgz", + "integrity": "sha1-p7iCyC1sk6SGOlUEvV3o7IYli5Y=", + "requires": { + "is": "3.2.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "1.1.0" + } + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=" + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "requires": { + "for-own": "0.1.5", + "is-extendable": "0.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "ordered-read-streams": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz", + "integrity": "sha1-cTfmmzKYuzQiR6G77jiByA4v14s=", + "requires": { + "is-stream": "1.1.0", + "readable-stream": "2.3.3" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "requires": { + "is-extglob": "1.0.0" + } + } + } + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "requires": { + "through": "2.3.8" + } + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "2.0.4" + } + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qs": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", + "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=" + }, + "querystringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-1.0.0.tgz", + "integrity": "sha1-YoYkIRLFtxL6ZU5SZlK/ahP/Bcs=" + }, + "queue": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/queue/-/queue-3.1.0.tgz", + "integrity": "sha1-bEnQHwCeIlZ4h4nyv/rGuLmZBYU=", + "requires": { + "inherits": "2.0.3" + } + }, + "randomatic": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", + "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", + "requires": { + "is-number": "3.0.0", + "kind-of": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "requires": { + "is-equal-shallow": "0.1.3" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "replace-ext": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=" + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + }, + "dependencies": { + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "requires": { + "hoek": "2.16.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "requires": { + "source-map": "0.5.7" + } + }, + "sparkles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz", + "integrity": "sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM=" + }, + "split": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "requires": { + "through": "2.3.8" + } + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "stat-mode": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.2.2.tgz", + "integrity": "sha1-5sgLYjEj19gM8TLOU480YokHJQI=" + }, + "stream-combiner": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "requires": { + "duplexer": "0.1.1" + } + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" + }, + "streamfilter": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/streamfilter/-/streamfilter-1.0.5.tgz", + "integrity": "sha1-h1BxEb644phFFxe1Ec/tjwAqv1M=", + "requires": { + "readable-stream": "2.3.3" + } + }, + "streamifier": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/streamifier/-/streamifier-0.1.1.tgz", + "integrity": "sha1-l+mNj6TRBdYqJpHR3AfoINuN/E8=" + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "requires": { + "is-utf8": "0.2.1" + } + }, + "strip-bom-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz", + "integrity": "sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=", + "requires": { + "first-chunk-stream": "1.0.0", + "strip-bom": "2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "requires": { + "readable-stream": "2.3.3", + "xtend": "4.0.1" + } + }, + "through2-filter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz", + "integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=", + "requires": { + "through2": "2.0.3", + "xtend": "4.0.1" + } + }, + "time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=" + }, + "to-absolute-glob": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz", + "integrity": "sha1-HN+kcqnvUMI57maZm2YsoOs5k38=", + "requires": { + "extend-shallow": "2.0.1" + } + }, + "tough-cookie": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=" + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, + "unique-stream": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.2.1.tgz", + "integrity": "sha1-WqADz76Uxf+GbE59ZouxxNuts2k=", + "requires": { + "json-stable-stringify": "1.0.1", + "through2-filter": "2.0.0" + } + }, + "url-parse": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.1.9.tgz", + "integrity": "sha1-xn8dd11R8KGJEd17P/rSe7nlvRk=", + "requires": { + "querystringify": "1.0.0", + "requires-port": "1.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" + }, + "vali-date": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", + "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "vinyl": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", + "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + "requires": { + "clone": "1.0.2", + "clone-stats": "0.0.1", + "replace-ext": "0.0.1" + } + }, + "vinyl-fs": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-2.4.4.tgz", + "integrity": "sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=", + "requires": { + "duplexify": "3.5.1", + "glob-stream": "5.3.5", + "graceful-fs": "4.1.11", + "gulp-sourcemaps": "1.6.0", + "is-valid-glob": "0.3.0", + "lazystream": "1.0.0", + "lodash.isequal": "4.5.0", + "merge-stream": "1.0.1", + "mkdirp": "0.5.1", + "object-assign": "4.1.1", + "readable-stream": "2.3.3", + "strip-bom": "2.0.0", + "strip-bom-stream": "1.0.0", + "through2": "2.0.3", + "through2-filter": "2.0.0", + "vali-date": "1.0.0", + "vinyl": "1.2.0" + }, + "dependencies": { + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "vinyl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", + "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", + "requires": { + "clone": "1.0.2", + "clone-stats": "0.0.1", + "replace-ext": "0.0.1" + } + } + } + }, + "vinyl-source-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vinyl-source-stream/-/vinyl-source-stream-1.1.0.tgz", + "integrity": "sha1-RMvlEIIFJ53rDFZTwJSiiHk4sas=", + "requires": { + "through2": "0.6.5", + "vinyl": "0.4.6" + }, + "dependencies": { + "clone": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", + "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "requires": { + "readable-stream": "1.0.34", + "xtend": "4.0.1" + } + }, + "vinyl": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", + "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", + "requires": { + "clone": "0.2.0", + "clone-stats": "0.0.1" + } + } + } + }, + "vscode": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.5.tgz", + "integrity": "sha1-EOsQQAGEDD3QgTgV/UoF+PyILRQ=", + "requires": { + "glob": "7.1.2", + "gulp-chmod": "2.0.0", + "gulp-filter": "5.0.1", + "gulp-gunzip": "0.0.3", + "gulp-remote-src": "0.4.3", + "gulp-symdest": "1.1.0", + "gulp-untar": "0.0.6", + "gulp-vinyl-zip": "1.4.0", + "mocha": "3.5.3", + "request": "2.81.0", + "semver": "5.4.1", + "source-map-support": "0.4.18", + "url-parse": "1.1.9", + "vinyl-source-stream": "1.1.0" + } + }, + "vscode-jsonrpc": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.4.0.tgz", + "integrity": "sha1-qpWsWDvzHYD3JdV8J8CfTCz+n6k=" + }, + "vscode-languageclient": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.4.2.tgz", + "integrity": "sha1-LtbuoHJVC6q8m9MkgP8CeHVZiXI=", + "requires": { + "vscode-languageserver-protocol": "3.4.1" + } + }, + "vscode-languageserver-protocol": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.4.1.tgz", + "integrity": "sha1-lrfIo+1opOvTCkB7BCenY3k1/h8=", + "requires": { + "vscode-jsonrpc": "3.4.0", + "vscode-languageserver-types": "3.4.0" + } + }, + "vscode-languageserver-types": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.4.0.tgz", + "integrity": "sha1-UEOuR+5KwWrwe7PQylYSNeDA0vo=" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "yauzl": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.8.0.tgz", + "integrity": "sha1-eUUK/yKyqcWkHvVOAtuQfM+/nuI=", + "requires": { + "buffer-crc32": "0.2.13", + "fd-slicer": "1.0.1" + } + }, + "yazl": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.4.2.tgz", + "integrity": "sha1-FMsZCD4eJacAksFYiqvg9OTdTYg=", + "requires": { + "buffer-crc32": "0.2.13" + } + } + } +} diff --git a/vscode-sbt-scala/client/package.json b/vscode-sbt-scala/client/package.json new file mode 100644 index 000000000..7f1760155 --- /dev/null +++ b/vscode-sbt-scala/client/package.json @@ -0,0 +1,35 @@ +{ + "name": "vscode-sbt-scala", + "displayName": "Scala (sbt)", + "version": "0.0.1", + "author": "Lightbend, Inc.", + "license": "BSD-3-Clause", + "publisher": "lightbend", + "repository": { + "type": "git", + "url": "https://github.com/sbt/sbt" + }, + "description": "Scala language support using sbt", + "icon": "images/sbt-logo-455x262.png", + "engines": { + "vscode": "^1.16.0" + }, + "categories": [ + "Languages" + ], + "activationEvents": [ + "workspaceContains:build.sbt" + ], + "main": "./out/src/extension", + "scripts": { + "vscode:prepublish": "tsc -p ./", + "compile": "tsc -p ./", + "watch": "tsc -w -p ./", + "update-vscode": "node ./node_modules/vscode/bin/install", + "postinstall": "node ./node_modules/vscode/bin/install" + }, + "dependencies": { + "vscode": "^1.1.5", + "vscode-languageclient": "^3.4.2" + } +} diff --git a/vscode-sbt-scala/client/src/extension.ts b/vscode-sbt-scala/client/src/extension.ts new file mode 100644 index 000000000..f4a3eabb4 --- /dev/null +++ b/vscode-sbt-scala/client/src/extension.ts @@ -0,0 +1,45 @@ +'use strict'; + +import * as path from 'path'; + +let fs = require('fs'); +import { ExtensionContext, workspace } from 'vscode'; // workspace, +import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from 'vscode-languageclient'; + +export function activate(context: ExtensionContext) { + // The server is implemented in node + let serverModule = context.asAbsolutePath(path.join('server', 'server.js')); + // The debug options for the server + // let debugOptions = { execArgv: ["--nolazy", "--debug=6009"] }; + + // If the extension is launched in debug mode then the debug server options are used + // Otherwise the run options are used + let serverOptions: ServerOptions = { + run : { module: serverModule, transport: TransportKind.stdio }, + debug: { module: serverModule, transport: TransportKind.stdio } + } + + // Options to control the language client + let clientOptions: LanguageClientOptions = { + documentSelector: [{ language: 'scala', scheme: 'file' }, { language: 'java', scheme: 'file' }], + initializationOptions: () => { + return { + token: discoverToken() + }; + } + } + + // the port file is hardcoded to a particular location relative to the build. + function discoverToken(): String { + let pf = path.join(workspace.rootPath, 'project', 'target', 'active.json'); + let portfile = JSON.parse(fs.readFileSync(pf)); + let tf = portfile.tokenfilePath; + let tokenfile = JSON.parse(fs.readFileSync(tf)); + return tokenfile.token; + } + + // Create the language client and start the client. + let disposable = new LanguageClient('lspSbtScala', 'sbt Scala Language Server', serverOptions, clientOptions).start(); + + context.subscriptions.push(disposable); +} diff --git a/vscode-sbt-scala/client/tsconfig.json b/vscode-sbt-scala/client/tsconfig.json new file mode 100644 index 000000000..c10ad282c --- /dev/null +++ b/vscode-sbt-scala/client/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "target": "es6", + "module": "commonjs", + "moduleResolution": "node", + "rootDir": ".", + "outDir": "out", + "lib": [ "es2016" ], + "sourceMap": true + }, + "exclude": [ + "node_modules", + "server" + ] +} \ No newline at end of file diff --git a/vscode-sbt-scala/package-lock.json b/vscode-sbt-scala/package-lock.json new file mode 100644 index 000000000..5b8616285 --- /dev/null +++ b/vscode-sbt-scala/package-lock.json @@ -0,0 +1,26 @@ +{ + "name": "vscode-sbt-scala", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/mocha": { + "version": "2.2.43", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.43.tgz", + "integrity": "sha512-xNlAmH+lRJdUMXClMTI9Y0pRqIojdxfm7DHsIxoB2iTzu3fnPmSMEN8SsSx0cdwV36d02PWCWaDUoZPDSln+xw==", + "dev": true + }, + "@types/node": { + "version": "6.0.88", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.88.tgz", + "integrity": "sha512-bYDPZTX0/s1aihdjLuAgogUAT5M+TpoWChEMea2p0yOcfn5bu3k6cJb9cp6nw268XeSNIGGr+4+/8V5K6BGzLQ==", + "dev": true + }, + "typescript": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.2.tgz", + "integrity": "sha1-A4qV99m7tCCxvzW6MdTFwd0//jQ=", + "dev": true + } + } +} diff --git a/vscode-sbt-scala/package.json b/vscode-sbt-scala/package.json new file mode 100644 index 000000000..e57bb7b9a --- /dev/null +++ b/vscode-sbt-scala/package.json @@ -0,0 +1,26 @@ +{ + "name": "vscode-sbt-scala", + "displayName": "Scala (sbt)", + "version": "0.0.1", + "author": "Lightbend, Inc.", + "license": "BSD-3-Clause", + "publisher": "lightbend", + "description": "Scala language support for Visual Studio Code using sbt", + "repository": { + "type": "git", + "url": "https://github.com/sbt/sbt" + }, + "scripts": { + "postinstall": "cd server && npm install && cd ../client && npm install && cd ..", + "compile": "tsc -p client/tsconfig.json && cd server && npm run installServer && cd .. && tsc -p server/tsconfig.json", + "compile:client": "tsc -p client/tsconfig.json", + "watch:client": "tsc -w -p client/tsconfig.json", + "compile:server": "cd server && npm run installServer && cd .. && tsc -p server/tsconfig.json", + "watch:server": "cd server && npm run installServer && cd .. && tsc -w -p server/tsconfig.json" + }, + "devDependencies": { + "@types/mocha": "^2.2.42", + "@types/node": "^6.0.88", + "typescript": "^2.5.2" + } +} diff --git a/vscode-sbt-scala/server/package-lock.json b/vscode-sbt-scala/server/package-lock.json new file mode 100644 index 000000000..d56b2fe0e --- /dev/null +++ b/vscode-sbt-scala/server/package-lock.json @@ -0,0 +1,41 @@ +{ + "name": "vscode-sbt-scala", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "vscode-jsonrpc": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.4.0.tgz", + "integrity": "sha1-qpWsWDvzHYD3JdV8J8CfTCz+n6k=" + }, + "vscode-languageserver": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.4.2.tgz", + "integrity": "sha1-CMvlDuJpAdN91LXcUsJbkJNjwfE=", + "requires": { + "vscode-languageserver-protocol": "3.4.1", + "vscode-uri": "1.0.1" + } + }, + "vscode-languageserver-protocol": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.4.1.tgz", + "integrity": "sha1-lrfIo+1opOvTCkB7BCenY3k1/h8=", + "requires": { + "vscode-jsonrpc": "3.4.0", + "vscode-languageserver-types": "3.4.0" + } + }, + "vscode-languageserver-types": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.4.0.tgz", + "integrity": "sha1-UEOuR+5KwWrwe7PQylYSNeDA0vo=" + }, + "vscode-uri": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.1.tgz", + "integrity": "sha1-Eahr7+rDxKo+wIYjZRo8gabQu8g=" + } + } +} diff --git a/vscode-sbt-scala/server/package.json b/vscode-sbt-scala/server/package.json new file mode 100644 index 000000000..dd14d02a2 --- /dev/null +++ b/vscode-sbt-scala/server/package.json @@ -0,0 +1,24 @@ +{ + "name": "vscode-sbt-scala", + "displayName": "Scala (sbt)", + "version": "0.0.1", + "author": "Lightbend, Inc.", + "license": "BSD-3-Clause", + "publisher": "lightbend", + "description": "Relay server to sbt server.", + "repository": { + "type": "git", + "url": "https://github.com/sbt/sbt" + }, + "engines": { + "node": "*" + }, + "dependencies": { + "vscode-languageserver": "^3.4.2" + }, + "scripts": { + "installServer": "installServerIntoExtension ../client ./package.json ./tsconfig.json", + "compile": "installServerIntoExtension ../client ./package.json ./tsconfig.json && tsc -p .", + "watch": "installServerIntoExtension ../client ./package.json ./tsconfig.json && tsc -w -p ." + } +} diff --git a/vscode-sbt-scala/server/src/server.ts b/vscode-sbt-scala/server/src/server.ts new file mode 100644 index 000000000..bef7e50a9 --- /dev/null +++ b/vscode-sbt-scala/server/src/server.ts @@ -0,0 +1,33 @@ +'use strict'; + +import * as path from 'path'; +import * as url from 'url'; +let net = require('net'), + fs = require('fs'), + stdin = process.stdin, + stdout = process.stdout; + +let u = discoverUrl(); + +let socket = net.Socket(); +socket.on('data', (chunk: any) => { + // send it back to stdout + stdout.write(chunk); +}).on('end', () => { + stdin.pause(); +}); +socket.connect(u.port, '127.0.0.1'); + +stdin.resume(); +stdin.on('data', (chunk: any) => { + socket.write(chunk); +}).on('end', () => { + socket.end(); +}); + +// the port file is hardcoded to a particular location relative to the build. +function discoverUrl(): url.Url { + let pf = path.join(process.cwd(), 'project', 'target', 'active.json'); + let portfile = JSON.parse(fs.readFileSync(pf)); + return url.parse(portfile.uri); +} diff --git a/vscode-sbt-scala/server/tsconfig.json b/vscode-sbt-scala/server/tsconfig.json new file mode 100644 index 000000000..1ae7a021a --- /dev/null +++ b/vscode-sbt-scala/server/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "target": "es6", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "lib" : [ "es2016" ], + "outDir": "../client/server" + }, + "exclude": [ + "node_modules" + ] +} \ No newline at end of file From 4fe0d08ab07d1b7a0f1dabfd7eacb4b2cbefda28 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 2 Oct 2017 15:42:55 -0400 Subject: [PATCH 2/6] substitute println with logger --- .../scala/sbt/internal/CommandExchange.scala | 15 ++++++++++-- .../server/LanguageServerProtocol.scala | 8 ++++--- .../sbt/internal/server/NetworkChannel.scala | 24 ++++++++++--------- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/main/src/main/scala/sbt/internal/CommandExchange.scala b/main/src/main/scala/sbt/internal/CommandExchange.scala index 66702e677..6daf56ab0 100644 --- a/main/src/main/scala/sbt/internal/CommandExchange.scala +++ b/main/src/main/scala/sbt/internal/CommandExchange.scala @@ -16,9 +16,10 @@ import scala.util.{ Success, Failure } import sbt.io.syntax._ import sbt.io.Hash import sbt.internal.server._ -import sbt.internal.util.{ StringEvent, ObjectEvent } +import sbt.internal.util.{ StringEvent, ObjectEvent, ConsoleOut, MainAppender } import sbt.internal.util.codec.JValueFormats import sbt.protocol.{ EventMessage, Serialization, ChannelAcceptedEvent } +import sbt.util.{ Level, Logger, LogExchange } /** * The command exchange merges multiple command channels (e.g. network and console), @@ -92,9 +93,19 @@ private[sbt] final class CommandExchange { case Some(xs) => xs case None => Set(ServerAuthentication.Token) } + val serverLogLevel: Level.Value = Level.Debug def onIncomingSocket(socket: Socket, instance: ServerInstance): Unit = { s.log.info(s"new client connected from: ${socket.getPort}") - val channel = new NetworkChannel(newChannelName, socket, Project structure s, auth, instance) + val logger: Logger = { + val loggerName = s"network-${socket.getPort}" + val log = LogExchange.logger(loggerName, None, None) + LogExchange.unbindLoggerAppenders(loggerName) + val appender = MainAppender.defaultScreen(s.globalLogging.console) + LogExchange.bindLoggerAppenders(loggerName, List(appender -> serverLogLevel)) + log + } + val channel = + new NetworkChannel(newChannelName, socket, Project structure s, auth, instance, logger) subscribe(channel) } server match { diff --git a/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala b/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala index 988d5678c..ea84fbed7 100644 --- a/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala @@ -9,6 +9,7 @@ import sbt.internal.protocol._ import sbt.internal.protocol.codec._ import sbt.internal.langserver._ import sbt.internal.util.ObjectEvent +import sbt.util.Logger private[sbt] case class LangServerError(code: Long, message: String) extends Throwable(message) @@ -22,13 +23,14 @@ private[sbt] trait LanguageServerProtocol extends CommandChannel { protected def authenticate(token: String): Boolean protected def authOptions: Set[ServerAuthentication] protected def setInitialized(value: Boolean): Unit + protected def log: Logger protected def onRequestMessage(request: JsonRpcRequestMessage): Unit = { import sbt.internal.langserver.codec.JsonProtocol._ import internalJsonProtocol._ - println(s"onRequestMessage: $request") + log.debug(s"onRequestMessage: $request") request.method match { case "initialize" => if (authOptions(ServerAuthentication.Token)) { @@ -70,7 +72,7 @@ private[sbt] trait LanguageServerProtocol extends CommandChannel { case "xsbti.Problem" => () // ignore case _ => - // println(event) + // log.debug(event) () } } @@ -114,7 +116,7 @@ private[sbt] trait LanguageServerProtocol extends CommandChannel { private[sbt] def langNotify[A: JsonFormat](method: String, params: A): Unit = { val m = JsonRpcNotificationMessage("2.0", method, Option(Converter.toJson[A](params).get)) - println(s"langNotify: $m") + log.debug(s"langNotify: $m") val bytes = Serialization.serializeNotificationMessage(m) publishBytes(bytes) } diff --git a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala index ca1de8ea8..43c01e343 100644 --- a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala +++ b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala @@ -16,12 +16,14 @@ import sbt.internal.langserver.ErrorCodes import sbt.internal.protocol.JsonRpcResponseMessage import sbt.internal.util.ObjectEvent import sbt.internal.util.codec.JValueFormats +import sbt.util.Logger final class NetworkChannel(val name: String, connection: Socket, structure: BuildStructure, auth: Set[ServerAuthentication], - instance: ServerInstance) + instance: ServerInstance, + val log: Logger) extends CommandChannel with LanguageServerProtocol { import NetworkChannel._ @@ -106,7 +108,7 @@ final class NetworkChannel(val name: String, .deserializeCommand(chunk) .fold( errorDesc => - println( + log.error( s"Got invalid chunk from client (${new String(chunk.toArray, "UTF-8")}): " + errorDesc), onCommand ) @@ -117,7 +119,7 @@ final class NetworkChannel(val name: String, case Some(_) => state = InHeader process() - case _ => println("Got invalid chunk from client: " + str) + case _ => log.error("Got invalid chunk from client: " + str) } } case _ => () @@ -133,7 +135,7 @@ final class NetworkChannel(val name: String, handleHeader(str) match { case Some(_) => process() case _ => - println("Got invalid header from client: " + str) + log.error("Got invalid header from client: " + str) resetChannelState() } case _ => () @@ -152,7 +154,7 @@ final class NetworkChannel(val name: String, while (bytesRead != -1 && running.get) { try { bytesRead = in.read(readBuffer) - println(s"bytesRead: $bytesRead") + // log.debug(s"bytesRead: $bytesRead") if (bytesRead > 0) { buffer = buffer ++ readBuffer.toVector.take(bytesRead) } @@ -174,7 +176,7 @@ final class NetworkChannel(val name: String, onRequestMessage(req) } catch { case LangServerError(code, message) => - println(s"sending error: $code: $message") + log.debug(s"sending error: $code: $message") langError(Option(req.id), code, message) } case Left(errorDesc) => @@ -188,12 +190,12 @@ final class NetworkChannel(val name: String, .deserializeCommand(chunk) .fold( errorDesc => - println( + log.error( s"Got invalid chunk from client (${new String(chunk.toArray, "UTF-8")}): " + errorDesc), onCommand ) case _ => - println(s"Unknown Content-Type: $contentType") + log.error(s"Unknown Content-Type: $contentType") } } // if-else } @@ -312,7 +314,7 @@ final class NetworkChannel(val name: String, append( Exec(cmd.commandLine, cmd.execId orElse Some(Exec.newExecId), Some(CommandSource(name)))) } else { - println(s"ignoring command $cmd before initialization") + log.warn(s"ignoring command $cmd before initialization") } } @@ -320,12 +322,12 @@ final class NetworkChannel(val name: String, if (initialized) { StandardMain.exchange publishEventMessage SettingQuery.handleSettingQuery(req, structure) } else { - println(s"ignoring query $req before initialization") + log.warn(s"ignoring query $req before initialization") } } def shutdown(): Unit = { - println("Shutting down client connection") + log.info("Shutting down client connection") running.set(false) out.close() } From 5d7641ee1866a3ab93a24a298113b21d35c8b42e Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 2 Oct 2017 15:52:02 -0400 Subject: [PATCH 3/6] Filtering out mima issues --- build.sbt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.sbt b/build.sbt index fec97e6be..e59cc8169 100644 --- a/build.sbt +++ b/build.sbt @@ -300,6 +300,8 @@ lazy val commandProj = (project in file("main-command")) exclude[DirectMissingMethodProblem]("sbt.internal.server.Server.*"), // Added method to ServerInstance. This is also internal. exclude[ReversedMissingMethodProblem]("sbt.internal.server.ServerInstance.*"), + // Added method to CommandChannel. internal. + exclude[ReversedMissingMethodProblem]("sbt.internal.CommandChannel.*"), ) ) .configure( @@ -380,6 +382,8 @@ lazy val mainProj = (project in file("main")) // New and changed methods on KeyIndex. internal. exclude[ReversedMissingMethodProblem]("sbt.internal.KeyIndex.*"), exclude[DirectMissingMethodProblem]("sbt.internal.KeyIndex.*"), + // Removed unused val. internal. + exclude[DirectMissingMethodProblem]("sbt.internal.RelayAppender.jsonFormat"), ) ) .configure( From f188e60d8f73e23a1630a954c21d6d00e5eaaf30 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 2 Oct 2017 17:12:15 -0400 Subject: [PATCH 4/6] Update test --- main/src/test/scala/sbt/internal/server/SettingQueryTest.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/test/scala/sbt/internal/server/SettingQueryTest.scala b/main/src/test/scala/sbt/internal/server/SettingQueryTest.scala index d7c88e71c..c77d38ed7 100644 --- a/main/src/test/scala/sbt/internal/server/SettingQueryTest.scala +++ b/main/src/test/scala/sbt/internal/server/SettingQueryTest.scala @@ -196,7 +196,7 @@ object SettingQueryTest extends org.specs2.mutable.Specification { "scala.collection.Seq[java.lang.String]") "t/libraryDependencies" in qok( - """[{"organization":"org.scala-lang","name":"scala-library","revision":"2.12.1","isChanging":false,"isTransitive":true,"isForce":false,"crossVersion":{"type":"Disabled"}}]""", + """[{"organization":"org.scala-lang","name":"scala-library","revision":"2.12.1","isChanging":false,"isTransitive":true,"isForce":false,"explicitArtifacts":[],"inclusions":[],"exclusions":[],"extraAttributes":{},"crossVersion":{"type":"Disabled"}}]""", "scala.collection.Seq[sbt.librarymanagement.ModuleID]" ) From a8e770c446fb1e962226005a2eb9a9e08a5c4d84 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Tue, 3 Oct 2017 00:18:58 -0400 Subject: [PATCH 5/6] handle exec as "sbt/exec" --- .../server/LanguageServerProtocol.scala | 11 ++++--- .../sbt/internal/server/NetworkChannel.scala | 14 +++----- .../internal/langserver/SbtExecParams.scala | 33 +++++++++++++++++++ .../langserver/codec/JsonProtocol.scala | 1 + .../codec/SbtExecParamsFormats.scala | 27 +++++++++++++++ protocol/src/main/contraband/lsp.contra | 7 ++++ server.md | 10 +++--- 7 files changed, 85 insertions(+), 18 deletions(-) create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/SbtExecParams.scala create mode 100644 protocol/src/main/contraband-scala/sbt/internal/langserver/codec/SbtExecParamsFormats.scala diff --git a/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala b/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala index ea84fbed7..ba713c631 100644 --- a/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala @@ -30,14 +30,14 @@ private[sbt] trait LanguageServerProtocol extends CommandChannel { import sbt.internal.langserver.codec.JsonProtocol._ import internalJsonProtocol._ + def json = + request.params.getOrElse( + throw LangServerError(ErrorCodes.InvalidParams, + s"param is expected on '${request.method}' method.")) log.debug(s"onRequestMessage: $request") request.method match { case "initialize" => if (authOptions(ServerAuthentication.Token)) { - val json = - request.params.getOrElse( - throw LangServerError(ErrorCodes.InvalidParams, - "param is expected on 'initialize' method.")) val param = Converter.fromJson[InitializeParams](json).get val optionJson = param.initializationOptions.getOrElse( throw LangServerError(ErrorCodes.InvalidParams, @@ -51,6 +51,9 @@ private[sbt] trait LanguageServerProtocol extends CommandChannel { langRespond(InitializeResult(serverCapabilities), Option(request.id)) case "textDocument/didSave" => append(Exec("compile", Some(request.id), Some(CommandSource(name)))) + case "sbt/exec" => + val param = Converter.fromJson[SbtExecParams](json).get + append(Exec(param.commandLine, Some(request.id), Some(CommandSource(name)))) case _ => () } } diff --git a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala index 43c01e343..12d9b33d8 100644 --- a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala +++ b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala @@ -102,17 +102,11 @@ final class NetworkChannel(val name: String, tillEndOfLine match { case Some(chunk) => chunk.headOption match { - case None => // ignore blank line + case None => // ignore blank line case Some(Curly) => - Serialization - .deserializeCommand(chunk) - .fold( - errorDesc => - log.error( - s"Got invalid chunk from client (${new String(chunk.toArray, "UTF-8")}): " + errorDesc), - onCommand - ) - resetChannelState() + // When Content-Length header is not found, interpret the line as JSON message. + handleBody(chunk) + process() case Some(_) => val str = (new String(chunk.toArray, "UTF-8")).trim handleHeader(str) match { diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/SbtExecParams.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/SbtExecParams.scala new file mode 100644 index 000000000..d60cc441b --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/SbtExecParams.scala @@ -0,0 +1,33 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver +/** Command to execute sbt command. */ +final class SbtExecParams private ( + val commandLine: String) extends Serializable { + + + + override def equals(o: Any): Boolean = o match { + case x: SbtExecParams => (this.commandLine == x.commandLine) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (17 + "sbt.internal.langserver.SbtExecParams".##) + commandLine.##) + } + override def toString: String = { + "SbtExecParams(" + commandLine + ")" + } + protected[this] def copy(commandLine: String = commandLine): SbtExecParams = { + new SbtExecParams(commandLine) + } + def withCommandLine(commandLine: String): SbtExecParams = { + copy(commandLine = commandLine) + } +} +object SbtExecParams { + + def apply(commandLine: String): SbtExecParams = new SbtExecParams(commandLine) +} diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/JsonProtocol.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/JsonProtocol.scala index 24ca637e4..a40a00bbe 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/JsonProtocol.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/JsonProtocol.scala @@ -17,4 +17,5 @@ trait JsonProtocol extends sjsonnew.BasicJsonProtocol with sbt.internal.langserver.codec.ServerCapabilitiesFormats with sbt.internal.langserver.codec.InitializeResultFormats with sbt.internal.langserver.codec.PublishDiagnosticsParamsFormats + with sbt.internal.langserver.codec.SbtExecParamsFormats object JsonProtocol extends JsonProtocol \ No newline at end of file diff --git a/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/SbtExecParamsFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/SbtExecParamsFormats.scala new file mode 100644 index 000000000..9447f9180 --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/SbtExecParamsFormats.scala @@ -0,0 +1,27 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.internal.langserver.codec +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait SbtExecParamsFormats { self: sjsonnew.BasicJsonProtocol => +implicit lazy val SbtExecParamsFormat: JsonFormat[sbt.internal.langserver.SbtExecParams] = new JsonFormat[sbt.internal.langserver.SbtExecParams] { + override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.langserver.SbtExecParams = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val commandLine = unbuilder.readField[String]("commandLine") + unbuilder.endObject() + sbt.internal.langserver.SbtExecParams(commandLine) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.internal.langserver.SbtExecParams, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("commandLine", obj.commandLine) + builder.endObject() + } +} +} diff --git a/protocol/src/main/contraband/lsp.contra b/protocol/src/main/contraband/lsp.contra index cfc43ae69..49853a2f4 100644 --- a/protocol/src/main/contraband/lsp.contra +++ b/protocol/src/main/contraband/lsp.contra @@ -110,3 +110,10 @@ type PublishDiagnosticsParams { ## An array of diagnostic information items. diagnostics: [sbt.internal.langserver.Diagnostic] } + +# sbt extension + +## Command to execute sbt command. +type SbtExecParams { + commandLine: String! +} diff --git a/server.md b/server.md index 20c55f508..a172eb5fd 100644 --- a/server.md +++ b/server.md @@ -1,11 +1,13 @@ +### initialize + +```json +{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "initializationOptions": { "token": "************" } } } +``` ### ExecCommand ```json -{ "type": "ExecCommand", "commandLine": "compile" } +{ "jsonrpc": "2.0", "id": 1, "method": "sbt/exec", "params": { "commandLine": "compile" } } ``` -```json -{ "type": "ExecCommand", "commandLine": "eval Thread.sleep(10000)" } -``` From 1ad9360e3e9446eed325fd7259c41b59541393dc Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Tue, 3 Oct 2017 01:45:06 -0400 Subject: [PATCH 6/6] setting query is "sbt/setting" --- .../server/LanguageServerProtocol.scala | 7 ++++++ .../sbt/internal/server/NetworkChannel.scala | 12 ++++++---- .../sbt/internal/server/SettingQuery.scala | 17 +++++++------- server.md | 23 ++++++++++++++++++- 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala b/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala index ba713c631..ad585d6f4 100644 --- a/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala @@ -5,6 +5,7 @@ package server import sjsonnew.JsonFormat import sjsonnew.support.scalajson.unsafe.Converter import sbt.protocol.Serialization +import sbt.protocol.{ SettingQuery => Q } import sbt.internal.protocol._ import sbt.internal.protocol.codec._ import sbt.internal.langserver._ @@ -24,6 +25,7 @@ private[sbt] trait LanguageServerProtocol extends CommandChannel { protected def authOptions: Set[ServerAuthentication] protected def setInitialized(value: Boolean): Unit protected def log: Logger + protected def onSettingQuery(execId: Option[String], req: Q): Unit protected def onRequestMessage(request: JsonRpcRequestMessage): Unit = { @@ -54,6 +56,11 @@ private[sbt] trait LanguageServerProtocol extends CommandChannel { case "sbt/exec" => val param = Converter.fromJson[SbtExecParams](json).get append(Exec(param.commandLine, Some(request.id), Some(CommandSource(name)))) + case "sbt/setting" => { + import sbt.protocol.codec.JsonProtocol._ + val param = Converter.fromJson[Q](json).get + onSettingQuery(Option(request.id), param) + } case _ => () } } diff --git a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala index 12d9b33d8..7044cd9a2 100644 --- a/main/src/main/scala/sbt/internal/server/NetworkChannel.scala +++ b/main/src/main/scala/sbt/internal/server/NetworkChannel.scala @@ -9,11 +9,9 @@ import java.net.{ Socket, SocketTimeoutException } import java.util.concurrent.atomic.AtomicBoolean import sjsonnew._ -import sjsonnew.support.scalajson.unsafe.Converter import scala.annotation.tailrec import sbt.protocol._ import sbt.internal.langserver.ErrorCodes -import sbt.internal.protocol.JsonRpcResponseMessage import sbt.internal.util.ObjectEvent import sbt.internal.util.codec.JValueFormats import sbt.util.Logger @@ -283,7 +281,7 @@ final class NetworkChannel(val name: String, def onCommand(command: CommandMessage): Unit = command match { case x: InitCommand => onInitCommand(x) case x: ExecCommand => onExecCommand(x) - case x: SettingQuery => onSettingQuery(x) + case x: SettingQuery => onSettingQuery(None, x) } private def onInitCommand(cmd: InitCommand): Unit = { @@ -312,9 +310,13 @@ final class NetworkChannel(val name: String, } } - private def onSettingQuery(req: SettingQuery) = { + protected def onSettingQuery(execId: Option[String], req: SettingQuery) = { if (initialized) { - StandardMain.exchange publishEventMessage SettingQuery.handleSettingQuery(req, structure) + import sbt.protocol.codec.JsonProtocol._ + SettingQuery.handleSettingQueryEither(req, structure) match { + case Right(x) => langRespond(x, execId) + case Left(s) => langError(execId, ErrorCodes.InvalidParams, s) + } } else { log.warn(s"ignoring query $req before initialization") } diff --git a/main/src/main/scala/sbt/internal/server/SettingQuery.scala b/main/src/main/scala/sbt/internal/server/SettingQuery.scala index e8c585c18..9b3cd3859 100644 --- a/main/src/main/scala/sbt/internal/server/SettingQuery.scala +++ b/main/src/main/scala/sbt/internal/server/SettingQuery.scala @@ -110,18 +110,19 @@ object SettingQuery { toJson(value) }) - def handleSettingQuery(req: SettingQuery, structure: BuildStructure): SettingQueryResponse = { + def handleSettingQueryEither(req: SettingQuery, + structure: BuildStructure): Either[String, SettingQuerySuccess] = { val key = Parser.parse(req.setting, scopedKeyParser(structure)) - val result = - for { - key <- key - json <- getSettingJsonValue(structure, key) - } yield SettingQuerySuccess(json, key.key.manifest.toString) + for { + key <- key + json <- getSettingJsonValue(structure, key) + } yield SettingQuerySuccess(json, key.key.manifest.toString) + } - result match { + def handleSettingQuery(req: SettingQuery, structure: BuildStructure): SettingQueryResponse = + handleSettingQueryEither(req, structure) match { case Right(x) => x case Left(s) => SettingQueryFailure(s) } - } } diff --git a/server.md b/server.md index a172eb5fd..5afbb6f4f 100644 --- a/server.md +++ b/server.md @@ -1,13 +1,34 @@ +$ cat ~/.sbt/1.0/server/0845deda85cb41abdb9f/token.json + ### initialize ```json { "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "initializationOptions": { "token": "************" } } } ``` -### ExecCommand +### sbt/exec ```json { "jsonrpc": "2.0", "id": 1, "method": "sbt/exec", "params": { "commandLine": "compile" } } ``` +### sbt/setting + +```json +{ "jsonrpc": "2.0", "id": 1, "method": "sbt/setting", "params": { "setting": "root/name" } } +``` + +Here's an example of a bad query: + +```json +{ "jsonrpc": "2.0", "id": 1, "method": "sbt/setting", "params": { "setting": "name" } } +``` + + +``` +Content-Length: 104 +Content-Type: application/vscode-jsonrpc; charset=utf-8 + +{"jsonrpc":"2.0","id":"1","error":{"code":-32602,"message":"Not a valid project ID: name\nname\n ^"}} +```