Jump to content

Module:Sandbox/BrandonXLF/Module:Map params

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by BrandonXLF (talk | contribs) at 07:18, 5 September 2024 (Not used). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

local p = {}
local yesno = require('Module:Yesno')

-- Escape a string to add to a Lua pattern
local function escPattern(s)
	return s:gsub('([%(%)%%%.%[%]%*%+%-%?%^%$])', '%%%1')
end

-- Get the value of a prefixed argument
function getPrefixedArg(args, prefix, num, optNum)
	return args[prefix .. num] or ((num == 1 and optNum and args[prefix]) or nil)
end

-- Get the prefixed parameters to process
local function getPrefixes(args)
	local prefixes = {}
    local i = 1
    local cur = getPrefixedArg(args, 'prefix', i, true)

    repeat
    	table.insert(prefixes, cur or '')
    	i = i + 1
    	cur = getPrefixedArg(args, 'prefix', i, true)
    until not cur
    
    return prefixes
end

-- Get the extra parameters to process
local function getExtras(args)
	local extras = {}
    local i = 1
    local cur = getPrefixedArg(args, 'extra', i, true)

    while cur do
    	local numMatch = cur:match('^(.+)%(i%)$')
    	
    	if numMatch then
    		table.insert(extras, {numMatch, true})
    	else
    		table.insert(extras, {cur, false})
    	end
    	
    	i = i + 1
    	cur = getPrefixedArg(args, 'extra', i, true)
    end
    
    return extras
end

-- Perform wikitext parameter substitution
function substParams(code, num, args)
	args['i'] = num
	local processed = code:gsub("{{{([^{}|]*)|?[^{}]*}}}", args) -- Substitute parameters
	return processed
end

-- Return the function that processes each iteration
function makeProcessor(frame)
	local template = frame.args.call
	
	if template then
		return function(num, args)
			args['i'] = num
			
			return frame:expandTemplate{
				title = template,
				args = args
			}
		end
	end
	
	-- Note: The difference between angle brackets and their entities is lost
	local code = mw.text.unstripNoWiki(frame.args[1]):gsub('&lt;', '<'):gsub('&gt;', '>')
	local expand = yesno(frame.args.expand or true)
	
	if expand then
		return function(num, args)
			return frame:preprocess(substParams(code, num, args))
		end
	end

	return function(num, args)
		return substParams(code, num, args)
	end
end

function numPairs(args, parentArgs, prefixes, optNum)
	local start = tonumber(args.start or 1)
	
	if yesno(args.sparse or false) then
		local nums = {}
		local seenNums = {} 

	    for k, _ in pairs(parentArgs) do
	    	local prefixMatch = false
	    	local j = 1

			-- Check every prefix for a match
	    	while prefixes[j] and not prefixMatch do
	    		local numStr = tostring(k):match('^' .. escPattern(prefixes[j]) .. '(%d*)$')

	    		if numStr ~= nil then
	    			local num = tonumber(numStr) or (optNum and 1 or nil)

	    			if num ~= nil and num >= start and not seenNums[num] then
	    				table.insert(nums, num)
	    				seenNums[num] = true
	    			end

	    			prefixMatch = true
	    		end

	    		j = j + 1
	    	end
	    end
	
	    table.sort(nums)
	    
	    -- Iterate over each found number
	    function sequenceIter(a, i)
			i = i + 1
			
			local v = a[i]
			
			if v then
				return i, v
			end
	    end
	    
	    return sequenceIter, nums, 0
	end
	
	-- Iterate each number and check for any matches
	local function prefixIter(a, i)
		i = i + 1
		
    	local j = 1
    	local prefixMatch = false
    	
    	-- Check every prefix for a match
    	while prefixes[j] and not prefixMatch do
    		prefixMatch = getPrefixedArg(a, prefixes[j], i, optNum) ~= nil
    		j = j + 1
    	end
    	
    	if prefixMatch then
    		return i, i
    	end
	end
	
	return prefixIter, parentArgs, start - 1
end

function p.map(frame)
	local result = {}
	local parent = frame:getParent()
	
	local sep = frame.args.sep or ''
	local conj = frame.args.conj or sep
	local prefixes = getPrefixes(frame.args)
	local extras = getExtras(frame.args)
	local process = makeProcessor(frame)
	local optNum = yesno(frame.args.optnum or true)
	
	for _, num in numPairs(frame.args, parent.args, prefixes, optNum) do
		local args = {}
		
		-- Pass extra registered arguments
		for _, extraInfo in ipairs(extras) do
			local extra, numbered = unpack(extraInfo)
			
			if numbered then
				args[extra] = getPrefixedArg(parent.args, extra, num, optNum)
			else
				args[extra] = parent.args[extra]
			end
		end
		
		-- Pass current parameters without their numeric suffix
		for _, prefix in ipairs(prefixes) do
			args[prefix ~= '' and prefix or '@'] = getPrefixedArg(parent.args, prefix, num, optNum)
		end
		
		table.insert(result, process(num, args))
	end
	
	return mw.text.listToText(result, sep, conj)
end

return p