che-astronvim-config/lua/polish.lua
User 1af2b4cc7d refactor: enhance polish.lua with comprehensive documentation, security validation, and improved error handling
- Add LuaDoc annotations and type definitions for better code documentation

- Implement package name validation to prevent command injection attacks

- Improve error handling with proper notifications and graceful failure handling

- Remove debug prints and make code production-ready

- Add proper module exports for better code organization

- Clean up obsolete lazy_lock_files/vue.json file

Signed-off-by: User <user@example.com>
2025-10-11 19:03:11 +00:00

162 lines
5.5 KiB
Lua

--- @meta
--- Framework-specific tool configurations and installation utilities for Neovim.
--- This module provides automatic installation of language servers and tools
--- based on the current development framework environment.
--- It reads the FRAMEWORK environment variable to determine which tools to install.
--- @alias FrameworkName "python"|"vue"|string
--- @class FrameworkTools
--- @field python string[] Python development tools and LSP servers including formatters, linters, and type checkers
--- @field vue string[] Vue.js development tools and LSP servers including JavaScript/TypeScript tools and CSS utilities
--- Framework-specific tool configurations
--- Maps framework names to their respective tool lists
--- @type FrameworkTools
local FRAMEWORK_TOOLS = {
python = {
"black",
"python-lsp-server",
"mypy",
"pylint",
"flake8",
"pylama",
"bandit",
"pydocstyle",
"pyproject-flake8",
"pyproject-fmt",
"reorder-python-imports",
},
vue = {
"eslint-lsp",
"stylelint-lsp",
"tailwindcss-language-server",
"typescript-language-server",
"stylelint",
"prettier",
},
}
--- Retrieves the appropriate tool set based on the current framework environment.
--- This function checks the FRAMEWORK environment variable and returns the corresponding
--- tool list from FRAMEWORK_TOOLS. If no framework is set or the framework is not recognized,
--- returns an empty table.
--- @return string[] tools List of tools to install for the detected framework, or empty table if no framework is set
local function get_framework_tools()
local current_framework = os.getenv("FRAMEWORK")
if current_framework then
local tools = FRAMEWORK_TOOLS[current_framework]
return tools or {}
else
return {}
end
end
--- Validates if a package name is safe to install.
--- This function performs basic security validation to prevent command injection
--- and ensures package names follow expected patterns.
--- @param package_name string The package name to validate
--- @return boolean is_valid True if the package name is valid, false otherwise
local function is_valid_package_name(package_name)
-- Basic validation: package names should only contain alphanumeric characters, hyphens, and dots
-- This prevents command injection attacks
if type(package_name) ~= "string" or package_name == "" then
return false
end
-- Additional security: check for potentially dangerous patterns
local dangerous_patterns = {
"%.%.%/", -- Path traversal
"%;", -- Command separator
"%|", -- Pipe
"%&", -- Background process
"%`", -- Command substitution
"%$", -- Variable expansion
"%!" -- History expansion
}
for _, pattern in ipairs(dangerous_patterns) do
if string.match(package_name, pattern) then
return false
end
end
-- Check for valid characters: alphanumeric, hyphen, dot, underscore
local valid_pattern = "^[%w%-%.%_]+$"
return string.match(package_name, valid_pattern) ~= nil
end
--- Checks if Mason is available and ready for package installation.
--- @return boolean is_available True if Mason is available, false otherwise
local function is_mason_available()
local mason_ok, _ = pcall(require, "mason")
return mason_ok
end
--- Installs Mason packages based on the current framework environment.
--- This function retrieves the appropriate tool set and installs them one by one
--- to handle individual failures gracefully. Each package installation is wrapped
--- in a protected call to prevent one failure from stopping the entire process.
--- @return nil
function InstallMyMasonPackages()
-- Check if Mason is available first
if not is_mason_available() then
vim.notify("Mason is not available. Please install Mason first.", vim.log.levels.ERROR)
return
end
local packages = get_framework_tools()
if #packages > 0 then
local installed_count = 0
local failed_count = 0
-- Install packages one by one to handle individual failures
for _, package in ipairs(packages) do
-- Validate package name for security
if not is_valid_package_name(package) then
vim.notify("Skipping invalid package name: " .. package, vim.log.levels.WARN)
failed_count = failed_count + 1
else
local success, result = pcall(function()
vim.cmd("MasonInstall " .. package)
end)
if success then
installed_count = installed_count + 1
vim.notify("Successfully installed: " .. package, vim.log.levels.INFO)
else
failed_count = failed_count + 1
vim.notify("Failed to install " .. package .. ": " .. tostring(result), vim.log.levels.WARN)
end
end
end
-- Provide summary
if failed_count == 0 then
vim.notify("Framework-specific packages installation completed successfully. Installed: " .. installed_count .. " packages", vim.log.levels.INFO)
else
vim.notify("Framework-specific packages installation completed with " .. failed_count .. " failures. Successfully installed: " .. installed_count .. " packages", vim.log.levels.WARN)
end
else
vim.notify("No framework detected or no packages to install", vim.log.levels.INFO)
end
end
-- Create user command for Mason installation
vim.api.nvim_create_user_command(
"MasonInstallR", -- Command name
InstallMyMasonPackages, -- Function to call
{ nargs = 0 } -- Command takes no arguments
)
-- Module exports
return {
FRAMEWORK_TOOLS = FRAMEWORK_TOOLS,
get_framework_tools = get_framework_tools,
InstallMyMasonPackages = InstallMyMasonPackages,
}