Documentation for this module may be created at Module:Entrypoint/doc
--- Entrypoint templating wrapper for Scribunto packages.
-- The module generates an entrypoint function that can execute Scribunto
-- package calls in the template context. This allows a package to support
-- both direct and template invocations.
--
-- @script entrypoint
-- @release stable
-- @author [[User:8nml|8nml]]
-- @param {table} package Scribunto package.
-- @error[85] {string} 'you must specify a function to call'
-- @error[91] {string} 'the function you specified did not exist'
-- @error[opt,95] {string} '$2 is not a function'
-- @return {function} Template entrypoint - @{main}.
-- @note Parent frames are not available in Entrypoint's
-- `frame`. This is because recursive (grandparent)
-- frame access is impossible in legacy Scribunto
-- due to [[mw:Manual:Parser#Empty-argument expansion
-- cache|empty-argument expansion cache]] limitations.
-- @note As Entrypoint enables template access rather than
-- a new extension hook, it does not work with named
-- numeric parameters such as `1=` or `2=`. This may
-- result in unexpected behaviour such as Entrypoint
-- and module errors.
--- Stateless, sequential Lua iterator.
-- @function inext
-- @param {table} t Invariant state to loop over.
-- @param {number} i Control variable (current index).
-- @return[opt] {number} Next index.
-- @return[opt] {number|string|table|boolean} Next value.
-- @see [[github:lua/lua/blob/v5.1.1/lbaselib.c#L247]]
local inext = select(1, ipairs{})
--- Check for MediaWiki version 1.25.
-- The concurrent Scribunto release adds a type check for package functions.
-- @variable {boolean} func_check
-- @see [[mw:MediaWiki 1.24/wmf7#Scribunto]]
local func_check = tonumber(mw.site.currentVersion:match('^%d+.%d+')) >= 1.25
--- MediaWiki error message getter.
-- Mimics Scribunto error formatting for script errors.
-- @function msg
-- @param {string} key MediaWiki i18n message key.
-- @param[opt] {string} fn_name Name of package function.
-- @return {string} Formatted lowercase message.
-- @local
local function msg(key, fn_name)
return select(1, mw.message.new(key)
:plain()
:match(':%s*(.-)[.۔。෴։።]?$')
:gsub('^.', mw.ustring.lower)
:gsub('$2', fn_name or '$2')
)
end
--- Template entrypoint function generated by this module.
-- @function main
-- @param {Frame} frame Scribunto frame in module context.
-- @return {string} Module output in template context.
return function(package) return function(f)
local frame = f:getParent()
local args_mt = {}
local arg_cache = {}
args_mt.__pairs = function()
return next, arg_cache, nil
end
args_mt.__ipairs = function()
return inext, arg_cache, 0
end
args_mt.__index = function(t, k)
return arg_cache[k]
end
for key, val in pairs(frame.args) do
arg_cache[key] = val
end
local fn_name = table.remove(arg_cache, 1)
f.args = setmetatable({}, args_mt)
frame.args = setmetatable({}, args_mt)
if not fn_name then
error(msg('scribunto-common-nofunction'))
end
fn_name = mw.text.trim(fn_name)
if not package[fn_name] then
error(msg('scribunto-common-nosuchfunction', fn_name))
end
if func_check and type(package[fn_name]) ~= 'function' then
error(msg('scribunto-common-notafunction', fn_name))
end
return package[fn_name](frame)
end end