Documentation for this module may be created at Module:Transclude/doc

-- <nowiki>
--------------------------------------------------------------------------------
-- Module that allows transcluding a template with all parent arguments.
-- Useful in `/i18n` template subpages that delegate to a `/layout` subpage.
--
-- @module transclude
-- @author [[User:ExE Boss]]
-- @require [[Module:No globals]]
--------------------------------------------------------------------------------

require('strict')
local checkType = require('libraryUtil').checkType;

local p = {}
local INVALID_TITLES = {
	["."]	= true,
	[".."]	= true,
};

local function _ne(value)
	return value and value ~= ''
end

--------------------------------------------------------------------------------
-- Helper function that merges argument tables.
--
-- @function mergeArgs
-- @param {table} inArgs
-- @param {table} outArgs
--------------------------------------------------------------------------------
local function mergeArgs(inArgs, outArgs, opts)
	checkType("mergeArgs", 1, inArgs, "table");
	checkType("mergeArgs", 2, outArgs, "table");
	checkType("mergeArgs", 3, opts, "table", true);
	opts = opts or {}

	local ignoredParams = opts.ignoredParams;
	local ignoredPrefix = opts.ignoredPrefix;

	for name, value in pairs(inArgs) do
		if (type(name) == "string") then
			if not (
				(ignoredParams and ignoredParams[name] == true)
				or (ignoredPrefix and
					ignoredPrefix == name:sub(1, ignoredPrefix:len()))
			) then
				outArgs[name] = value;
			end
		else
			outArgs[name] = value;
		end
	end

	return outArgs;
end

-- Exported for testing:
p['#mergeArgs'] = mergeArgs;

local mt = {};

function mt.__index(_, name)
	if (
		type(name) ~= "string"
		or INVALID_TITLES[name]
		or mw.ustring.find(name, "#", nil, true)
	) then
		return nil;
	end

	local title = mw.title.new(name, "Template")
	if (not title) then
		return nil;
	end

	return function (frame)
		checkType('transclude["' .. name .. '"]', 1, frame, "table");
		local parentFrame = frame:getParent();

		local ignoredParams, ignoredPrefix;
		if _ne(frame.args["#ignoredParams"]) then
			ignoredParams = {};
            for m in mw.text.gsplit(frame.args["#ignoredParams"], '|', true) do
                ignoredParams[mw.text.trim(m)] = true;
            end
		end

		if _ne(frame.args['#ignoredPrefix']) then
			ignoredPrefix = frame.args['#ignoredPrefix'];
		end

		local args = {};
		if (parentFrame) then
			mergeArgs(parentFrame.args, args, {
				ignoredParams = ignoredParams,
				ignoredPrefix = ignoredPrefix,
			});
		end
		mergeArgs(frame.args, args, {
			ignoredPrefix = "#",
		});

		if (not title.exists) then
			return "[[:" .. title.fullText .. "]]";
		end

		return frame:expandTemplate{
			title = title,
			args = args,
		};
	end
end

return setmetatable(p, mt);