Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(typescript): biome pack #1006

Closed
wants to merge 8 commits into from
Closed
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
31 changes: 31 additions & 0 deletions lua/astrocommunity/pack/typescript-biome/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# TypeScript Biome Language Pack

This plugin pack does the following:

- Adds `typescript`, `javascript`, `tsx`, and `jsdoc` Treesitter parsers
- Adds `vtsls` and `biome` language server
- Adds [JSON language support](../json)
- Adds support for dap for JS
- Adds [nvim-vtsls](https://github.com/yioneko/nvim-vtsls) for language specific tooling
- Adds [package-info.nvim](https://github.com/vuki656/package-info.nvim) for project package management
- Adds [nvim-lsp-file-operations](https://github.com/antosha417/nvim-lsp-file-operations) to handles file imports on rename or move within neo-tree

## How do I use biome without mason?

If you have biome as a dependency, then it's recommended to run the LSP through that dependency. This is because the biome linter and formatter
is prone to change between versions meaning your LSP can show different diagnostics compared to the actual version of biome you have installed.

```lua
return {
"AstroNvim/astrolsp",
servers = {
"biome",
},
config = {
biome = {
-- Use the package manager of your project: npx, yarn, pnpm, bun...
cmd = { "yarn", "biome", "lsp-proxy" }
}
}
}
```
133 changes: 133 additions & 0 deletions lua/astrocommunity/pack/typescript-biome/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
local function decode_json(filename)
-- Open the file in read mode
local file = io.open(filename, "r")
if not file then
return false -- File doesn't exist or cannot be opened
end

-- Read the contents of the file
local content = file:read "*all"
file:close()

-- Parse the JSON content
local json_parsed, json = pcall(vim.fn.json_decode, content)
if not json_parsed or type(json) ~= "table" then
return false -- Invalid JSON format
end
return json
end

local function check_json_key_exists(json, ...) return vim.tbl_get(json, ...) ~= nil end

local lsp_rooter, prettierrc_rooter
local function has_prettier(bufnr)
if type(bufnr) ~= "number" then bufnr = vim.api.nvim_get_current_buf() end

local rooter = require "astrocore.rooter"

if not lsp_rooter then
lsp_rooter = rooter.resolve("lsp", {
ignore = {
servers = function(client) return not vim.tbl_contains({ "eslint" }, client.name) end,
},
})
end

if not prettierrc_rooter then
prettierrc_rooter = rooter.resolve {
".prettierrc",
".prettierrc.json",
".prettierrc.yml",
".prettierrc.yaml",
".prettierrc.json5",
".prettierrc.js",
".prettierrc.cjs",
"prettier.config.js",
".prettierrc.mjs",
"prettier.config.mjs",
"prettier.config.cjs",
".prettierrc.toml",
}
end

local prettier_dependency = false

for _, root in ipairs(require("astrocore").list_insert_unique(lsp_rooter(bufnr), { vim.fn.getcwd() })) do
local package_json = decode_json(root .. "/package.json")
if
package_json
and (
check_json_key_exists(package_json, "dependencies", "prettier")
or check_json_key_exists(package_json, "devDependencies", "prettier")
)
then
prettier_dependency = true
break
end
end
return prettier_dependency or next(prettierrc_rooter(bufnr))
end

local function has_biome()
local bufnr = vim.api.nvim_get_current_buf()
local rooter = require "astrocore.rooter"

local biomejson_rooter = rooter.resolve {
"biome.json",
}

return next(biomejson_rooter(bufnr))
end

local biome_format_filetypes = { "javascript", "javascriptreact", "typescript", "typescriptreact", "json", "jsonc" }
local prettier_format_filetypes = { "javascript", "javascriptreact", "typescript", "typescriptreact" }

local function null_ls_formatter(params)
-- prefer biome for the file types it can format
if has_biome() then return not vim.tbl_contains(biome_format_filetypes, params.filetype) end

if vim.tbl_contains(prettier_format_filetypes, params.filetype) then return has_prettier(params.bufnr) end
return true
end

return {
{ import = "astrocommunity.pack.typescript.core" },
{
"williamboman/mason-lspconfig.nvim",
opts = function(_, opts)
opts.ensure_installed = require("astrocore").list_insert_unique(opts.ensure_installed, { "biome" })
end,
},
{
"jay-babu/mason-null-ls.nvim",
optional = true,
opts = function(_, opts)
if not opts.handlers then opts.handlers = {} end

opts.handlers.prettierd = function(source_name, methods)
local null_ls = require "null-ls"
for _, method in ipairs(methods) do
null_ls.register(null_ls.builtins[method][source_name].with { runtime_condition = null_ls_formatter })
end
end
end,
},
{
"stevearc/conform.nvim",
optional = true,
opts = function(_, opts)
if not opts.formatters_by_ft then opts.formatters_by_ft = {} end

for _, filetype in ipairs(biome_format_filetypes) do
opts.formatters_by_ft[filetype] = function()
-- let the biome lsp handle this
if has_biome() then return {} end

if vim.tbl_contains(prettier_format_filetypes, filetype) and has_prettier() then return { "prettierd" } end

return {}
end
end
end,
},
}
108 changes: 108 additions & 0 deletions lua/astrocommunity/pack/typescript/core.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
return {
{ import = "astrocommunity.pack.json" },
{ import = "astrocommunity.lsp.nvim-lsp-file-operations" },
{
"nvim-treesitter/nvim-treesitter",
optional = true,
opts = function(_, opts)
if opts.ensure_installed ~= "all" then
opts.ensure_installed =
require("astrocore").list_insert_unique(opts.ensure_installed, { "javascript", "typescript", "tsx", "jsdoc" })
end
end,
},
{
"AstroNvim/astrolsp",
---@type AstroLSPOpts
opts = {
---@diagnostic disable: missing-fields
config = {
vtsls = {
settings = {
typescript = {
updateImportsOnFileMove = { enabled = "always" },
inlayHints = {
parameterNames = { enabled = "all" },
parameterTypes = { enabled = true },
variableTypes = { enabled = true },
propertyDeclarationTypes = { enabled = true },
functionLikeReturnTypes = { enabled = true },
enumMemberValues = { enabled = true },
},
},
javascript = {
updateImportsOnFileMove = { enabled = "always" },
inlayHints = {
parameterNames = { enabled = "literals" },
parameterTypes = { enabled = true },
variableTypes = { enabled = true },
propertyDeclarationTypes = { enabled = true },
functionLikeReturnTypes = { enabled = true },
enumMemberValues = { enabled = true },
},
},
vtsls = {
enableMoveToFileCodeAction = true,
},
},
},
},
},
},
{
"williamboman/mason-lspconfig.nvim",
opts = function(_, opts)
opts.ensure_installed = require("astrocore").list_insert_unique(opts.ensure_installed, { "vtsls" })
end,
},
{
"jay-babu/mason-nvim-dap.nvim",
optional = true,
opts = function(_, opts)
opts.ensure_installed = require("astrocore").list_insert_unique(opts.ensure_installed, { "js" })
end,
},
{
"WhoIsSethDaniel/mason-tool-installer.nvim",
optional = true,
opts = function(_, opts)
opts.ensure_installed =
require("astrocore").list_insert_unique(opts.ensure_installed, { "vtsls", "js-debug-adapter" })
end,
},
{
"vuki656/package-info.nvim",
dependencies = { "MunifTanjim/nui.nvim" },
opts = {},
event = "BufRead package.json",
},
{
"yioneko/nvim-vtsls",
lazy = true,
dependencies = {
"AstroNvim/astrocore",
opts = {
autocmds = {
nvim_vtsls = {
{
event = "LspAttach",
desc = "Load nvim-vtsls with vtsls",
callback = function(args)
if assert(vim.lsp.get_client_by_id(args.data.client_id)).name == "vtsls" then
require("vtsls")._on_attach(args.data.client_id, args.buf)
vim.api.nvim_del_augroup_by_name "nvim_vtsls"
end
end,
},
},
},
},
},
config = function(_, opts) require("vtsls").config(opts) end,
},
{
"dmmulroy/tsc.nvim",
cmd = "TSC",
opts = {},
},
}
Loading
Loading