跳转到内容

模組:ACGaward/nominee check new

本页使用了标题或全文手工转换
维基百科,自由的百科全书

require('strict')

local str = mw.ustring
local split = mw.text.split

local getArgs = require("Module:Arguments").getArgs

local CURRENT_RULES_VERSION = '1'

---@alias RuleCode string
---@alias Rule { [1]: string, [2]: number, aliases: RuleCode[] }
---@alias Rules table<RuleCode, Rule>

--- @param ver string?
--- @param strict boolean
--- @return Rules
local function load_rules(ver, strict)
	if strict ~= false and ver == nil then
		error('需指定規則版本號`|ver=' .. CURRENT_RULES_VERSION .. '`')
	end
    local version = ver or CURRENT_RULES_VERSION
    local rules_page = 'Module:ACGaward/nominee check new/' .. version
    return mw.loadData(rules_page)
end

--- @param text string
--- @param status string
--- @return string
local function with_icon(text, status)
    local icon_table = {
        ["yes"] = "[[File:Green check.svg|13px|alt=✓|link=]]",
        ["partly"] = "[[File:Yellow check.svg|13px|alt=✓|link=]]",
        ["no"] = "[[File:Red x.svg|13px|alt=✗|link=]]"
    }
    return icon_table[status] .. ' ' .. text
end

---@param criteria_table Rules
---@param code RuleCode
---@return string
---@return table
local function parse_code(criteria_table, code)
    if code == nil then
        return nil
    end

    local normalized_code = str.lower(code)
    local rule = criteria_table[normalized_code]
    if criteria_table[normalized_code] then
        return normalized_code, rule
    end

    for k, v in pairs(criteria_table) do
        for _, w in ipairs(v.aliases) do
            if w == normalized_code then
                return k, v
            end
        end
    end
end

---@param criteria_table Rules
---@param text string
---@return string?
---@return string?
---@return number?
---@return boolean?
local function parse_item(criteria_table, text)
    local _, _, code_, pending_mark = str.find(text, "^([0-9A-Za-z-]+)([??]?)")
    local code, rule = parse_code(criteria_table, code_)
    if rule == nil then
        return
    end
    local _, _, annotation = str.find(text, "[((](.+)[))]")
    annotation = annotation or rule[1]
    local _, _, score = str.find(text, "%[(%d+%.?%d-)%]")
    score = score and tonumber(score) or rule[2]
    local pending = (pending_mark ~= "")
    return code, annotation, score, pending
end

---@param code string
---@param annotation string
---@param pending boolean
---@return string
local function item_string(code, annotation, pending)
    local template = '<span style="margin-right: 0.2em; font-weight: bold;">%s</span><small>%s</small>'
    if pending then
        template = "''" .. template .. "''"
    end
    return str.format(template, str.sub(code, 1, 1), annotation)
end

---In seek of defamiliarization.
---@param num number
---@return string
local function frac_format(num)
    if num == 0 then
        return "?"
    end
    local integer, decimal = math.modf(num)
    if decimal == 0.5 then
        if integer == 0 then
            return '½'
        end
        return tostring(integer) .. '½'
    end
    return tostring(num)
end

---@param config_table Rules
---@param text string
---@return string
---@return number
local function generate_result(config_table, text)
    local items = {}
    local string_fragments = split(text, "%s+")
    for _, string_fragment in ipairs(string_fragments) do
        local code, annotation, score, pending = parse_item(config_table, string_fragment)
        if code then
            table.insert(items, { code, annotation, score, pending })
        end
    end
    local result_string_fragments, total_score = {}, 0
    for _, v in ipairs(items) do
        table.insert(result_string_fragments, item_string(v[1], v[2], v[4]))
        total_score = total_score + v[3]
    end
    return table.concat(result_string_fragments, '、'), total_score
end

local p = {}

local function makeInvokeFunc(funcName)
    return function(frame)
        local args = getArgs(frame)
        return p[funcName](args)
    end
end

p.main = makeInvokeFunc("_main")
function p._main(args)
    if args[1] == nil then
        return
    end

    if args[1] == "0" then
        return with_icon("'''不得分'''。", "no")
    end

    local criteria = load_rules(args.ver)
    local _result, _score = generate_result(criteria, args[1])
    local yes_result = str.format("符合%s,'''得%s分'''", _result, frac_format(_score))
    if args.no == nil then
        return with_icon(yes_result .. '。', 'yes')
    end

    _result, _score = generate_result(criteria, args.no)
    local no_result = str.format("不符合%s", _result)
    return with_icon(yes_result .. ";" .. no_result .. "。", 'partly')
end

p.request = makeInvokeFunc("_request")
function p._request(args)
    if args[1] == nil then
        return
    end

    local criteria = load_rules(args.ver)
    local _result, _score = generate_result(criteria, args[1])
    if _result == "" then
        return args[1]
    end
    return str.format("%s,計%s分", _result, frac_format(_score))
end

p.item_doc = makeInvokeFunc('_item_doc')
function p._item_doc(args)
    local criteria = load_rules(args.ver, false)
    local normalized_code = parse_code(criteria, args[1])
    local rule = criteria[normalized_code]
    if rule == nil then
        return
    end
    return str.format('<code>%s</code> — %s(%s分)', args[1], rule[1], frac_format(rule[2]))
end

p.rules_ver = makeInvokeFunc('_rules_ver')
function p._rules_ver(args)
    return CURRENT_RULES_VERSION
end

return p