モジュール:Entrypoint

--- 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            beta
--  @author             8nml (Fandom Dev Wiki)
--  @param              {table} package Scribunto package.
--  @error85          {string} 'you must specify a function to call'
--  @error91          {string} 'the function you specified did not exist'
--  @erroropt,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 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).
--  @returnopt        {number} Next index.
--  @returnopt        {number|string|table|boolean} Next value.
--  @see                https://github.com/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.
--  @paramopt         {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_cachek
end
for key, val in pairs(frame.args) do
arg_cachekey = 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 packagefn_name then
error(msg('scribunto-common-nosuchfunction', fn_name))
end
if func_check and type(packagefn_name) ~= 'function' then
error(msg('scribunto-common-notafunction', fn_name))
end
return packagefn_name(frame)
end end