Files
input-form.nvim/lua/input-form/validators.lua
2026-04-06 00:51:27 +03:00

162 lines
4.2 KiB
Lua

--- Validators for form inputs.
---
--- A validator is a function `fun(value): string|nil`. It receives the
--- current input value and returns a non-empty error message string when
--- invalid, or `nil` / `""` when valid.
---
--- This module exposes factory functions for common validators plus a
--- `chain` combinator that runs several validators in order and returns the
--- first error.
---
---@tag input-form.validators
local M = {}
--- Require the field to have a non-empty value.
---@param msg string|nil Override error message.
---@return function
function M.non_empty(msg)
msg = msg or "This field is required"
return function(value)
if value == nil then
return msg
end
if type(value) == "string" and value == "" then
return msg
end
return nil
end
end
--- Require the value's length to be at least `n` characters.
---@param n integer
---@param msg string|nil
---@return function
function M.min_length(n, msg)
return function(value)
local s = type(value) == "string" and value or tostring(value or "")
if vim.fn.strchars(s) < n then
return msg or ("Must be at least " .. n .. " characters")
end
return nil
end
end
--- Require the value's length to be at most `n` characters.
---@param n integer
---@param msg string|nil
---@return function
function M.max_length(n, msg)
return function(value)
local s = type(value) == "string" and value or tostring(value or "")
if vim.fn.strchars(s) > n then
return msg or ("Must be at most " .. n .. " characters")
end
return nil
end
end
--- Require the value to match a Lua pattern.
---@param pattern string Lua pattern (not PCRE).
---@param msg string|nil
---@return function
function M.matches(pattern, msg)
return function(value)
local s = type(value) == "string" and value or tostring(value or "")
if not s:match(pattern) then
return msg or "Invalid format"
end
return nil
end
end
--- Require the value to parse as a number.
---@param msg string|nil
---@return function
function M.is_number(msg)
return function(value)
if value == nil or value == "" or tonumber(value) == nil then
return msg or "Must be a number"
end
return nil
end
end
--- Require a checkbox value to equal the given boolean. Intended for
--- `checkbox` inputs ("must agree to terms", "must enable feature", ...).
---@param required boolean|nil The required value. Defaults to `true`.
---@param msg string|nil Override error message. Defaults to
--- `"(must be checked)"` when `required` is `true`, otherwise
--- `"(must be unchecked)"`.
---@return function
function M.checked(required, msg)
if required == nil then
required = true
end
if type(msg) ~= "string" then
msg = required and "(must be checked)" or "(must be unchecked)"
end
return function(value)
if value == required then
return nil
end
return msg
end
end
--- Require the value to be one of the given choices (useful for text inputs
--- that must match a fixed allowlist; select inputs should use their
--- `options` list instead).
---@param choices table List of allowed values.
---@param msg string|nil
---@return function
function M.one_of(choices, msg)
return function(value)
for _, c in ipairs(choices) do
if c == value then
return nil
end
end
return msg or "Value is not allowed"
end
end
--- Wrap a predicate `fun(value): boolean` as a validator.
---@param predicate function
---@param msg string Error message to return when the predicate is false.
---@return function
function M.custom(predicate, msg)
return function(value)
if predicate(value) then
return nil
end
return msg
end
end
--- Combine multiple validators. Runs them in order and returns the first
--- non-empty error. Accepts either a list table or a varargs list.
---@param ... function|table
---@return function
function M.chain(...)
local validators = { ... }
if
#validators == 1
and type(validators[1]) == "table"
and type(validators[1][1]) == "function"
then
validators = validators[1]
end
return function(value)
for _, v in ipairs(validators) do
local err = v(value)
if err and err ~= "" then
return err
end
end
return nil
end
end
return M