fake-lsp-server.js 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. // Simple JSON-RPC 2.0 LSP-like fake server over stdio
  2. // Implements a minimal LSP handshake and triggers a request upon notification
  3. let nextId = 1
  4. function encode(message) {
  5. const json = JSON.stringify(message)
  6. const header = `Content-Length: ${Buffer.byteLength(json, "utf8")}\r\n\r\n`
  7. return Buffer.concat([Buffer.from(header, "utf8"), Buffer.from(json, "utf8")])
  8. }
  9. function decodeFrames(buffer) {
  10. const results = []
  11. let idx
  12. while ((idx = buffer.indexOf("\r\n\r\n")) !== -1) {
  13. const header = buffer.slice(0, idx).toString("utf8")
  14. const m = /Content-Length:\s*(\d+)/i.exec(header)
  15. const len = m ? parseInt(m[1], 10) : 0
  16. const bodyStart = idx + 4
  17. const bodyEnd = bodyStart + len
  18. if (buffer.length < bodyEnd) break
  19. const body = buffer.slice(bodyStart, bodyEnd).toString("utf8")
  20. results.push(body)
  21. buffer = buffer.slice(bodyEnd)
  22. }
  23. return { messages: results, rest: buffer }
  24. }
  25. let readBuffer = Buffer.alloc(0)
  26. process.stdin.on("data", (chunk) => {
  27. readBuffer = Buffer.concat([readBuffer, chunk])
  28. const { messages, rest } = decodeFrames(readBuffer)
  29. readBuffer = rest
  30. for (const m of messages) handle(m)
  31. })
  32. function send(msg) {
  33. process.stdout.write(encode(msg))
  34. }
  35. function sendRequest(method, params) {
  36. const id = nextId++
  37. send({ jsonrpc: "2.0", id, method, params })
  38. return id
  39. }
  40. function handle(raw) {
  41. let data
  42. try {
  43. data = JSON.parse(raw)
  44. } catch {
  45. return
  46. }
  47. if (data.method === "initialize") {
  48. send({ jsonrpc: "2.0", id: data.id, result: { capabilities: {} } })
  49. return
  50. }
  51. if (data.method === "initialized") {
  52. return
  53. }
  54. if (data.method === "workspace/didChangeConfiguration") {
  55. return
  56. }
  57. if (data.method === "test/trigger") {
  58. const method = data.params && data.params.method
  59. if (method) sendRequest(method, {})
  60. return
  61. }
  62. if (typeof data.id !== "undefined") {
  63. // Respond OK to any request from client to keep transport flowing
  64. send({ jsonrpc: "2.0", id: data.id, result: null })
  65. return
  66. }
  67. }