• 欢迎来到THBWiki!如果您是第一次来到这里,请点击右上角注册一个帐户
  • 有任何意见、建议、求助、反馈都可以在 讨论板 提出
  • THBWiki以专业性和准确性为目标,如果你发现了任何确定的错误或疏漏,可在登录后直接进行改正

模块:checkargs

来自THBWiki
跳到导航 跳到搜索
Lua-Logo.svg 模块文档[创建]
local p = {}

-- 处理空白参数方式的选项
local blank_arg_filters = {
    first = function(k, v)
        return k ~= 1 or v:match('%S')
    end,
    positional = function(k, v)
        return type(k) ~= 'number' or v:match('%S')
    end,
    all = function(_, v)
        return v:match('%S')
    end,
    none = function()
        return true
    end
}

local function get_filter(mode)
    return blank_arg_filters[mode]
        or error('ignore_blank 可选值为 first, positional, all, none')
end

-- 统一化生成消息
local function make_message(data)
    local name = data.name
    local msg = data.msg
    local args = data.args
    local cat = data.cat

    local formatted = {}
    for i = 1, #args do
        local arg = mw.text.nowiki(mw.text.unstrip(tostring(args[i])))
        formatted[i] = '<code>' .. arg .. '</code>'
    end
    msg = msg .. ':' .. table.concat(formatted, '、')
    local key = table.concat(args, ', ')
    if name then
        msg = '[[' .. name .. ']] 中有' .. msg
        key = name .. ' | ' .. key
    end
    cat = '[[分类:' .. cat .. '|^' .. mw.text.nowiki(key) .. '^]]'
    return require('Module:error')._main{ msg = msg, cat = cat }
end

-- 使用模板传入的参数表创建 ArgsTracker 对象
-- 通过此对象可以访问原始参数, 访问时会记录使用
-- 可用 get_used, get_missing, get_unused 方法获取参数使用情况
-- 在模块逻辑结束后可用 make_message 方法生成未使用参数的警告消息
function p.ArgsTracker(raw_args)
    local obj = {
        _raw = raw_args,
        _input = {},  -- 记录传入的参数
        _used = {}  -- 记录已访问的参数
    }

    for k, _ in pairs(raw_args) do
        obj._input[k] = true
    end

    local mt = {}
    setmetatable(obj, mt)

    -- 通过此对象访问参数时记录使用
    function mt:__index(k)
        self._used[k] = true
        return self._raw[k]
    end

    -- 允许使用 pairs 遍历, 但不记录使用
    function mt:__pairs()
        return pairs(self._raw)
    end

    function mt:__ipairs()
        return ipairs(self._raw)
    end

    -- 返回已使用参数的列表
    function obj:get_used()
        local used = {}
        for k, _ in pairs(self._used) do
            used[#used + 1] = k
        end
        return used
    end

    -- 返回已使用但是未传入的参数的列表
    function obj:get_missing()
        local input = self._input
        local missing = {}
        for k, _ in pairs(self._used) do
            if not input[k] then
                missing[#missing + 1] = k
            end
        end
        return missing
    end

    -- 返回未使用参数的列表
    -- 可用 { ignore_blank = ... } 设置忽略哪些空白参数
    function obj:get_unused(args)
        local ignore_blank = args and args.ignore_blank or 'first'
        local should_keep = get_filter(ignore_blank)

        local used = self._used
        local unused = {}
        for k, _ in pairs(self._input) do
            if not used[k] and should_keep(k, self._raw[k]) then
                unused[#unused + 1] = k
            end
        end
        return unused
    end

    -- 生成关于未使用参数的警告消息
    -- 可以传入 { '模板:模板名', ignore_blank = ... }
    function obj:make_message(args)
        args = args or {}
        local unused = self:get_unused(args)
        if #unused == 0 then
            return nil
        end

        return make_message{
            name = args.name or args[1],
            msg = '以下参数未被使用,请检查填写',
            args = unused,
            cat = '有未使用模板参数的页面'
        }
    end

    function mt.__newindex()
        error('ArgsTracker 对象仅用于访问原始参数, 请勿修改')
    end

    return obj
end

-- 使用已知参数表 args (可用字符串模式) 找出 pargs 中的未知参数
-- 若有未知参数则返回警告消息
function p._check_unknown(args, pargs)
    local known_args = {}
    local regexps = {}
    for k, v in pairs(args) do
        if type(k) == 'number' then
            v = mw.text.trim(v)
            known_args[v] = true
        elseif k:match('^regexp[1-9]%d*$') then
            table.insert(regexps, '^' .. v .. '$')
        end
    end

    local should_keep = get_filter(args.ignore_blank or 'first')
    local unknown_args = {}
    for k, v in pairs(pargs) do
        local k_str = tostring(k)
        if not known_args[k_str] then
            local known = false
            for i = 1, #regexps do
                if mw.ustring.match(k_str, regexps[i]) then
                    known = true
                    break
                end
            end
            if not known and should_keep(k, v) then
                table.insert(unknown_args, k)
            end
        end
    end

    if #unknown_args == 0 then
        return nil
    end

    return make_message{
        name = args.name,
        msg = '以下参数无法识别,请修正',
        args = unknown_args,
        cat = '有未知模板参数的页面'
    }
end

function p.check_unknown(frame)
    local pframe = frame:getParent()
    local args = frame.args
    local pargs = pframe.args

    args.name = pframe:getTitle()
    return p._check_unknown(args, pargs) or ''
end

return p