Module: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            stable -- @author             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 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 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                MediaWiki 1.24/wmf7 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