模組:Ifexist
外观
local p = {}
local function makeTitle(title, callFn)
if type(title) == type({}) and type(title.fullText) == type('') then
return title
elseif type(title) == type('') then
local success, titleObj = pcall(mw.title.new, title)
if success and titleObj then
return titleObj
end
return false
end
error(string.format(
'bad argument #1 to \'%s\' (%s expected, got %s)',
callFn,
'string or mw.title object',
type(title)
))
end
local function wrapCacheAbleExistsFunc(callFn, callback)
local cache = {}
return function (title, ...)
local titleObj = makeTitle(title, callFn)
if not titleObj or titleObj.interwiki ~= '' then
return false
end
local cacheValue = cache[titleObj.fullText]
if cacheValue == nil then
cacheValue = callback(titleObj, ...)
cache[titleObj.fullText] = cacheValue
end
return cacheValue
end
end
local function wrapIfExists(fn)
return function (title, thenVal, elseVal)
return fn(title) and thenVal or elseVal
end
end
-- 使用 Lua Api mw.title.exists 來判斷
-- 不會呼叫 findVariantLink 所以有繁簡差異的頁面「不會」識別出來
-- 也會嚴格限制 500 次調用
-- from [[Special:PermanentLink/42867949#L-142]]
p._luaExists = wrapCacheAbleExistsFunc('_luaExists', function (titleObj)
return titleObj.exists and true or false
end)
p._luaIfExists = wrapIfExists(p._luaExists)
-- 檢查檔案的
p._luaFileExists = wrapCacheAbleExistsFunc('_luaFileExists', function (titleObj)
return (titleObj.namespace == 6 or titleObj.namespace == -2) and titleObj.file.exists and true or false
end)
p._luaFileIfExists = wrapIfExists(p._luaFileExists)
-- 使用解析器函數來判斷
-- 該解析器函數會呼叫 findVariantLink 有繁簡差異的頁面會識別出來
-- 由於使用了 LinkCache,所以允許次數相對寬鬆
-- from [[Special:PermanentLink/85840827#L-31]]
local existsPlaceholder = '__EXISTS__'
local missingPlaceholder = '__MISSING__'
p._pfExists = wrapCacheAbleExistsFunc('_pfExists', function (titleObj)
return mw.getCurrentFrame():callParserFunction('#ifexist', { titleObj.fullText, existsPlaceholder, missingPlaceholder }) == existsPlaceholder
end)
-- @deprecated
p._parseFunctionExists = p._pfExists
p._pfIfExists = wrapIfExists(p._pfExists)
-- @deprecated
p._parseFunctionIfExists = p._pfIfExists
-- 檢查檔案的
p._pfFileExists = wrapCacheAbleExistsFunc('_pfFileExists', function (titleObj)
if titleObj.namespace == 6 then
-- 解析器函數檢查檔案本身是否存在的方式是查詢 Media 命名空間
titleObj = mw.title.makeTitle(-2, titleObj.text)
end
return titleObj.namespace == -2 and p._pfExists(titleObj) or false
end)
p._pfFileIfExists = wrapIfExists(p._pfFileExists)
function p._detectLangConvDiff(title)
-- 檢查輸入頁面是否不存在但呼叫 findVariantLink 後可以找到對應的繁簡頁面
-- 技術細節:
-- - 解析器函數會呼叫 findVariantLink
-- - Lua 函數不會呼叫 findVariantLink
-- - 故可以檢查兩個函數的返回值來確定一個頁面與其實際存在的頁面是否是有繁簡差異
-- 註:邏輯上可以用 parseFunctionExists ~= luaExists
-- 但後者是高開銷函數要省著用,並且解析器函數版本都回報不存在了就不用測 Lua Api 了
local titleObj = makeTitle(title, '_detectLangConvDiff')
if titleObj and titleObj.interwiki == '' then
local pfExists = p._pfExists(titleObj)
if pfExists then
return not p._luaExists(titleObj)
end
end
return false
end
-- //// //// --
local yesno
local function tidyValNoChange(value)
return value
end
local function tidyValTrim(value)
return mw.text.trim(value)
end
-- 註:wikitext 呼叫解析器函數不需要透過 Lua
-- 所以只提供 Lua Api
function p.main(frame)
if type(yesno) ~= type(tonumber) then
yesno = require('Module:Yesno')
end
local args = frame.args
local tidyValue = yesno(args.noTrim) and tidyValNoChange or tidyValTrim
local title = args.title or args[1]
if not title then
error('[[Module:Ifexist]]: Missing title.')
end
local thenVal = tidyValue(args['then'] or args[2] or title)
local elseVal = tidyValue(args['else'] or args[3] or '')
return p._luaIfExists(title, thenVal, elseVal)
end
return p