Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:TagBuilder: Difference between revisions

From Teriock
Content deleted Content added
// via Wikitext Extension for VSCode
Tag: Reverted
// via Wikitext Extension for VSCode
Tag: Reverted
Line 80: Line 80:
if spec.link then tagText = tagText .. '|l=:Category:' .. ucfirst(spec.link) end
if spec.link then tagText = tagText .. '|l=:Category:' .. ucfirst(spec.link) end
if opts and opts.transparent == '1' then tagText = tagText .. '|o=1' end
if opts and opts.transparent == '1' then tagText = tagText .. '|o=1' end
tagText = tagText .. '|class=' .. scope .. '-tagged{{lc:' .. tagText ..'}}}}'
tagText = tagText .. '|class=' .. scope .. '-tagged {{lc:' .. tagText ..'}}}}'


-- Category tokens
-- Category tokens

Revision as of 07:34, 18 August 2025

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

-- Module:TagBuilder
local TagParser = require('Module:TagParser')

local B = {}

local function normalizeModuleName(name)
	if not name or name == '' then return 'Module:TagCreatures' end
	if mw.ustring.find(name, '^Module:') then return name end
	return 'Module:' .. name
end

local function ucfirst(s)
	return mw.getContentLanguage():ucfirst(s or '')
end

-- Decide if we should include categories, based on |name= and |ns=
local function shouldAddCategories(opts)
	local title = mw.title.getCurrentTitle()
	local page  = title.text or ''
	local nsNow = title.nsText or ''

	local okName = true
	if opts and opts.name and opts.name ~= '' then
		local want = mw.text.trim(opts.name)
		okName = (want == page) or (want == "''" .. page .. "''")
	end

	local okNs = true
	if opts and opts.ns and opts.ns ~= '' then
		okNs = (mw.text.trim(opts.ns) == nsNow)
	end

	return okName and okNs
end

-- Find a tag spec by key, either under a specific scope or across all top-level tables
local function findTagSpec(data, key, scope)
	if scope then
		local tbl = data[scope]
		if type(tbl) == 'table' then return tbl[key] end
		return nil
	end
	for k, v in pairs(data) do
		if type(v) == 'table' and v[key] then
			return v[key], k
		end
	end
	return nil
end

-- Recursively expand a key into tag wikitext and categories.
local function expandKey(key, data, scope, opts, seen)
	seen = seen or {}
	if seen[key] then return '', {} end
	seen[key] = true

	local spec = findTagSpec(data, key, scope)

	-- Unknown key → "Key."
	if not spec then
		local txt = ucfirst(key)
		if txt ~= '' and txt:sub(-1) ~= '.' then txt = txt .. '.' end
		return txt, {}
	end

	-- Composite tag?
	if spec.tags then
		local out, cats = {}, {}
		for _, sub in ipairs(spec.tags) do
			local t, c = expandKey(sub, data, scope, opts, seen)
			table.insert(out, t)
			for _, cc in ipairs(c) do table.insert(cats, cc) end
		end
		return table.concat(out), cats
	end

	-- Build {{Tag|...}}
	local tagText = string.format('{{Tag|%s', ucfirst(spec.text))
	if spec.symbol then tagText = tagText .. '|' .. spec.symbol end
	if spec.link   then tagText = tagText .. '|l=:Category:' .. ucfirst(spec.link) end
	if opts and opts.transparent == '1' then tagText = tagText .. '|o=1' end
	tagText = tagText .. '|class=' .. scope .. '-tagged {{lc:' .. tagText ..'}}}}'

	-- Category tokens
	local cats = {}
	if spec.link then
		table.insert(cats, '[[Category:' .. ucfirst(spec.link) .. ']]')
	end

	return tagText, cats
end

-- Core builder: keys (array of strings) → concatenated tags, concatenated categories (conditionally)
function B.buildFromKeys(keys, dataModuleName, scope, opts)
	local moduleName = normalizeModuleName(dataModuleName)
	local data = mw.loadData(moduleName)

	local out, cats, seen = {}, {}, {}
	for _, key in ipairs(keys or {}) do
		local t, c = expandKey(key, data, scope, opts, seen)
		if t and t ~= '' then table.insert(out, t) end
		for _, cc in ipairs(c) do table.insert(cats, cc) end
	end

	-- Apply the |name= / |ns= gate for categories
	if not shouldAddCategories(opts) then
		cats = {}
	end

	return table.concat(out), table.concat(cats)
end

-- Convenience: raw ";;" string → tags, cats
function B.build(raw, dataModuleName, scope, opts)
	local keys = TagParser.parseList(raw)
	return B.buildFromKeys(keys, dataModuleName, scope, opts)
end

---------------------------
-- #invoke entrypoints
---------------------------
local p = {}

-- {{#invoke:TagBuilder|tags|t=undead;; skeletal;;|data=TagCreatures|scope=traits|o=1}}
function p.tags(frame)
	local args = frame.args or {}
	local t      = args.t or args[1] or ''
	local data   = args.data or 'TagCreatures'
	local scope  = args.scope -- optional (e.g., "traits")
	local opts   = {
		transparent = args.o or args.transparent,
		name = args.name,
		ns   = args.ns,
	}
	local tags = B.build(t, data, scope, opts)
	return frame:preprocess(tags or '')
end

-- {{#invoke:TagBuilder|categories|t=...|data=TagCreatures|scope=traits|name=Page Name|ns=Creature}}
function p.categories(frame)
	local args = frame.args or {}
	local t      = args.t or args[1] or ''
	local data   = args.data or 'TagCreatures'
	local scope  = args.scope
	local opts   = {
		name = args.name,
		ns   = args.ns,
	}
	local _, cats = B.build(t, data, scope, opts)
	return cats or ''
end

-- For other modules: require('Module:TagBuilder').build(...)
return setmetatable(p, { __index = B })