diff --git a/lua/copilot/config/server.lua b/lua/copilot/config/server.lua index 84b837d9..23aa78c2 100644 --- a/lua/copilot/config/server.lua +++ b/lua/copilot/config/server.lua @@ -1,5 +1,7 @@ +---@alias ServerType string<'nodejs', 'binary'> + ---@class (exact) ServerConfig ----@field type string<'nodejs', 'binary'> Type of the server +---@field type ServerType Type of the server ---@field custom_server_filepath? string|nil Path to the custom server file, can be absolute, relative or a file name (for PATH) local server = { diff --git a/lua/copilot/lsp/binary.lua b/lua/copilot/lsp/binary.lua index a8635d47..029c073b 100644 --- a/lua/copilot/lsp/binary.lua +++ b/lua/copilot/lsp/binary.lua @@ -1,5 +1,6 @@ local util = require("copilot.util") local logger = require("copilot.logger") +local nodejs = require("copilot.lsp.nodejs") local M = { ---@class copilot_server_info @@ -269,10 +270,8 @@ end ---@return table function M.get_execute_command() - return { - M.server_path or M.get_server_path(), - "--stdio", - } + local node_version = nodejs.get_node_version() + return util.get_node_args(M.server_path or M.get_server_path(), "binary", node_version) end ---@return copilot_server_info diff --git a/lua/copilot/lsp/nodejs.lua b/lua/copilot/lsp/nodejs.lua index eb506159..98c6107c 100644 --- a/lua/copilot/lsp/nodejs.lua +++ b/lua/copilot/lsp/nodejs.lua @@ -96,7 +96,9 @@ end ---@return table function M.get_execute_command() - return util.append_command(M.node_command, { M.server_path or M.get_server_path(), "--stdio" }) + local args = util.get_node_args(M.server_path or M.get_server_path(), "nodejs", M.node_version) + + return util.append_command(M.node_command, args) end ---@param node_command? string|string[] diff --git a/lua/copilot/util.lua b/lua/copilot/util.lua index 0942981b..80f176a7 100644 --- a/lua/copilot/util.lua +++ b/lua/copilot/util.lua @@ -187,4 +187,18 @@ function M.append_command(cmd, append) return full_cmd end +---@param server_path string +---@param server_type ServerType +---@param node_version string|nil +---@return string[] +function M.get_node_args(server_path, server_type, node_version) + local args = { server_path, "--stdio" } + local node_version_major = tonumber(string.match(node_version or "", "^(%d+)%.")) or 0 + if (server_type == "nodejs") and (node_version_major < 25) then + table.insert(args, 1, "--experimental-sqlite") + end + + return args +end + return M diff --git a/tests/stubs/nodejs.lua b/tests/stubs/nodejs.lua index 05c35402..0718e0f1 100644 --- a/tests/stubs/nodejs.lua +++ b/tests/stubs/nodejs.lua @@ -39,12 +39,23 @@ function M.process(stdout, code, fail, callback) return captured_args end -M.valid_node_version = "22.0.0" M.invalid_node_version = "10.0.0" +M.valid_node_version_22 = "22.0.0" +M.valid_node_version_24 = "24.0.0" +M.valid_node_version_25 = "25.0.0" ---Convenience wrapper for Stub.process for a valid Node.js version (>= 22) -function M.valid_node(callback) - return M.process("v" .. M.valid_node_version, 0, false, callback) +function M.valid_node_22(callback) + return M.process("v" .. M.valid_node_version_22, 0, false, callback) +end + +---Convenience wrapper for Stub.process for a valid Node.js version (>= 22) +function M.valid_node_24(callback) + return M.process("v" .. M.valid_node_version_24, 0, false, callback) +end + +function M.valid_node_25(callback) + return M.process("v" .. M.valid_node_version_25, 0, false, callback) end ---Convenience wrapper for Stub.process for an invalid Node.js version (< 22) @@ -53,8 +64,9 @@ function M.invalid_node(callback) end ---@param callback function the function to call while vim.api.nvim_get_runtime_file is stubbed +---@param node_function function|nil ---@return string|nil captured_path -- the path vim.api.nvim_get_runtime_file was called with -function M.get_runtime_server_path(callback) +function M.get_runtime_server_path(callback, node_function) local captured_path = nil local original_get_file = vim.api.nvim_get_runtime_file @@ -70,8 +82,12 @@ function M.get_runtime_server_path(callback) return 1 end + if node_function == nil then + node_function = M.valid_node_25 + end + -- stub valid node version for callback so setup() succeeds - M.valid_node(function() + node_function(function() -- wrap callback in pcall to ensure vim.api.nvim_get_runtime_file is restored if callback errors local ok, err = pcall(callback) vim.api.nvim_get_runtime_file = original_get_file diff --git a/tests/test_nodejs.lua b/tests/test_nodejs.lua index 2a53f785..b53572c5 100644 --- a/tests/test_nodejs.lua +++ b/tests/test_nodejs.lua @@ -15,47 +15,47 @@ local T = MiniTest.new_set({ T["get_node_version()"] = MiniTest.new_set() T["get_node_version()"]["default node command"] = function() - local captured_args = stub.valid_node(function() + local captured_args = stub.valid_node_22(function() stub.nodejs.setup() local version, error = stub.nodejs.get_node_version() - eq(version, stub.valid_node_version) + eq(version, stub.valid_node_version_22) eq(error, nil) end) eq(captured_args, { "node", "--version" }) end T["get_node_version()"]["custom node command as string"] = function() - local captured_args = stub.valid_node(function() + local captured_args = stub.valid_node_22(function() stub.nodejs.setup("/usr/local/bin/node") local version, error = stub.nodejs.get_node_version() - eq(version, stub.valid_node_version) + eq(version, stub.valid_node_version_22) eq(error, nil) end) eq(captured_args, { "/usr/local/bin/node", "--version" }) end T["get_node_version()"]["custom node command as string with spaces"] = function() - local captured_args = stub.valid_node(function() + local captured_args = stub.valid_node_22(function() stub.nodejs.setup("/path to/node") local version, error = stub.nodejs.get_node_version() - eq(version, stub.valid_node_version) + eq(version, stub.valid_node_version_22) eq(error, nil) end) eq(captured_args, { "/path to/node", "--version" }) end T["get_node_version()"]["custom node command as table"] = function() - local captured_args = stub.valid_node(function() + local captured_args = stub.valid_node_22(function() stub.nodejs.setup({ "mise", "x", "node@lts", "--", "node" }) local version, error = stub.nodejs.get_node_version() - eq(version, stub.valid_node_version) + eq(version, stub.valid_node_version_22) eq(error, nil) end) eq(captured_args, { "mise", "x", "node@lts", "--", "node", "--version" }) @@ -99,6 +99,24 @@ end T["get_execute_command()"] = MiniTest.new_set() +T["get_execute_command()"]["default node command v22, default server path"] = function() + local captured_path = stub.get_runtime_server_path(function() + eq(stub.nodejs.setup(), true) + local cmd = stub.nodejs.get_execute_command() + eq(cmd, { "node", "--experimental-sqlite", vim.fn.expand(stub.default_server_path), "--stdio" }) + end, stub.valid_node_22) + eq(captured_path, stub.default_server_path) +end + +T["get_execute_command()"]["default node command v24, default server path"] = function() + local captured_path = stub.get_runtime_server_path(function() + eq(stub.nodejs.setup(), true) + local cmd = stub.nodejs.get_execute_command() + eq(cmd, { "node", "--experimental-sqlite", vim.fn.expand(stub.default_server_path), "--stdio" }) + end, stub.valid_node_24) + eq(captured_path, stub.default_server_path) +end + T["get_execute_command()"]["default node command, default server path"] = function() local captured_path = stub.get_runtime_server_path(function() eq(stub.nodejs.setup(), true)