Plugin Lua Modules
mise plugins have access to a comprehensive set of built-in Lua modules that provide common functionality. These modules are available in both backend plugins and tool plugins, making it easy to perform common operations like HTTP requests, JSON parsing, file operations, and more.
Available Modules
Core Modules
cmd
- Execute shell commandsjson
- Parse and generate JSONhttp
- Make HTTP requests and downloadsfile
- File system operationsenv
- Environment variable operationsstrings
- String manipulation utilitieshtml
- HTML parsing and manipulationarchiver
- Archive extraction and compression
HTTP Module
The HTTP module provides functionality for making web requests and downloading files.
Basic HTTP Requests
local http = require("http")
-- GET request
local resp, err = http.get({
url = "https://api.github.com/repos/owner/repo/releases",
headers = {
['User-Agent'] = "mise-plugin",
['Accept'] = "application/json"
}
})
if err ~= nil then
error("Request failed: " .. err)
end
if resp.status_code ~= 200 then
error("HTTP error: " .. resp.status_code)
end
local body = resp.body
HEAD Requests
local http = require("http")
-- HEAD request to check file info
local resp, err = http.head({
url = "https://example.com/file.tar.gz"
})
if err ~= nil then
error("HEAD request failed: " .. err)
end
local content_length = resp.headers['content-length']
local content_type = resp.headers['content-type']
File Downloads
local http = require("http")
-- Download file
local err = http.download_file({
url = "https://github.com/owner/repo/archive/v1.0.0.tar.gz",
headers = {
['User-Agent'] = "mise-plugin"
}
}, "/path/to/download.tar.gz")
if err ~= nil then
error("Download failed: " .. err)
end
Response Object
HTTP responses contain the following fields:
{
status_code = 200,
headers = {
['content-type'] = "application/json",
['content-length'] = "1234"
},
body = "response content"
}
JSON Module
The JSON module provides encoding and decoding functionality.
Basic Usage
local json = require("json")
-- Encode table to JSON string
local obj = {
name = "mise-plugin",
version = "1.0.0",
tools = {"prettier", "eslint"}
}
local jsonStr = json.encode(obj)
-- Result: '{"name":"mise-plugin","version":"1.0.0","tools":["prettier","eslint"]}'
-- Decode JSON string to table
local decoded = json.decode(jsonStr)
print(decoded.name) -- "mise-plugin"
print(decoded.tools[1]) -- "prettier"
Error Handling (Lua)
local json = require("json")
-- Safe JSON parsing
local success, result = pcall(json.decode, response_body)
if not success then
error("Failed to parse JSON: " .. result)
end
-- Use the parsed data
for _, item in ipairs(result) do
print(item.version)
end
Strings Module
The strings module provides various string manipulation utilities.
String Operations
local strings = require("strings")
-- Split string into parts
local parts = strings.split("hello,world,test", ",")
print(parts[1]) -- "hello"
print(parts[2]) -- "world"
print(parts[3]) -- "test"
-- Join strings
local joined = strings.join({"hello", "world", "test"}, " - ")
print(joined) -- "hello - world - test"
-- Trim whitespace
local trimmed = strings.trim_space(" hello world ")
print(trimmed) -- "hello world"
String Checks
local strings = require("strings")
-- Check prefixes and suffixes
local text = "hello world"
print(strings.has_prefix(text, "hello")) -- true
print(strings.has_suffix(text, "world")) -- true
print(strings.contains(text, "lo wo")) -- true
-- Trim specific characters
local trimmed = strings.trim("hello world", "world")
print(trimmed) -- "hello "
Version String Utilities
local strings = require("strings")
-- Common version string operations
local function normalize_version(version)
-- Remove 'v' prefix if present
version = strings.trim_prefix(version, "v")
-- Remove pre-release suffixes
local parts = strings.split(version, "-")
return parts[1]
end
local version = normalize_version("v1.2.3-beta.1") -- "1.2.3"
HTML Module
The HTML module provides HTML parsing capabilities.
Basic HTML Parsing
local html = require("html")
-- Parse HTML document
local doc = html.parse([[
<html>
<body>
<div id="version" class="info">1.2.3</div>
<ul class="downloads">
<li><a href="/download/v1.2.3.tar.gz">Source</a></li>
<li><a href="/download/v1.2.3.zip">Windows</a></li>
</ul>
</body>
</html>
]])
-- Extract text content
local version = doc:find("#version"):text() -- "1.2.3"
-- Extract attributes
local links = doc:find("a")
for _, link in ipairs(links) do
local href = link:attr("href")
local text = link:text()
print(text .. ": " .. href)
end
CSS Selectors
local html = require("html")
local doc = html.parse(html_content)
-- Find by ID
local element = doc:find("#version")
-- Find by class
local elements = doc:find(".download-link")
-- Find by tag
local links = doc:find("a")
-- Complex selectors
local specific_links = doc:find("ul.downloads a[href$='.tar.gz']")
Real-World Example: Scraping Releases
local html = require("html")
local http = require("http")
function get_github_releases(owner, repo)
local resp, err = http.get({
url = "https://github.com/" .. owner .. "/" .. repo .. "/releases"
})
if err ~= nil then
error("Failed to fetch releases: " .. err)
end
local doc = html.parse(resp.body)
local releases = {}
-- Find all release tags
local release_elements = doc:find("a[href*='/releases/tag/']")
for _, element in ipairs(release_elements) do
local href = element:attr("href")
local version = href:match("/releases/tag/(.+)")
if version then
table.insert(releases, {
version = version,
url = "https://github.com" .. href
})
end
end
return releases
end
Archiver Module
The archiver module provides functionality for extracting compressed archives.
Supported Formats
- tar.gz / tgz - Gzipped tar archives
- tar.xz - XZ compressed tar archives
- zip - ZIP archives
- 7z - 7-Zip archives
Basic Extraction
local archiver = require("archiver")
-- Extract archive to directory
local err = archiver.decompress("archive.tar.gz", "extracted/")
if err ~= nil then
error("Extraction failed: " .. err)
end
-- Extract ZIP file
local err = archiver.decompress("package.zip", "destination/")
if err ~= nil then
error("ZIP extraction failed: " .. err)
end
Real-World Example: Plugin Installation
local archiver = require("archiver")
local http = require("http")
function install_from_archive(download_url, install_path)
-- Download the archive
local archive_path = install_path .. "/download.tar.gz"
local err = http.download_file({
url = download_url
}, archive_path)
if err ~= nil then
error("Download failed: " .. err)
end
-- Extract to installation directory
local err = archiver.decompress(archive_path, install_path)
if err ~= nil then
error("Extraction failed: " .. err)
end
-- Clean up archive
os.remove(archive_path)
end
File Module
The file module provides file system operations.
File Operations
local file = require("file")
-- Read file content
local content = file.read("/path/to/file.txt")
if content then
print("File content: " .. content)
else
error("Failed to read file")
end
-- Write file content
local success = file.write("/path/to/output.txt", "Hello, World!")
if not success then
error("Failed to write file")
end
-- Check if file exists
if file.exists("/path/to/file.txt") then
print("File exists")
end
Directory Operations
local file = require("file")
-- Create directory
local success = file.mkdir("/path/to/new/directory")
if not success then
error("Failed to create directory")
end
-- Create directory with parents
local success = file.mkdir_all("/path/to/deep/nested/directory")
if not success then
error("Failed to create directory tree")
end
-- List directory contents
local files = file.list_dir("/path/to/directory")
for _, filename in ipairs(files) do
print("Found file: " .. filename)
end
Path Joining
local file = require("file")
-- Join path segments using the OS-specific separator
local full_path = file.join_path("/foo", "bar", "baz.txt")
print(full_path) -- On Unix: /foo/bar/baz.txt, on Windows: \foo\bar\baz.txt
The file.join_path(...)
function joins any number of path segments using the correct separator for the current operating system. This is the recommended way to construct file paths in cross-platform plugins.
Environment Module
The env module provides environment variable operations.
Environment Variables
local env = require("env")
-- Get environment variable
local home = env.get("HOME")
local path = env.get("PATH")
-- Set environment variable
env.set("MY_VARIABLE", "my_value")
-- Check if environment variable exists
if env.exists("NODE_ENV") then
print("NODE_ENV is set to: " .. env.get("NODE_ENV"))
end
Path Operations
local env = require("env")
-- Get current PATH
local current_path = env.get("PATH")
-- Add to PATH
local new_path = "/usr/local/bin:" .. current_path
env.set("PATH", new_path)
-- Platform-specific PATH separator
local separator = package.config:sub(1,1) == '\\' and ";" or ":"
local paths = {"/usr/local/bin", "/opt/bin", current_path}
env.set("PATH", table.concat(paths, separator))
Command Module
The cmd module provides shell command execution.
Basic Command Execution
local cmd = require("cmd")
-- Execute command and get output
local output = cmd.exec("ls -la")
print("Directory listing:", output)
-- Execute command with error handling
local success, output = pcall(cmd.exec, "some-command")
if not success then
error("Command failed: " .. output)
end
Command Execution with Options
local cmd = require("cmd")
-- Execute command in a specific directory
local output = cmd.exec("pwd", {cwd = "/tmp"})
print("Current directory:", output)
-- Execute command with custom environment variables
local result = cmd.exec("echo $TEST_VAR", {
cwd = "/path/to/project",
env = {TEST_VAR = "hello", NODE_ENV = "production"}
})
-- Install package in specific directory
local result = cmd.exec("npm install package-name", {cwd = "/path/to/project"})
Available Options
The options table supports the following keys:
cwd
(string): Set the working directory for the commandenv
(table): Set environment variables for the command executiontimeout
(number): Set a timeout for command execution (future feature)
Platform-Specific Commands
local cmd = require("cmd")
-- Cross-platform command execution
local function is_windows()
return package.config:sub(1,1) == '\\'
end
local function get_os_info()
if is_windows() then
return cmd.exec("systeminfo")
else
return cmd.exec("uname -a")
end
end
local os_info = get_os_info()
print("OS Info:", os_info)
Practical Examples
Version Fetching from API
local http = require("http")
local json = require("json")
function fetch_npm_versions(package_name)
local resp, err = http.get({
url = "https://registry.npmjs.org/" .. package_name,
headers = {
['User-Agent'] = "mise-plugin"
}
})
if err ~= nil then
error("Failed to fetch package info: " .. err)
end
local package_info = json.decode(resp.body)
local versions = {}
for version, _ in pairs(package_info.versions) do
table.insert(versions, version)
end
-- Sort versions (simple string sort)
table.sort(versions)
return versions
end
File Download with Progress
local http = require("http")
local file = require("file")
function download_with_verification(url, dest_path, expected_sha256)
-- Download file
local err = http.download_file({
url = url,
headers = {
['User-Agent'] = "mise-plugin"
}
}, dest_path)
if err ~= nil then
error("Download failed: " .. err)
end
-- Verify file exists
if not file.exists(dest_path) then
error("Downloaded file not found")
end
-- Note: SHA256 verification would need additional implementation
-- This is a simplified example
print("Downloaded successfully to: " .. dest_path)
end
Configuration File Parsing
local file = require("file")
local json = require("json")
local strings = require("strings")
function parse_config_file(config_path)
if not file.exists(config_path) then
return {} -- Return empty config
end
local content = file.read(config_path)
if not content then
error("Failed to read config file: " .. config_path)
end
-- Trim whitespace
content = strings.trim_space(content)
-- Parse JSON
local success, config = pcall(json.decode, content)
if not success then
error("Invalid JSON in config file: " .. config_path)
end
return config
end
Web Scraping for Versions
local http = require("http")
local html = require("html")
local strings = require("strings")
function scrape_versions_from_releases(base_url)
local resp, err = http.get({
url = base_url .. "/releases"
})
if err ~= nil then
error("Failed to fetch releases page: " .. err)
end
local doc = html.parse(resp.body)
local versions = {}
-- Find version tags
local version_elements = doc:find("h2 a[href*='/releases/tag/']")
for _, element in ipairs(version_elements) do
local version_text = element:text()
local version = strings.trim_space(version_text)
-- Remove 'v' prefix if present
version = strings.trim_prefix(version, "v")
if version and version ~= "" then
table.insert(versions, {
version = version,
url = base_url .. element:attr("href")
})
end
end
return versions
end
Best Practices
Error Handling
Always handle errors gracefully:
local http = require("http")
local json = require("json")
function safe_api_call(url)
local resp, err = http.get({url = url})
if err ~= nil then
error("HTTP request failed: " .. err)
end
if resp.status_code ~= 200 then
error("API returned error: " .. resp.status_code .. " " .. resp.body)
end
local success, data = pcall(json.decode, resp.body)
if not success then
error("Failed to parse JSON response: " .. data)
end
return data
end
Caching
Implement caching for expensive operations:
local cache = {}
local cache_ttl = 3600 -- 1 hour
function cached_http_get(url)
local now = os.time()
local cache_key = url
-- Check cache
if cache[cache_key] and (now - cache[cache_key].timestamp) < cache_ttl then
return cache[cache_key].data
end
-- Fetch fresh data
local http = require("http")
local resp, err = http.get({url = url})
if err ~= nil then
error("HTTP request failed: " .. err)
end
-- Cache the result
cache[cache_key] = {
data = resp,
timestamp = now
}
return resp
end
Platform Detection
Handle cross-platform differences:
local function get_platform_info()
local is_windows = package.config:sub(1,1) == '\\'
local cmd = require("cmd")
if is_windows then
return {
os = "windows",
arch = os.getenv("PROCESSOR_ARCHITECTURE") or "x64",
path_sep = "\\",
env_sep = ";"
}
else
local uname = cmd.exec("uname -s"):lower()
local arch = cmd.exec("uname -m")
return {
os = uname,
arch = arch,
path_sep = "/",
env_sep = ":"
}
end
end