feat: validate all option types (#2414)
* refactor: follow config structure for `ACCEPTED_TYPES` * Bug fix * Fix check for default values * Reduce error notifications verbosity * Address issues introduced previously * stylua --------- Co-authored-by: Alexander Courtis <alex@courtis.org>
This commit is contained in:
@@ -621,14 +621,31 @@ local FIELD_SKIP_VALIDATE = {
|
|||||||
open_win_config = true,
|
open_win_config = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
local FIELD_OVERRIDE_TYPECHECK = {
|
local ACCEPTED_TYPES = {
|
||||||
width = { string = true, ["function"] = true, number = true, ["table"] = true },
|
on_attach = { "function", "string" },
|
||||||
max = { string = true, ["function"] = true, number = true },
|
sort = {
|
||||||
min = { string = true, ["function"] = true, number = true },
|
sorter = { "function", "string" },
|
||||||
on_attach = { ["function"] = true, string = true },
|
},
|
||||||
sorter = { ["function"] = true, string = true },
|
view = {
|
||||||
root_folder_label = { ["function"] = true, string = true, boolean = true },
|
width = {
|
||||||
picker = { ["function"] = true, string = true },
|
"string",
|
||||||
|
"function",
|
||||||
|
"number",
|
||||||
|
"table",
|
||||||
|
min = { "string", "function", "number" },
|
||||||
|
max = { "string", "function", "number" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
renderer = {
|
||||||
|
root_folder_label = { "function", "string", "boolean" },
|
||||||
|
},
|
||||||
|
actions = {
|
||||||
|
open_file = {
|
||||||
|
window_picker = {
|
||||||
|
picker = { "function", "string" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
local ACCEPTED_STRINGS = {
|
local ACCEPTED_STRINGS = {
|
||||||
@@ -653,43 +670,65 @@ local ACCEPTED_STRINGS = {
|
|||||||
local function validate_options(conf)
|
local function validate_options(conf)
|
||||||
local msg
|
local msg
|
||||||
|
|
||||||
local function validate(user, def, strs, prefix)
|
local function validate(user, def, strs, types, prefix)
|
||||||
-- only compare tables with contents that are not integer indexed
|
-- if user's option is not a table there is nothing to do
|
||||||
if type(user) ~= "table" or type(def) ~= "table" or not next(def) or type(next(def)) == "number" then
|
if type(user) ~= "table" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- only compare tables with contents that are not integer indexed
|
||||||
|
if type(def) ~= "table" or not next(def) or type(next(def)) == "number" then
|
||||||
|
-- unless the field can be a table (and is not a table in default config)
|
||||||
|
if vim.tbl_contains(types, "table") then
|
||||||
|
-- use a dummy default to allow all checks
|
||||||
|
def = {}
|
||||||
|
else
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
for k, v in pairs(user) do
|
for k, v in pairs(user) do
|
||||||
if not FIELD_SKIP_VALIDATE[k] then
|
if not FIELD_SKIP_VALIDATE[k] then
|
||||||
local invalid
|
local invalid
|
||||||
local override_typecheck = FIELD_OVERRIDE_TYPECHECK[k] or {}
|
|
||||||
if def[k] == nil then
|
if def[k] == nil and types[k] == nil then
|
||||||
-- option does not exist
|
-- option does not exist
|
||||||
invalid = string.format("[NvimTree] unknown option: %s%s", prefix, k)
|
invalid = string.format("Unknown option: %s%s", prefix, k)
|
||||||
elseif type(v) ~= type(def[k]) and not override_typecheck[type(v)] then
|
elseif type(v) ~= type(def[k]) then
|
||||||
-- option is of the wrong type and is not a function
|
local expected
|
||||||
invalid =
|
|
||||||
string.format("[NvimTree] invalid option: %s%s expected: %s actual: %s", prefix, k, type(def[k]), type(v))
|
if types[k] and #types[k] > 0 then
|
||||||
|
if not vim.tbl_contains(types[k], type(v)) then
|
||||||
|
expected = table.concat(types[k], "|")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
expected = type(def[k])
|
||||||
|
end
|
||||||
|
|
||||||
|
if expected then
|
||||||
|
-- option is of the wrong type
|
||||||
|
invalid = string.format("Invalid option: %s%s. Expected %s, got %s", prefix, k, expected, type(v))
|
||||||
|
end
|
||||||
elseif type(v) == "string" and strs[k] and not vim.tbl_contains(strs[k], v) then
|
elseif type(v) == "string" and strs[k] and not vim.tbl_contains(strs[k], v) then
|
||||||
-- option has type `string` but value is not accepted
|
-- option has type `string` but value is not accepted
|
||||||
invalid = string.format("[NvimTree] invalid value for field %s%s: '%s'", prefix, k, v)
|
invalid = string.format("Invalid value for field %s%s: '%s'", prefix, k, v)
|
||||||
end
|
end
|
||||||
|
|
||||||
if invalid then
|
if invalid then
|
||||||
if msg then
|
if msg then
|
||||||
msg = string.format("%s | %s", msg, invalid)
|
msg = string.format("%s | %s", msg, invalid)
|
||||||
else
|
else
|
||||||
msg = string.format("%s", invalid)
|
msg = string.format("[NvimTree] %s", invalid)
|
||||||
end
|
end
|
||||||
user[k] = nil
|
user[k] = nil
|
||||||
else
|
else
|
||||||
validate(v, def[k], strs[k] or {}, prefix .. k .. ".")
|
validate(v, def[k], strs[k] or {}, types[k] or {}, prefix .. k .. ".")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
validate(conf, DEFAULT_OPTS, ACCEPTED_STRINGS, "")
|
validate(conf, DEFAULT_OPTS, ACCEPTED_STRINGS, ACCEPTED_TYPES, "")
|
||||||
|
|
||||||
if msg then
|
if msg then
|
||||||
vim.notify_once(msg .. " | see :help nvim-tree-opts for available configuration options", vim.log.levels.WARN)
|
vim.notify_once(msg .. " | see :help nvim-tree-opts for available configuration options", vim.log.levels.WARN)
|
||||||
|
|||||||
Reference in New Issue
Block a user