Module:Engineers: Difference between revisions

Current answers. Practical procedures. Reliable reference.
Jump to navigation Jump to search
Clean Engineer infobox output: grouped sections, concise labels, and JSON image support
Allow Engineer infobox fields to be edited on article pages
Line 88: Line 88:
end
end
end
end
-- Infobox pages may override the structured data directly in the article
-- template call. This keeps the sidebar editable from page edit/source
-- while still letting JSON records provide defaults and power comparison
-- tables. Empty parameters do not erase structured defaults.
for _, f in ipairs(FIELD_ORDER) do
if pargs[f.key] ~= nil and pargs[f.key] ~= '' then
fields[f.key] = pargs[f.key]
end
end
return fields
return fields
end
end

Revision as of 03:42, 13 August 2026

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

-- Module:Engineers
-- Reads canonical Engineer facts from Module:Data/Engineers/<Name> (JSON
-- content-model pages) and formats them for three consumers: an Engineer's
-- own infobox (via Template:Engineer infobox), List of Engineers, and
-- Engineer Capability Comparison. One record, one module, three consumers
-- -- see Elite Dangerous Field Manual:Adding Structured Data.
--
-- Adding a new engineer: create Module:Data/Engineers/<Name> in the same
-- shape as the existing four, then append the name to
-- Module:Data/Engineers/index. Don't edit this module unless you're
-- changing the schema itself.

local p = {}

-- Field order/labels shared by both the JSON-backed path and the manual
-- fallback path, so {{Engineer infobox|system=...|facility=...}} produces
-- the same shape of infobox whether or not a JSON record exists yet.
local FIELD_ORDER = {
	{ key = 'engineer_type', label = 'Engineer type', group = 'ENGINEER' },
	{ key = 'system', label = 'System' },
	{ key = 'body', label = 'Body' },
	{ key = 'facility', label = 'Facility' },
	{ key = 'region', label = 'Region' },
	{ key = 'allegiance', label = 'Allegiance' },
	{ key = 'specialties', label = 'Specialties' },
	{ key = 'max_grade', label = 'Maximum grade' },
	{ key = 'prerequisite_engineer', label = 'Prerequisite', group = 'ACCESS' },
	{ key = 'discovery_requirement', label = 'Discovery' },
	{ key = 'invitation_requirement', label = 'Invitation' },
	{ key = 'unlock_requirement', label = 'Unlock' },
}

local function loadRecord(name)
	local title = mw.title.new('Data/Engineers/' .. name, 'Module')
	if not title then
		return nil
	end
	local content = title:getContent()
	if not content then
		return nil
	end
	local ok, data = pcall(mw.text.jsonDecode, content)
	if not ok then
		return nil
	end
	return data
end

local function loadIndex()
	local title = mw.title.new('Data/Engineers/index', 'Module')
	local content = title and title:getContent()
	if not content then
		return {}
	end
	local ok, data = pcall(mw.text.jsonDecode, content)
	if not ok then
		return {}
	end
	return data
end

local function joinSpecialties(d)
	if d.specialties and type(d.specialties) == 'table' then
		return table.concat(d.specialties, ', ')
	end
	return d.specialties
end

-- Builds a plain { key = displayValue } table from either a JSON record
-- or manually-supplied template args, using the same FIELD_ORDER either
-- way.
local function buildFields(d, pargs)
	local fields = {}
	if d then
		for _, f in ipairs(FIELD_ORDER) do
			fields[f.key] = d[f.key]
		end
		fields.specialties = joinSpecialties(d)
		if d.prerequisite_engineer then
			local note = d.prerequisite_engineer_note and (' ' .. d.prerequisite_engineer_note) or ''
			fields.prerequisite_engineer = '[[' .. d.prerequisite_engineer .. ']]' .. note
		else
			fields.prerequisite_engineer = d.prerequisite_engineer_display or 'None — available from the start'
		end
	else
		for _, f in ipairs(FIELD_ORDER) do
			fields[f.key] = pargs[f.key]
		end
	end

	-- Infobox pages may override the structured data directly in the article
	-- template call. This keeps the sidebar editable from page edit/source
	-- while still letting JSON records provide defaults and power comparison
	-- tables. Empty parameters do not erase structured defaults.
	for _, f in ipairs(FIELD_ORDER) do
		if pargs[f.key] ~= nil and pargs[f.key] ~= '' then
			fields[f.key] = pargs[f.key]
		end
	end

	return fields
end

-- {{#invoke:Engineers|infobox}}, called from Template:Engineer infobox.
-- Falls back to whatever manual named params were passed if no JSON
-- record exists yet, so the wrapper template is safe to adopt one page at
-- a time rather than needing every engineer's data backfilled first.
function p.infobox(frame)
	local parent = frame:getParent()
	local pargs = parent and parent.args or {}
	local name = pargs.name or mw.title.getCurrentTitle().text
	local d = loadRecord(name)
	local fields = buildFields(d, pargs)

	local image = pargs.image
	if ( image == nil or image == '' ) and d and d.image then
		image = d.image
	end

	local args = { name = name, image = image }
	local n = 0
	for _, f in ipairs(FIELD_ORDER) do
		local value = fields[f.key]
		if value ~= nil and value ~= '' then
			n = n + 1
			if f.group then
				args['group' .. n] = f.group
			end
			args['label' .. n] = f.label
			args['row' .. n] = value
		end
	end

	return frame:expandTemplate{ title = 'Infobox', args = args }
end

-- {{#invoke:Engineers|list}}, used by List of Engineers.
function p.list()
	local rows = {}
	for _, name in ipairs(loadIndex()) do
		local d = loadRecord(name)
		if d then
			table.insert(rows, string.format(
				'|-\n| [[%s]] || %s || %s || %s',
				d.name,
				d.system or '—',
				joinSpecialties(d) or '—',
				d.max_grade or 'Not yet confirmed'
			))
		end
	end
	return '{| class="wikitable sortable"\n! Engineer !! System !! Specialties !! Maximum grade\n'
		.. table.concat(rows, '\n') .. '\n|}'
end

-- {{#invoke:Engineers|comparison}}, used by Engineer Capability Comparison.
function p.comparison()
	local rows = {}
	for _, name in ipairs(loadIndex()) do
		local d = loadRecord(name)
		if d then
			local prereq = d.prerequisite_engineer and ('[[' .. d.prerequisite_engineer .. ']]') or ( d.prerequisite_engineer_display or 'None' )
			table.insert(rows, string.format(
				'|-\n| [[%s]] || %s || %s || %s',
				d.name,
				joinSpecialties(d) or '—',
				prereq,
				d.unlock_requirement or 'Not yet confirmed'
			))
		end
	end
	return '{| class="wikitable sortable"\n! Engineer !! Specialties !! Prerequisite Engineer !! Unlock requirement\n'
		.. table.concat(rows, '\n') .. '\n|}'
end

return p