“模块:ModulePageSystem”的版本间的差异
1.38>牛腩面 (创建页面,内容为“local mps = {} mps.util = require("Module:ModulePageSystem/util") local dictionary = require("Module:Dictionary") mps.FUNC_HASVALUE_TRUE = function() return true end mps.FUNC_HASVALUE_FALSE = function() return false end mps.…) |
小 (导入1个版本) |
(没有差异)
|
2022年7月8日 (五) 21:15的最新版本
此模块的文档可以在模块:ModulePageSystem/doc创建
local mps = {}
mps.util = require("Module:ModulePageSystem/util")
local dictionary = require("Module:Dictionary")
mps.FUNC_HASVALUE_TRUE = function() return true end
mps.FUNC_HASVALUE_FALSE = function() return false end
mps.FUNC_VALUE_NIL = function() return nil end
--定义一个常量,表示该节点值不存在。
mps.NOVALUE = {
hasValue = mps.FUNC_HASVALUE_FALSE,
value = mps.FUNC_VALUE_NIL
}
--[[
验证一个节点是否是格式正确的对象。
通过检测数个字段、函数是否存在,类型是否正确来验证节点格式是否正确。
-----
node - 将要验证的节点。
validations - 指定了验证的类型,若有多个验证类型,则以空白字符分隔,验证结果将取与。
value - 该节点支持存储值。
sub - 该节点支持包含次级节点。
-----
返回:多个验证类型结果的与值。
--]]
function mps.validate(node, validations)
if node == nil then return false
elseif type(node) ~= "table" then return false
end
if type(validations) == "table" then validations = table.concat(validations, " ")
elseif type(validations) ~= "string" then return false
end
for validation in mw.ustring.gmatch(validations, "%S+") do
if validation == "value" then
if type(node.hasValue) ~= "function" or
type(node.value) ~= "function" then return false end
elseif validation == "ref" then
if type(node.getTarget) ~= "function" then return false end
elseif validation == "sub" then
if type(node.plain) ~= "function" or
type(node.wiki) ~= "function" or
type(node.ref) ~= "function" or
type(node.sub) ~= "function" or
type(node.substart) ~= "function" or
type(node.subend) ~= "function" or
type(node.format) ~= "function" or
type(node.find) ~= "function" then return false end
else
mps.util.error(mw.ustring.format("不支持的验证类型:\"%s\"", validation), mps.util.ELID_WARNING)
return false
end
end
return true
end
--[[
从指定的节点开始按路径查找值。
-----
node - 指定的节点。
path - 路径
-----
返回:路径name处的值。
--]]
function mps.find(node, path, params)
if type(params) ~= "table" then params = {} end
if type(params.path) ~= "table" then params.path = {} end
if type(params.basestack) ~= "table" then params.basestack = {} end
if type(params.refhistory) ~= "table" then params.refhistory = dictionary.create() end
if node == nil or type(node) == "string" then -- node为表示以这个字符串为网页路径创建的节点。
-- 若node为空,则设为调用页面的标题。
node = node or mw.title.getCurrentTitle().prefixedText
-- 尝试加载页面。
local root = mps.load({}, node)
if mps.validate(node, "value") and value:hasValue(params) then
-- 以这个字符串为基地址创建根节点。
node = mps.create(node)
else
node = root
end
end
if params.root == nil then params.root = node end -- 将自身设为查询根节点。
local value
local subpath = mps.util.pathSplit(path)
-- 截取顶层目录为当前名称;其余为下级名称。
local name = subpath[1]
table.remove(subpath, 1)
table.insert(params.path, name) -- 将当前名称添加到路径中。
table.insert(params.basestack, { node.base }) -- 将当前所属页面路径添加到页面路径堆栈中。(由于所属页面路径可能为nil,故用table包裹。)
-- 筛选子节点。子节点是否为底层节点将对其是否会被接受有影响。
-- 底层节点:接受值节点;不接受含有子节点的节点。
-- 非底层节点:接受含有子节点的节点;不接受值节点。
local findInternal = function(_value)
-- 获取节点值。
if mps.validate(_value, "ref") then -- 如果是引用节点
-- 获取引用节点指向的节点。
_value = _value:getTarget(params)
end
if (params.novalidation or false) == true then -- 若忽略子节点是否为底层节点对其是否会被接受的影响。
if #subpath == 0 then -- 仅当子节点为底层节点时生效。
if (mps.validate(_value, "value") and _value:hasValue(params)) or mps.validate(_value, "sub") then
-- 仅在子节点是含有值的值节点或者含有子节点的节点时,直接返回子节点本身。
return _value
end
end
end
if #subpath == 0 and mps.validate(_value, "value") then -- 如果是底层节点,且节点是值节点。
if _value:hasValue(params) then -- 如果有值则返回节点。
return _value
end
elseif #subpath ~= 0 and mps.validate(_value, "sub") then -- 如果不是底层节点,且节点含有子节点。
-- 进行递归查找。
_value = _value:find(subpath, params)
if mps.validate(_value, "value") and _value:hasValue(params) then -- 子节点查找到值则返回节点。
return _value
elseif mps.validate(_value, "sub") then -- 从findInternal返回的含有子节点的节点绝对是忽略层级影响。
return _value
end
elseif #subpath == 0 and not (mps.validate(_value, "value") or mps.validate(_value, "sub")) then -- 节点不是任何节点,且是底层节点。
mps.util.error("非节点对象。", mps.util.ELID_ERROR)
end
return mps.NOVALUE -- 查找不到子节点树的值。
end
if mps.validate(node, "sub") then -- 本节点含有子节点。
-- 寻找键name。
if node.dic:hasKey(name) then
value = findInternal(node.dic:getValue(name))
if mps.validate(value, "value") and value:hasValue(params) then
table.remove(params.path, #params.path) -- 从路径中删除最后一段名称。
table.remove(params.basestack, #params.basestack) -- 从页面路径堆栈中删除最后一段所属页面路径。
return value
elseif mps.validate(value, "sub") then -- 从findInternal返回的含有子节点的节点绝对是忽略层级影响。
table.remove(params.path, #params.path) -- 从路径中删除最后一段名称。
table.remove(params.basestack, #params.basestack) -- 从页面路径堆栈中删除最后一段所属页面路径。
return value
end
end
-- 寻找通用函数formatfunc。
if node.formatfunc ~= nil then -- 找到通用函数formatfunc。
-- 获取处理结果。
value = node:formatfunc(name, params)
value = findInternal(value)
if mps.validate(value, "value") and value:hasValue(params) then
table.remove(params.path, #params.path) -- 从路径中删除最后一段名称。
table.remove(params.basestack, #params.basestack) -- 从页面路径堆栈中删除最后一段所属页面路径。
return value
elseif mps.validate(value, "sub") then -- 从findInternal返回的含有子节点的节点绝对是忽略层级影响。
table.remove(params.path, #params.path) -- 从路径中删除最后一段名称。
table.remove(params.basestack, #params.basestack) -- 从页面路径堆栈中删除最后一段所属页面路径。
return value
end
end
end
-- 尝试加载页面。
local fullpagename = nil
-- 沿堆栈向下查询上级节点的基路径。
for i = #params.basestack, 1, -1 do
if #params.basestack[i] ~= 0 then
fullpagename = params.basestack[i][1]
break;
end
end
if fullpagename == nil then
-- 无法获取基路径。
mps.util.error(mw.ustring.format("无法获取节点“%s”基路径,因为上层节点均未定义基路径。", mps.util.pathCombine(params.path)), mps.util.ELID_WARNING)
else
fullpagename = mw.ustring.format("%s/%s", fullpagename, table.concat(mps.util.pathSplit(params.path), "/")) -- 要加载的页面。
value = findInternal(mps.load(node, fullpagename))
if mps.validate(value, "value") and value:hasValue(params) then -- 页面加载成功。
table.remove(params.path, #params.path) -- 从路径中删除最后一段名称。
table.remove(params.basestack, #params.basestack) -- 从页面路径堆栈中删除最后一段所属页面路径。
return value
elseif mps.validate(value, "sub") then -- 从findInternal返回的含有子节点的节点绝对是忽略层级影响。
table.remove(params.path, #params.path) -- 从路径中删除最后一段名称。
table.remove(params.basestack, #params.basestack) -- 从页面路径堆栈中删除最后一段所属页面路径。
return value
end
end
table.remove(params.path, #params.path) -- 从路径中删除最后一段名称。
table.remove(params.basestack, #params.basestack) -- 从页面路径堆栈中删除最后一段所属页面路径。
return mps.NOVALUE -- 查询不到值。
end
mps.FUNC_SUBEND_COMMON = function(self)
mps.util.error("语法错误:subend。(当前并未处于定义子项的上下文。)", mps.util.ELID_WARNING)
return self
end
--[[
从一个页面地址创建一个节点。
-----
page - 定义这个节点的页面,应当是你在书写这个代码时所处的模块名页面全名。
-----
返回:新节点。
--]]
function mps.create(page)
if page ~= nil and type(page) ~= "string" then mps.util.error(mw.ustring.format("在create中参数page的值类型错误。(应为%s,实际为%s)", "nil或string", type(page)), mps.util.ELID_FATAL)
elseif page == nil then -- 检测页面地址是否为空。
mps.util.error(mw.ustring.format("页面地址为空。", page), mps.util.ELID_WARNING)
elseif type(page) == "string" and mw.title.new(page) == nil then -- 检测页面地址是否包含不合法字符。
mps.util.error(mw.ustring.format("页面地址“%s”包含不合法字符。", page), mps.util.ELID_ERROR)
end
local prototype = {
dic = dictionary.create(function(k1, k2) return mps.util.normalize(k1) == mps.util.normalize(k2) end),
base = page, -- 本节点所在的页面地址。
inheritbase = "", -- [未启用]以定义了页面地址的最近一个上层节点开始到本节点的路径,即本节点的“继承”得到的基路径。
plain = mps.registerPlain,
wiki = mps.registerWiki,
ref = mps.registerRef,
sub = mps.registerSubpage,
substart = mps.registerNewSubpage,
subend = mps.FUNC_SUBEND_COMMON,
format = mps.registerFormat,
find = mps.find
}
return prototype
end
mps.FUNC_VALUE_PLAIN = function(self) return self.innervalue end
--[[
创建一个纯文本的值节点。
-----
plain - 文本内容。
page - 定义这个节点的页面,应当是你在书写这个代码时所处的模块名页面全名。
-----
返回:新值节点。
--]]
function mps.createPlain(plain, page)
if plain ~= nil and type(plain) ~= "string" then mps.util.error(mw.ustring.format("参数plain的值类型错误。(应为%s,实际为%s)", "nil或string", type(plain)), mps.util.ELID_FATAL) end
if page ~= nil and type(page) ~= "string" then mps.util.error(mw.ustring.format("参数page的值类型错误。(应为%s,实际为%s)", "nil或string", type(page)), mps.util.ELID_FATAL)
elseif page == nil then -- 检测页面地址是否为空。
mps.util.error(mw.ustring.format("页面地址为空。", page), mps.util.ELID_WARNING)
elseif type(page) == "string" and mw.title.new(page) == nil then -- 检测页面地址是否包含不合法字符。
mps.util.error(mw.ustring.format("页面地址“%s”包含不合法字符。", page), mps.util.ELID_ERROR)
end
return {
base = page,
innervalue = plain,
hasValue = mps.FUNC_HASVALUE_TRUE,
value = mps.FUNC_VALUE_PLAIN
}
end
mps.FUNC_VALUE_WIKI = function(self, params)
if self.innervalue == nil then return nil
elseif params.plain then return self.innervalue
elseif self.innerwiki ~= nil then return self.innerwiki
elseif params == nil or params.frame == nil then
mps.util.error(mw.ustring.format("无法获取wiki执行对象(frame的值为nil)。"), mps.util.ELID_WARNING)
else
self.innerwiki = params.frame:preprocess(self.innervalue)
return self.innerwiki
end
end
--[[
创建一个Wiki内容的值节点。
-----
wiki - Wiki内容。
plain - 指示wiki参数的字符串值是否是纯文本,默认为true。
page - 定义这个节点的页面,应当是你在书写这个代码时所处的模块名页面全名。
-----
返回:新值节点。
--]]
function mps.createWiki(wiki, plain, page)
if wiki ~= nil and type(wiki) ~= "string" then mps.util.error(mw.ustring.format("参数wiki的值类型错误。(应为%s,实际为%s)", "nil或string", type(wiki)), mps.util.ELID_FATAL) end
if page ~= nil and type(page) ~= "string" then mps.util.error(mw.ustring.format("参数page的值类型错误。(应为%s,实际为%s)", "nil或string", type(page)), mps.util.ELID_FATAL)
elseif page == nil then -- 检测页面地址是否为空。
mps.util.error(mw.ustring.format("页面地址为空。", page), mps.util.ELID_WARNING)
elseif type(page) == "string" and mw.title.new(page) == nil then -- 检测页面地址是否包含不合法字符。
mps.util.error(mw.ustring.format("页面地址“%s”包含不合法字符。", page), mps.util.ELID_ERROR)
end
local result = {
base = page,
innervalue = wiki,
innerwiki = nil,
hasValue = mps.FUNC_HASVALUE_TRUE,
value = mps.FUNC_VALUE_WIKI
}
if (plain or false) ~= true then result.innerwiki = wiki end -- 默认是以纯文本形式创建。
return result
end
local find_ref = function(node, params)
-- 查找引用历史,检测是否循环引用。
local flag = false
local path = mps.util.pathCombine(params.path)
if params.refhistory:hasKey(path) then
-- 检测到循环引用。
flag = true
else
for _, rh_entry in params.refhistory:enum() do
if rh_entry.value == node then
-- 检测到循环引用。
flag = true
break
end
end
end
if flag then
local errorinfo = {}
for _, _entry in params.refhistory:enum() do
table.insert(errorinfo, _entry.key)
end
table.insert(errorinfo, rh_entry.key)
mps.util.error("形成了循环引用。(“%s”)", table.concat(errorinfo, "”→“"), mps.util.ELID_ERROR)
return mps.NOVALUE
end
-- 构建引用目标节点的路径。
local newPath
if node.isabsolute then -- 绝对路径
newPath = mps.util.pathCombine(node.innervalue)
else -- 相对路径
newPath = mps.util.pathCombine(params.path, mps.util.PARENTNODE, node.innervalue)
end
-- 构建查找引用目标节点的新参数。
local newParams = {
frame = params.frame,
plain = params.plain,
refhistory = dictionary.create(nil, params.refhistory):add(path, node), -- 新建引用历史字典的副本,并将自身添加进去。
novalidation = true -- 忽略节点所处层级的影响。
}
return mps.find(params.root, newPath, newParams), newParams
end
mps.FUNC_GETTARGET_REF = function(self, params)
local target, newParams = find_ref(self, params)
-- 递归获得指向的目标节点。
if mps.validate(target, "ref") then
return target:getTarget(target, newParams)
else
return target
end
end
--[[
创建一个引用节点。
-----
target - 引用指向的目标。
isabsolute - 指示target参数表示的引用目标路径是否为绝对路径,默认为true。
page - 定义这个节点的页面,应当是你在书写这个代码时所处的模块名页面全名。
-----
返回:新引用节点。
--]]
function mps.createRef(target, isabsolute, page)
if page ~= nil and type(page) ~= "string" then mps.util.error(mw.ustring.format("参数page的值类型错误。(应为%s,实际为%s)", "nil或string", type(page)), mps.util.ELID_FATAL)
elseif page == nil then -- 检测页面地址是否为空。
mps.util.error(mw.ustring.format("页面地址为空。", page), mps.util.ELID_WARNING)
elseif type(page) == "string" and mw.title.new(page) == nil then -- 检测页面地址是否包含不合法字符。
mps.util.error(mw.ustring.format("页面地址“%s”包含不合法字符。", page), mps.util.ELID_ERROR)
end
return {
base = page,
innervalue = target,
isabsolute = (isabsolute or false) == true,
getTarget = mps.FUNC_GETTARGET_REF
}
end
--[[
向节点中注册一个纯文本的子值节点。
-----
parent - 节点本身。
name - 子节点名称。
plain - 文本内容。
page - 定义这个节点的页面,应当是你在书写这个代码时所处的模块名页面全名。若为非空值,则将覆盖参数parent的继承。
-----
返回:节点本身。(为语法糖提供支持)
--]]
function mps.registerPlain(parent, name, plain, page)
if type(parent) == "nil" then mps.util.error(mw.ustring.format("参数parent的值类型错误。(应为%s,实际为%s)", "table", type(parent)), mps.util.ELID_FATAL) end
if type(name) ~= "string" then mps.util.error(mw.ustring.format("参数name的值类型错误。(应为%s,实际为%s)", "string", type(name)), mps.util.ELID_FATAL) end
if page ~= nil and type(page) ~= "string" then mps.util.error(mw.ustring.format("参数page的值类型错误。(应为%s,实际为%s)", "nil或string", type(page)), mps.util.ELID_FATAL) end
plain = mps.createPlain(plain, page or parent.page)
if parent.dic:hasKey(name) then
if parent.dic:getValue(name) ~= nil and parent.dic:getValue(name):hasValue() then
mps.util.error(mw.ustring.format("在对节点\"%s\"赋值时失败,该节点已存在另外的值。", name), mps.util.ELID_ERROR)
else
parent.dic:setValue(name, plain)
end
else
parent.dic:add(name, plain)
end
return parent
end
--[[
向节点中注册一个Wiki内容的子值节点。
-----
parent - 节点本身。
name - 子节点名称。
wiki - Wiki内容。
plain - 指示wiki参数的字符串值是否是纯文本,默认为true。
page - 定义这个节点的页面,应当是你在书写这个代码时所处的模块名页面全名。若为非空值,则将覆盖参数parent的继承。
-----
返回:节点本身。(为语法糖提供支持)
--]]
function mps.registerWiki(parent, name, wiki, plain, page)
if type(parent) == "nil" then mps.util.error(mw.ustring.format("参数parent的值类型错误。(应为%s,实际为%s)", "table", type(parent)), mps.util.ELID_FATAL) end
if type(name) ~= "string" then mps.util.error(mw.ustring.format("参数name的值类型错误。(应为%s,实际为%s)", "string", type(name)), mps.util.ELID_FATAL) end
if page ~= nil and type(page) ~= "string" then mps.util.error(mw.ustring.format("参数page的值类型错误。(应为%s,实际为%s)", "nil或string", type(page)), mps.util.ELID_FATAL) end
wiki = mps.createWiki(wiki, plain, page or parent.page)
if parent.dic:hasKey(name) then
if parent.dic:getValue(name) ~= nil and parent.dic:getValue(name):hasValue() then
mps.util.error(mw.ustring.format("在对节点\"%s\"赋值时失败,该节点已存在另外的值。", name), mps.util.ELID_ERROR)
else
parent.dic:setValue(name, wiki)
end
else
parent.dic:add(name, wiki)
end
return parent
end
--[[
向节点中注册一个引用的子值节点。
-----
parent - 节点本身。
names - 所有引用子节点的名称(被指向目标的别名)。若类型为string则表示一个名称;若类型为table则表示多个名称。
target - 引用指向的目标。
isabsolute - 指示target参数表示的引用目标路径是否为绝对路径,默认为true。
page - 定义这个节点的页面,应当是你在书写这个代码时所处的模块名页面全名。若为非空值,则将覆盖参数parent的继承。
-----
返回:节点本身。(为语法糖提供支持)
--]]
function mps.registerRef(parent, names, target, isabsolute, page)
if type(parent) == "nil" then mps.util.error(mw.ustring.format("参数parent的值类型错误。(应为%s,实际为%s)", "table", type(parent)), mps.util.ELID_FATAL) end
if type(names) == "string" then names = { names }
elseif type(names) ~= "table" then mps.util.error(mw.ustring.format("参数names的值类型错误。(应为%s,实际为%s)", "string或table", type(names)), mps.util.ELID_FATAL)
end
if page ~= nil and type(page) ~= "string" then mps.util.error(mw.ustring.format("参数page的值类型错误。(应为%s,实际为%s)", "nil或string", type(page)), mps.util.ELID_FATAL) end
local ref
for i, name in ipairs(names) do
if type(name) ~= "string" then
mps.util.error(mw.ustring.format("参数names的第%d项的值类型错误。(应为%s,实际为%s)", i, "string", type(name)), mps.util.ELID_FATAL)
else
ref = ref or mps.createRef(target, isabsolute, page or parent.base) -- 只创建一次,整个循环使用同一且唯一的引用节点。
if parent.dic:hasKey(name) then
if parent.dic:getValue(name) ~= nil and parent.dic:getValue(name):hasValue() then
mps.util.error(mw.ustring.format("在对节点\"%s\"赋值时失败,该节点已存在另外的值。", name), mps.util.ELID_ERROR)
else
parent.dic:setValue(name, ref)
end
else
parent.dic:add(name, ref)
end
end
end
return parent
end
--[[
向节点中注册一个现有的子节点。
这个子节点可以是从另一个页面导入、在本地定义的——node节点、储存了纯数据的普通Lua表。
-----
parent - 节点本身。
name - 子节点名称。
node - 将作为被添加的子节点的内容。
page - 定义这个节点的页面,应当是你在书写这个代码时所处的模块名页面全名。若为非空值,则将覆盖参数parent的继承。
-----
返回:节点本身。(为语法糖提供支持)
--]]
function mps.registerSubpage(parent, name, node, page)
if type(parent) == "nil" then mps.util.error(mw.ustring.format("参数parent的值类型错误。(应为%s,实际为%s)", "table", type(parent)), mps.util.ELID_FATAL) end
if type(name) ~= "string" then mps.util.error(mw.ustring.format("参数name的值类型错误。(应为%s,实际为%s)", "string", type(name)), mps.util.ELID_FATAL) end
if page ~= nil and type(page) ~= "string" then mps.util.error(mw.ustring.format("参数page的值类型错误。(应为%s,实际为%s)", "nil或string", type(page)), mps.util.ELID_FATAL) end
if type(node) == "string" then -- 是从指定路径的页面导入的内容。
-- node默认是绝对路径,若需要引用节点所处页面路径则需使用“%0”。
-- 获取绝对路径。
local path = mw.ustring.gsub(node, "%%[%%0]", function(m)
if m == "%%" then return "%"
elseif m == "%0" then return parent.base
else return ""
end
end)
-- 加载页面。
node = mps.load(parent, path)
elseif type(node) == "table" then -- 是在本地定义的内容。
if mps.validate(node, "sub") then -- 检测是否是含有子节点的节点对象。
node = mps.derive(parent, node, page) -- 创建一个node的继承节点。
elseif mps.validate(node, "value") then -- 检测是否是值节点。
-- 设置所属页面路径。
node.base = node.base or page or parent.base -- 取值原则:本地定义的值节点的已定义所属页面路径 → 覆盖参数parent继承的页面路径 → 参数parent继承的页面路径。
else
node = mps.parse(parent, node, page) -- 从一个普通Lua表转换成为节点。
end
end
if parent.dic:hasKey(name) then
if parent.dic:getValue(name) ~= nil and parent.dic:getValue(name):hasValue() then
mps.util.error(mw.ustring.format("在对节点\"%s\"赋值时失败,该节点已存在另外的值。", name), mps.util.ELID_ERROR)
else
parent.dic:setValue(name, node)
end
else
parent.dic:add(name, node)
end
return parent
end
mps.FUNC_SUBEND_SUB = function(self) return self.parent end
--[[
向节点中注册一个子节点,并切换到子节点的上下文。
这个子节点可以是从另一个模板导入、在本地定义的——node节点、储存了纯数据的普通Lua表。
-----
parent - 节点本身。
name - 子节点名称。
node - 将作为被添加的子节点的内容。
page - 定义这个节点的页面,应当是你在书写这个代码时所处的模块名页面全名。若为非空值,则将覆盖参数parent的继承。
-----
返回:子节点本身。(为语法糖提供支持)
--]]
function mps.registerNewSubpage(parent, name)
if type(parent) == "nil" then mps.util.error(mw.ustring.format("参数parent的值类型错误。(应为%s,实际为%s)", "table", type(parent)), mps.util.ELID_FATAL) end
if type(name) ~= "string" then mps.util.error(mw.ustring.format("参数name的值类型错误。(应为%s,实际为%s)", "string", type(name)), mps.util.ELID_FATAL) end
local prototype = mps.create(parent.page) -- 获取一个标准的节点对象。
prototype.inheritbase = mps.util.pathCombine(parent.inheritbase, name) -- 继承本节点的路径组成新路径。
prototype.parent = parent -- 将本节点保存在parent字段中
prototype.subend = mps.FUNC_SUBEND_SUB -- 结束子节点定义,返回到其父节点,即本节点。
if parent.dic:hasKey(name) then
if parent.dic:getValue(name) ~= nil and parent.dic:getValue(name):hasValue() then
mps.util.error(mw.ustring.format("在对节点\"%s\"赋值时失败,该节点已存在另外的值。", name), mps.util.ELID_ERROR)
else
parent.dic:setValue(name, prototype)
end
else
parent.dic:add(name, prototype)
end
return prototype
end
function mps.registerFormat(parent, format)
if type(parent) == "nil" then mps.util.error(mw.ustring.format("参数parent的值类型错误。(应为%s,实际为%s)", "table", type(parent)), mps.util.ELID_FATAL) end
if format == nil then return
elseif type(format) ~= "function" then mps.util.error(mw.ustring.format("通用函数formatfunc类型错误。(应为%s,实际为%s)", "function", type(format)), mps.util.ELID_FATAL)
end
if parent.formatfunc == nil then
parent.formatfunc = format
else
mps.util.error("通用函数赋值失败,该节点已存在另外的通用函数。", mps.util.ELID_ERROR)
end
return parent
end
--[[
从指定页面加载节点。
-----
parent - 本节点。
path - 包含节点的模块页面地址。
-----
返回:指定页面包含的节点。
--]]
function mps.load(parent, path)
if type(parent) == "nil" then mps.util.error(mw.ustring.format("在load中参数parent的值类型错误。(应为%s,实际为%s)", "table", type(parent)), mps.util.ELID_FATAL) end
if type(path) ~= "string" then mps.util.error(mw.ustring.format("在load中参数path的值类型错误。(应为%s,实际为%s)", "string", type(path)), mps.util.ELID_FATAL) end
local success, result = pcall(function(_path)
local title = mw.title.new(_path) -- 获取要加载的页面的标题对象。
if title == nil then
error(mw.ustring.format("页面“%s”路径格式不正确。"), _path)
elseif title.exists then -- 加载的页面存在。
return require(_path)
else
mps.util.error(mw.ustring.format("页面“%s”不存在。", _path), mps.util.ELID_WARNING)
return mps.NOVALUE
end
end, path)
if result == mps.NOVALUE then return result
elseif not success then
mps.util.error(result, mps.util.ELID_ERROR)
return mps.NOVALUE
end
local node = result
if mps.validate(node, "sub") then -- 检测是否是节点对象。
node = mps.derive(parent, node, path)
else
node = mps.parse(parent, node, path)
end
return node
end
--[[
将一个节点设为本节点的继承节点。
-----
parent - 本节点。
sub - 要被设为继承节点的节点。
page - 定义这个节点的页面,应当是你在书写这个代码时所处的模块名页面全名。若为非空值,则将覆盖参数parent的继承。
-----
返回:被设为继承节点的节点。
--]]
function mps.derive(parent, sub, page)
if type(parent) == "nil" then mps.util.error(mw.ustring.format("在derive中参数parent的值类型错误。(应为%s,实际为%s)", "table", type(parent)), mps.util.ELID_FATAL) end
if type(sub) ~= "table" then mps.util.error(mw.ustring.format("在derive中参数sub的值类型错误。(应为%s,实际为%s)", "table", type(sub)), mps.util.ELID_FATAL) end
if page ~= nil and type(page) ~= "string" then mps.util.error(mw.ustring.format("参数page的值类型错误。(应为%s,实际为%s)", "nil或string", type(page)), mps.util.ELID_FATAL) end
sub.base = sub.base or page or parent.base
return sub
end
--[[
将一个普通Lua表转换成为本节点的子节点。
-----
parent - 本节点。
tab - 要被转换为本节点的子节点的普通Lua表。
page - 定义这个节点的页面,应当是你在书写这个代码时所处的模块名页面全名。若为非空值,则将覆盖参数parent的继承。
-----
返回:转换后的节点。
--]]
function mps.parse(parent, tab, page)
if type(parent) == "nil" then mps.util.error(mw.ustring.format("在parse中参数parent的值类型错误。(应为%s,实际为%s)", "table", type(parent)), mps.util.ELID_FATAL) end
if type(tab) ~= "table" then mps.util.error(mw.ustring.format("在parse中参数tab的值类型错误。(应为%s,实际为%s)", "table", type(tab)), mps.util.ELID_FATAL) end
if page ~= nil and type(page) ~= "string" then mps.util.error(mw.ustring.format("参数page的值类型错误。(应为%s,实际为%s)", "nil或string", type(page)), mps.util.ELID_FATAL) end
local node = mps.create(page or parent.base)
for _name, _node in pairs(tab) do
if type(_node) == "table" then
-- 递归转换Lua表中的节点
mps.registerSubpage(node, _name, _node)
elseif type(_node) == "string" then
-- 默认转换为纯文本节点。
mps.registerPlain(node, _name, _node)
end
end
return node
end
return mps