Module:Lua
From Liquipedia Commons Wiki
Some functions for checking the existence of modules and loading them.
API[edit]
- Programmatic name: Lua
- moduleExists(name: string) → boolean
Checks if a Module with the name exists.
- requireIfExists(name: string, options: table) → Module require or default
Requires the Module if it exists and returns the default otherwise.
- loadDataIfExists(name: string) → Module data or default
Loads the Module data if the Module exists and returns the default otherwise.
- import(name: string, options: table?) → Module
Imports a module by name.
See all our documentation here.
The above documentation is transcluded from Module:Lua/doc. (edit | history) Editors can experiment in this module's sandbox (create | mirror) and testcases (edit | run) pages. Subpages of this module. |
--- -- @Liquipedia -- wiki=commons -- page=Module:Lua -- -- Please see https://github.com/Liquipedia/Lua-Modules to contribute -- local Logic = require('Module:Logic') local StringUtils = require('Module:StringUtils') local Lua = {} ---Checks for the existence of a Lua module ---@param name string ---@return boolean function Lua.moduleExists(name) if package.loaded[name] then return true else -- Package.Searchers was renamed from Loaders in lua5.2, have support for both ---@diagnostic disable-next-line: deprecated for _, searcher in ipairs(package.searchers or package.loaders) do local loader = searcher(name) if type(loader) == 'function' then -- luacheck: ignore -- luacheck complains about package.preload being read-only package.preload[name] = loader return true end end return false end end ---Imports a module if it exists by its name. --- ---By default it will include the /dev module if in dev mode activated. This can be turned off by setting --- the requireDevIfEnabled option to false. ---@param name string ---@param options {requireDevIfEnabled: boolean, loadData: boolean?}? ---@return unknown? function Lua.requireIfExists(name, options) if Lua.moduleExists(name) then return Lua.import(name, options) end end ---Loads (mw.loadData) a data module if it exists by its name. ---@deprecated use `Lua.requireIfExists` with `loadData` option instead ---@param name string ---@return unknown? function Lua.loadDataIfExists(name) mw.ext.TeamLiquidIntegration.add_category('Pages using deprecated Lua.loadDataIfExists function') return Lua.requireIfExists(name, {loadData = true}) end ---Imports a module by its name. ---By default it will include the /dev module if in dev mode activated. This can be turned off by setting --- the requireDevIfEnabled option to false. --- Optionally mw.loaddata can be used instead of require by passing the loadData option. ---@param name string ---@param options {requireDevIfEnabled: boolean?, loadData: boolean?}? ---@return unknown function Lua.import(name, options) options = options or {} local importFunction = options.loadData and mw.loadData or require if options.requireDevIfEnabled ~= false then if StringUtils.endsWith(name, '/dev') then error('Lua.import: Module name should not end in \'/dev\'') end local devName = name .. '/dev' local devEnabled = require('Module:FeatureFlag').get('dev') if devEnabled and require('Module:Namespace').isMain() then mw.ext.TeamLiquidIntegration.add_category('Pages using dev modules') end if devEnabled and Lua.moduleExists(devName) then return importFunction(devName) else return importFunction(name) end else return importFunction(name) end end --[[ This function intended to be #invoke'd from wikicode. Invokes a function inside a module or a dev module depending on the dev feature flag. Can also set the dev feature flag inside the function scope by passing dev=1. The following 3 code snippets are equivalent, assuming that Module:Magpie/dev exists and that feature_dev is unset previously. {{#invoke:Lua|invoke|module=Magpie|fn=theive|foo=3|dev=1}} {{#vardefine:feature_dev|1}} {{#invoke:Magpie/dev|theive|foo=3}} {{#vardefine:feature_dev|}} require('Module:FeatureFlag').set('dev', true) require('Module:Magpie/dev').theive({args = {foo = 3}}) require('Module:FeatureFlag').set('dev', nil) ]] ---@param frame Frame ---@return unknown function Lua.invoke(frame) local moduleName = frame.args.module local fnName = frame.args.fn assert(moduleName, 'Lua.invoke: args.module is missing') assert(fnName, 'Lua.invoke: args.fn is missing') assert( not StringUtils.endsWith(moduleName, '/dev'), 'Lua.invoke: Module name should not end in \'/dev\'' ) assert( not StringUtils.startsWith(moduleName, 'Module:'), 'Lua.invoke: Module name should not begin with \'Module:\'' ) frame.args.module = nil frame.args.fn = nil local devEnabled = function(startFrame) local currentFrame = startFrame while currentFrame do if Logic.readBoolOrNil(currentFrame.args.dev) ~= nil then return Logic.readBool(currentFrame.args.dev) end currentFrame = currentFrame:getParent() end end local flags = {dev = devEnabled(frame)} return require('Module:FeatureFlag').with(flags, function() local module = Lua.import('Module:' .. moduleName) return module[fnName](frame) end) end --[[ Incorporates Lua.invoke functionality into an entry point. The resulting entry point can be #invoked directly, without needing Lua.invoke. Usage: function JayModule.TemplateJay(frame) ... end JayModule.TemplateJay = Lua.wrapAutoInvoke(JayModule, 'Module:JayModule', 'TemplateJay') ]] ---@param module table ---@param baseModuleName string ---@param fnName string ---@return fun(frame: Frame|table): unknown function Lua.wrapAutoInvoke(module, baseModuleName, fnName) assert( not StringUtils.endsWith(baseModuleName, '/dev'), 'Lua.wrapAutoInvoke: Module name should not end in \'/dev\'' ) assert( StringUtils.startsWith(baseModuleName, 'Module:'), 'Lua.wrapAutoInvoke: Module name must begin with \'Module:\'' ) local moduleFn = module[fnName] return function(frame) local dev if type(frame.args) == 'table' then dev = frame.args.dev else dev = frame.dev end local flags = {dev = Logic.readBoolOrNil(dev)} return require('Module:FeatureFlag').with(flags, function() local variantModule = Lua.import(baseModuleName) local fn = module == variantModule and moduleFn or variantModule[fnName] return fn(frame) end) end end --[[ Incorporates Lua.invoke functionality into entry points of a module. The entry points can then be invoked directly, without needing Lua.invoke. This is intended for widely #invoked entry points where it is difficult to migrate existing wikicode calls to Lua.invoke. Avoid applying on entry points #invoked by a single template. Functions whose names begin with 'Template' are assumed to be the entry points. Specify fnNames to override this. Usage: local Jay = {} function Jay.TemplateJay(frame) ... end Lua.autoInvokeEntryPoints(JayModule, 'Module:JayModule') ]] ---@param module table ---@param baseModuleName string ---@param fnNames string[]? function Lua.autoInvokeEntryPoints(module, baseModuleName, fnNames) fnNames = fnNames or Lua.getDefaultEntryPoints(module) for _, fnName in ipairs(fnNames) do module[fnName] = Lua.wrapAutoInvoke(module, baseModuleName, fnName) end end --[[ Returns the functions whose names begin with 'Template'. Functions that start with 'Template' are presumably entry points. ]] ---@param module table ---@return string[] function Lua.getDefaultEntryPoints(module) local fnNames = {} for fnName, fn in pairs(module) do if type(fn) == 'function' and StringUtils.startsWith(fnName, 'Template') then table.insert(fnNames, fnName) end end return fnNames end return Lua