Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ By default, the plugin uses the default `tsc` command with the `--noEmit` flag t
use_trouble_qflist = false,
use_diagnostics = false,
run_as_monorepo = false,
monorepo_root_patterns = { ".git" },
max_tsconfig_files = 20,
bin_path = nil,
bin_name = "tsc",
Expand Down
30 changes: 27 additions & 3 deletions lua/tsc/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ end
--- @field use_trouble_qflist? boolean - (false) When true the quick fix list will be opened in Trouble if it is installed
--- @field use_diagnostics? boolean - (false) When true the errors will be set as diagnostics
--- @field run_as_monorepo? boolean - (false) When true the `tsc` process will be started mode for each tsconfig in the current working directory
--- @field monorepo_root_patterns? string[] - ({".git"}) The file pattern to be used to find the root of the monorepo
--- @field max_tsconfig_files? number - (20) Will not run `tsc` if number of found tsconfig files is greater.
--- @field bin_path? string - Path to the tsc binary if it is not in the projects node_modules or globally
--- @field bin_name? string - Name of the binary to use (default: "tsc")
Expand All @@ -39,6 +40,7 @@ local DEFAULT_CONFIG = {
enable_progress_notifications = true,
enable_error_notifications = true,
run_as_monorepo = false,
monorepo_root_patterns = { ".git" },
max_tsconfig_files = 20,
flags = {
noEmit = true,
Expand Down Expand Up @@ -83,7 +85,11 @@ local function format_notification_msg(msg, spinner_idx)
return string.format(" %s %s ", config.spinner[spinner_idx], msg)
end

M.run = function()
--- @class RunParams
--- @field force_monorepo_mode boolean

--- @param params RunParams?
M.run = function(params)
-- Closed over state
local tsc = config.bin_path or utils.find_tsc_bin(config.bin_name)
local errors = {}
Expand All @@ -107,7 +113,14 @@ M.run = function()
return
end

local configs_to_run = utils.find_tsconfigs(config.run_as_monorepo)
--- @type boolean
local run_as_monorepo = (params and params.force_monorepo_mode) or config.run_as_monorepo or false

-- When running a monorepo check, we need to make sure we run the commands
-- from the root of the monorepo, as the cwd may be a subdirectory
local monorepo_root_path = vim.fs.root(0, config.monorepo_root_patterns) or "."

local configs_to_run = utils.find_tsconfigs(run_as_monorepo, monorepo_root_path)

if #configs_to_run > 0 and not config.run_as_monorepo then
M.stop()
Expand Down Expand Up @@ -240,8 +253,10 @@ M.run = function()
)
end

---@param output string[]
---@param project string
local function on_stdout(output, project)
local result = utils.parse_tsc_output(output, config)
local result = utils.parse_tsc_output(output, config, project)

running_processes[project].errors = result.errors

Expand Down Expand Up @@ -277,6 +292,7 @@ M.run = function()
end
end

--- @param project string
local opts = function(project)
return {
on_stdout = function(_, output)
Expand All @@ -286,6 +302,7 @@ M.run = function()
on_exit()
end,
stdout_buffered = true,
cwd = vim.fs.dirname(project),
}
end

Expand Down Expand Up @@ -338,6 +355,13 @@ function M.setup(opts)
M.run()
end, { desc = "Run `tsc` asynchronously and load the results into a qflist", force = true })

vim.api.nvim_create_user_command("TSCMono", function()
M.run({ force_monorepo_mode = true })
end, {
desc = "Run `tsc` for all the typescript projects in the monorepo",
force = true,
})

vim.api.nvim_create_user_command("TSCStop", function()
M.stop()
vim.notify_once(format_notification_msg("TSC stopped"), nil, get_notify_options())
Expand Down
34 changes: 23 additions & 11 deletions lua/tsc/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ M.find_tsc_bin = function(bin_name)
local node_modules_binary = vim.fn.findfile("node_modules/.bin/" .. bin_name, ".;")

if node_modules_binary ~= "" then
return node_modules_binary
return vim.fs.abspath(node_modules_binary)
end

return bin_name
end

--- @param run_mono_repo boolean
--- @return table<string>
M.find_tsconfigs = function(run_mono_repo)
--- @param monorepo_root_path string
--- @return string[]
M.find_tsconfigs = function(run_mono_repo, monorepo_root_path)
if not run_mono_repo then
return M.find_nearest_tsconfig()
end
Expand All @@ -33,28 +34,34 @@ M.find_tsconfigs = function(run_mono_repo)

local found_configs = nil
if M.is_executable("rg") then
found_configs = vim.fn.system("rg -g '!node_modules' --files | rg 'tsconfig.*.json'")
found_configs = vim.trim(
vim.system({ "rg", "--files", "-g", "!node_modules", "-g", "tsconfig.json", monorepo_root_path }):wait().stdout
)
else
found_configs = vim.fn.system('find . -not -path "*/node_modules/*" -name "tsconfig.*.json" -type f')
found_configs = vim.trim(
vim
.system({ "find", monorepo_root_path, "-not", "-path", "*/node_modules/*", "-name", "tsconfig.*.json", "-type", "f" })
:wait().stdout
)
end

if found_configs == nil then
return {}
end

for s in found_configs:gmatch("[^\r\n]+") do
table.insert(tsconfigs, s)
table.insert(tsconfigs, vim.fs.abspath(s))
end

assert(tsconfigs)
return tsconfigs
end

M.find_nearest_tsconfig = function()
local tsconfig = vim.fn.findfile("tsconfig.json", ".;")
local tsconfig_root = vim.fs.root(0, "tsconfig.json")

if tsconfig ~= "" then
return { tsconfig }
if tsconfig_root then
return { vim.fs.joinpath(vim.fs.abspath(tsconfig_root), "tsconfig.json") }
end

return {}
Expand Down Expand Up @@ -96,14 +103,19 @@ M.parse_flags = function(flags)
return parsed_flags
end

M.parse_tsc_output = function(output, config)
---@param output string[]
---@param config Opts
---@param project string
M.parse_tsc_output = function(output, config, project)
local errors = {}
local files = {}

if output == nil then
return { errors = errors, files = files }
end

local project_root = vim.fs.dirname(project)

for _, line in ipairs(output) do
local filename, lineno, colno, message = line:match("^(.+)%((%d+),(%d+)%)%s*:%s*(.+)$")
if filename ~= nil then
Expand All @@ -112,7 +124,7 @@ M.parse_tsc_output = function(output, config)
text = better_messages.translate(message)
end
table.insert(errors, {
filename = filename,
filename = vim.fs.joinpath(project_root, filename),
lnum = tonumber(lineno),
col = tonumber(colno),
text = text,
Expand Down
Loading