diff options
Diffstat (limited to 'packages/lsp/src/config.test.ts')
| -rw-r--r-- | packages/lsp/src/config.test.ts | 394 |
1 files changed, 197 insertions, 197 deletions
diff --git a/packages/lsp/src/config.test.ts b/packages/lsp/src/config.test.ts index 6d51774..0fa27e3 100644 --- a/packages/lsp/src/config.test.ts +++ b/packages/lsp/src/config.test.ts @@ -2,201 +2,201 @@ import { describe, expect, it } from "vitest"; import { resolveServers } from "./config.js"; describe("config", () => { - it("built-in typescript resolves when tsconfig.json exists", async () => { - const { servers } = await resolveServers({ - cwd: "/project", - dispatchLspJson: null, - opencodeJson: null, - exists: async (path) => path === "/project/tsconfig.json", - }); - - const ts = servers.find((s) => s.id === "typescript"); - expect(ts).toBeDefined(); - expect(ts?.command).toEqual(["typescript-language-server", "--stdio"]); - expect(ts?.extensions).toContain(".ts"); - expect(ts?.rootMarkers).toContain("tsconfig.json"); - }); - - it(".dispatch/lsp.json servers resolve", async () => { - const config = JSON.stringify({ - servers: { - mylsp: { - command: ["my-lsp", "--stdio"], - extensions: [".ml"], - rootMarkers: ["Makefile"], - }, - }, - }); - - const { servers } = await resolveServers({ - cwd: "/project", - dispatchLspJson: config, - opencodeJson: null, - exists: async () => false, - }); - - expect(servers).toHaveLength(1); - expect(servers[0]?.id).toBe("mylsp"); - expect(servers[0]?.command).toEqual(["my-lsp", "--stdio"]); - }); - - it("opencode.json lsp is used only as fallback", async () => { - const opencodeConfig = JSON.stringify({ - lsp: { - fallback: { - command: ["fallback-lsp"], - extensions: [".fb"], - }, - }, - }); - - const { servers } = await resolveServers({ - cwd: "/project", - dispatchLspJson: null, - opencodeJson: opencodeConfig, - exists: async () => false, - }); - - expect(servers).toHaveLength(1); - expect(servers[0]?.id).toBe("fallback"); - }); - - it(".dispatch/lsp.json wins over opencode.json", async () => { - const dispatchConfig = JSON.stringify({ - servers: { primary: { command: ["primary-lsp"], extensions: [".p"] } }, - }); - const opencodeConfig = JSON.stringify({ - lsp: { fallback: { command: ["fallback-lsp"], extensions: [".f"] } }, - }); - - const { servers } = await resolveServers({ - cwd: "/project", - dispatchLspJson: dispatchConfig, - opencodeJson: opencodeConfig, - exists: async () => false, - }); - - expect(servers).toHaveLength(1); - expect(servers[0]?.id).toBe("primary"); - }); - - it("luau-lsp sourcemap.autogenerate yields a rojo --watch sidecar", async () => { - const config = JSON.stringify({ - servers: { - luau: { - command: ["luau-lsp", "lsp"], - extensions: [".luau"], - initialization: { - "luau-lsp": { - sourcemap: { - autogenerate: true, - rojoProjectFile: "default.project.json", - }, - }, - }, - }, - }, - }); - - const { servers } = await resolveServers({ - cwd: "/project", - dispatchLspJson: config, - opencodeJson: null, - exists: async () => false, - }); - - expect(servers).toHaveLength(1); - expect(servers[0]?.sidecar).toBeDefined(); - expect(servers[0]?.sidecar?.command).toEqual([ - "rojo", - "sourcemap", - "default.project.json", - "--watch", - "-o", - "sourcemap.json", - ]); - }); - - it("config: resolveServers records configSource", async () => { - // .dispatch/lsp.json entry → ".dispatch/lsp.json" - const dispatch = JSON.stringify({ - servers: { - mylsp: { command: ["my-lsp"], extensions: [".ml"] }, - }, - }); - const fromDispatch = await resolveServers({ - cwd: "/project", - dispatchLspJson: dispatch, - opencodeJson: null, - exists: async () => false, - }); - expect(fromDispatch.servers[0]?.configSource).toBe(".dispatch/lsp.json"); - - // fallback to opencode.json → "opencode.json" - const opencode = JSON.stringify({ - lsp: { - oc: { command: ["oc-lsp"], extensions: [".oc"] }, - }, - }); - const fromOpencode = await resolveServers({ - cwd: "/project", - dispatchLspJson: null, - opencodeJson: opencode, - exists: async () => false, - }); - expect(fromOpencode.servers[0]?.configSource).toBe("opencode.json"); - - // built-in TS → "built-in" - const fromBuiltin = await resolveServers({ - cwd: "/project", - dispatchLspJson: null, - opencodeJson: null, - exists: async () => false, - }); - expect(fromBuiltin.servers[0]?.configSource).toBe("built-in"); - }); - - it("config: shadowed flag is true when .dispatch/lsp.json shadows opencode.json lsp", async () => { - const dispatch = JSON.stringify({ - servers: { primary: { command: ["primary-lsp"], extensions: [".p"] } }, - }); - const opencode = JSON.stringify({ - lsp: { fallback: { command: ["fallback-lsp"], extensions: [".f"] } }, - }); - - const { shadowed, servers } = await resolveServers({ - cwd: "/project", - dispatchLspJson: dispatch, - opencodeJson: opencode, - exists: async () => false, - }); - - // dispatch wins, opencode entry is shadowed - expect(shadowed).toBe(true); - expect(servers.map((s) => s.id)).toEqual(["primary"]); - }); - - it("config: shadowed flag is false when only one config source declares lsp", async () => { - const dispatch = JSON.stringify({ - servers: { primary: { command: ["primary-lsp"], extensions: [".p"] } }, - }); - - // dispatch present, opencode has NO lsp key → not shadowed - const onlyDispatch = await resolveServers({ - cwd: "/project", - dispatchLspJson: dispatch, - opencodeJson: JSON.stringify({ lsp: {} }), - exists: async () => false, - }); - expect(onlyDispatch.shadowed).toBe(false); - - // dispatch absent, opencode has lsp → not shadowed (opencode is used) - const onlyOpencode = await resolveServers({ - cwd: "/project", - dispatchLspJson: null, - opencodeJson: JSON.stringify({ lsp: { fb: { command: ["fb"] } } }), - exists: async () => false, - }); - expect(onlyOpencode.shadowed).toBe(false); - }); + it("built-in typescript resolves when tsconfig.json exists", async () => { + const { servers } = await resolveServers({ + cwd: "/project", + dispatchLspJson: null, + opencodeJson: null, + exists: async (path) => path === "/project/tsconfig.json", + }); + + const ts = servers.find((s) => s.id === "typescript"); + expect(ts).toBeDefined(); + expect(ts?.command).toEqual(["typescript-language-server", "--stdio"]); + expect(ts?.extensions).toContain(".ts"); + expect(ts?.rootMarkers).toContain("tsconfig.json"); + }); + + it(".dispatch/lsp.json servers resolve", async () => { + const config = JSON.stringify({ + servers: { + mylsp: { + command: ["my-lsp", "--stdio"], + extensions: [".ml"], + rootMarkers: ["Makefile"], + }, + }, + }); + + const { servers } = await resolveServers({ + cwd: "/project", + dispatchLspJson: config, + opencodeJson: null, + exists: async () => false, + }); + + expect(servers).toHaveLength(1); + expect(servers[0]?.id).toBe("mylsp"); + expect(servers[0]?.command).toEqual(["my-lsp", "--stdio"]); + }); + + it("opencode.json lsp is used only as fallback", async () => { + const opencodeConfig = JSON.stringify({ + lsp: { + fallback: { + command: ["fallback-lsp"], + extensions: [".fb"], + }, + }, + }); + + const { servers } = await resolveServers({ + cwd: "/project", + dispatchLspJson: null, + opencodeJson: opencodeConfig, + exists: async () => false, + }); + + expect(servers).toHaveLength(1); + expect(servers[0]?.id).toBe("fallback"); + }); + + it(".dispatch/lsp.json wins over opencode.json", async () => { + const dispatchConfig = JSON.stringify({ + servers: { primary: { command: ["primary-lsp"], extensions: [".p"] } }, + }); + const opencodeConfig = JSON.stringify({ + lsp: { fallback: { command: ["fallback-lsp"], extensions: [".f"] } }, + }); + + const { servers } = await resolveServers({ + cwd: "/project", + dispatchLspJson: dispatchConfig, + opencodeJson: opencodeConfig, + exists: async () => false, + }); + + expect(servers).toHaveLength(1); + expect(servers[0]?.id).toBe("primary"); + }); + + it("luau-lsp sourcemap.autogenerate yields a rojo --watch sidecar", async () => { + const config = JSON.stringify({ + servers: { + luau: { + command: ["luau-lsp", "lsp"], + extensions: [".luau"], + initialization: { + "luau-lsp": { + sourcemap: { + autogenerate: true, + rojoProjectFile: "default.project.json", + }, + }, + }, + }, + }, + }); + + const { servers } = await resolveServers({ + cwd: "/project", + dispatchLspJson: config, + opencodeJson: null, + exists: async () => false, + }); + + expect(servers).toHaveLength(1); + expect(servers[0]?.sidecar).toBeDefined(); + expect(servers[0]?.sidecar?.command).toEqual([ + "rojo", + "sourcemap", + "default.project.json", + "--watch", + "-o", + "sourcemap.json", + ]); + }); + + it("config: resolveServers records configSource", async () => { + // .dispatch/lsp.json entry → ".dispatch/lsp.json" + const dispatch = JSON.stringify({ + servers: { + mylsp: { command: ["my-lsp"], extensions: [".ml"] }, + }, + }); + const fromDispatch = await resolveServers({ + cwd: "/project", + dispatchLspJson: dispatch, + opencodeJson: null, + exists: async () => false, + }); + expect(fromDispatch.servers[0]?.configSource).toBe(".dispatch/lsp.json"); + + // fallback to opencode.json → "opencode.json" + const opencode = JSON.stringify({ + lsp: { + oc: { command: ["oc-lsp"], extensions: [".oc"] }, + }, + }); + const fromOpencode = await resolveServers({ + cwd: "/project", + dispatchLspJson: null, + opencodeJson: opencode, + exists: async () => false, + }); + expect(fromOpencode.servers[0]?.configSource).toBe("opencode.json"); + + // built-in TS → "built-in" + const fromBuiltin = await resolveServers({ + cwd: "/project", + dispatchLspJson: null, + opencodeJson: null, + exists: async () => false, + }); + expect(fromBuiltin.servers[0]?.configSource).toBe("built-in"); + }); + + it("config: shadowed flag is true when .dispatch/lsp.json shadows opencode.json lsp", async () => { + const dispatch = JSON.stringify({ + servers: { primary: { command: ["primary-lsp"], extensions: [".p"] } }, + }); + const opencode = JSON.stringify({ + lsp: { fallback: { command: ["fallback-lsp"], extensions: [".f"] } }, + }); + + const { shadowed, servers } = await resolveServers({ + cwd: "/project", + dispatchLspJson: dispatch, + opencodeJson: opencode, + exists: async () => false, + }); + + // dispatch wins, opencode entry is shadowed + expect(shadowed).toBe(true); + expect(servers.map((s) => s.id)).toEqual(["primary"]); + }); + + it("config: shadowed flag is false when only one config source declares lsp", async () => { + const dispatch = JSON.stringify({ + servers: { primary: { command: ["primary-lsp"], extensions: [".p"] } }, + }); + + // dispatch present, opencode has NO lsp key → not shadowed + const onlyDispatch = await resolveServers({ + cwd: "/project", + dispatchLspJson: dispatch, + opencodeJson: JSON.stringify({ lsp: {} }), + exists: async () => false, + }); + expect(onlyDispatch.shadowed).toBe(false); + + // dispatch absent, opencode has lsp → not shadowed (opencode is used) + const onlyOpencode = await resolveServers({ + cwd: "/project", + dispatchLspJson: null, + opencodeJson: JSON.stringify({ lsp: { fb: { command: ["fb"] } } }), + exists: async () => false, + }); + expect(onlyOpencode.shadowed).toBe(false); + }); }); |
