fake-lsp-server.js 2.0 KB

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