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..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( @@ -407,6 +411,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 c96d8d83d..f4d64983d 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..6daf56ab0 100644 --- a/main/src/main/scala/sbt/internal/CommandExchange.scala +++ b/main/src/main/scala/sbt/internal/CommandExchange.scala @@ -4,19 +4,22 @@ 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, 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), @@ -34,6 +37,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 { @@ -88,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 { @@ -121,9 +136,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 +171,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 +184,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 +200,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 +251,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..ad585d6f4 --- /dev/null +++ b/main/src/main/scala/sbt/internal/server/LanguageServerProtocol.scala @@ -0,0 +1,139 @@ +package sbt +package internal +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._ +import sbt.internal.util.ObjectEvent +import sbt.util.Logger + +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 log: Logger + protected def onSettingQuery(execId: Option[String], req: Q): Unit + + protected def onRequestMessage(request: JsonRpcRequestMessage): Unit = { + + 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 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 "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 _ => () + } + } + + /** + * 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 _ => + // log.debug(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)) + log.debug(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..7044cd9a2 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 scala.annotation.tailrec +import sbt.protocol._ +import sbt.internal.langserver.ErrorCodes +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) - extends CommandChannel { + instance: ServerInstance, + val log: Logger) + 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,62 +66,229 @@ 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) => + // 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 { + case Some(_) => + state = InHeader + process() + case _ => log.error("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 _ => + log.error("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) + // log.debug(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) => + log.debug(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 => + log.error( + s"Got invalid chunk from client (${new String(chunk.toArray, "UTF-8")}): " + errorDesc), + onCommand + ) + case _ => + log.error(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() } 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 = { if (auth(ServerAuthentication.Token)) { cmd.token match { case Some(x) => - instance.authenticate(x) match { + authenticate(x) match { case true => initialized = true publishEventMessage(ChannelAcceptedEvent(name)) @@ -102,21 +306,32 @@ 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") } } - 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 { - 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() } } + +object NetworkChannel { + sealed trait ChannelState + case object SingleLine extends ChannelState + case object InHeader extends ChannelState + case object InBody extends ChannelState +} 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/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]" ) 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/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/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..a40a00bbe --- /dev/null +++ b/protocol/src/main/contraband-scala/sbt/internal/langserver/codec/JsonProtocol.scala @@ -0,0 +1,21 @@ +/** + * 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 + 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/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/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-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..49853a2f4 --- /dev/null +++ b/protocol/src/main/contraband/lsp.contra @@ -0,0 +1,119 @@ +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] +} + +# sbt extension + +## Command to execute sbt command. +type SbtExecParams { + commandLine: String! +} 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/server.md b/server.md index 20c55f508..5afbb6f4f 100644 --- a/server.md +++ b/server.md @@ -1,11 +1,34 @@ +$ cat ~/.sbt/1.0/server/0845deda85cb41abdb9f/token.json -### ExecCommand +### initialize ```json -{ "type": "ExecCommand", "commandLine": "compile" } +{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "initializationOptions": { "token": "************" } } } ``` +### sbt/exec + ```json -{ "type": "ExecCommand", "commandLine": "eval Thread.sleep(10000)" } +{ "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 ^"}} ``` 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 000000000..82f485ef9 Binary files /dev/null and b/vscode-sbt-scala/client/images/sbt-logo-455x262.png differ diff --git a/vscode-sbt-scala/client/images/sbt-logo.svg b/vscode-sbt-scala/client/images/sbt-logo.svg new file mode 100644 index 000000000..d028d0540 --- /dev/null +++ b/vscode-sbt-scala/client/images/sbt-logo.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + 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