ARBEIT MACHT FREI

Moduł:DesignAssignmentsAPI

Z 4 Strona Wiki
Wersja z dnia 10:04, 24 lip 2026 autorstwa Fuhrer (dyskusja | edycje) (1 wersja)
(różn.) ← poprzednia wersja | przejdź do aktualnej wersji (różn.) | następna wersja → (różn.)
Przejdź do nawigacji Przejdź do wyszukiwania

Dokumentacja dla tego modułu może zostać utworzona pod nazwą Moduł:DesignAssignmentsAPI/opis

-- Module:DesignAssignmentsAPI
local p = {}

local function trim(value)
	if not value then return "" end
	return mw.text.trim(value)
end

local function normalizeWhitespace(value)
	return trim((value or ""):gsub("%s+", " "))
end

local function renderWikitext(value)
	if not value or value == "" then
		return ""
	end

	local rendered = tostring(value)
	rendered = rendered:gsub("%[%[([^%]|]+)|([^%]]+)%]%]", "%2")
	rendered = rendered:gsub("%[%[([^%]]+)%]%]", "%1")
	rendered = rendered:gsub("%[https?://[^%s%]]+%s+([^%]]+)%]", "%1")
	rendered = rendered:gsub("%[https?://[^%]]+%]", "")
	rendered = rendered:gsub("'''''", "")
	rendered = rendered:gsub("'''", "")
	rendered = rendered:gsub("''", "")
	rendered = rendered:gsub("{{%s*[^|}]+%s*|%s*([^}]+)%s*}}", "%1")
	rendered = rendered:gsub("{{[^}]+}}", "")
	rendered = rendered:gsub("<%s*[Bb][Rr]%s*/?>", " ")
	rendered = rendered:gsub("<[^>]+>", "")
	rendered = mw.text.decode(rendered)
	return normalizeWhitespace(rendered)
end

local function splitNames(value)
	local cleaned = value or ""
	cleaned = cleaned:gsub("%b()", " ")
	cleaned = cleaned:gsub("[Bb][Aa][Cc][Kk][Ff][Ii][Ll][Ll][Ee][Dd]%s+[Bb][Yy]", " ")
	cleaned = cleaned:gsub("%s+[Aa][Nn][Dd]%s+", "|")
	cleaned = cleaned:gsub("%s+[Ww][Ii][Tt][Hh]%s+", "|")
	cleaned = cleaned:gsub("%s*/%s*", "|")
	cleaned = cleaned:gsub("%s*&%s*", "|")
	cleaned = cleaned:gsub("%s*;%s*", "|")
	cleaned = cleaned:gsub("%s*%+%s*", "|")
	cleaned = cleaned:gsub("%s*,%s*", "|")

	local parts = mw.text.split(cleaned, "|", true)
	local names = {}
	local seen = {}
	for _, part in ipairs(parts) do
		local name = normalizeWhitespace(part)
		if name ~= "" and not seen[name] then
			seen[name] = true
			table.insert(names, name)
		end
	end
	return names
end

local function extractDesignerNames(cellText)
	local names = {}
	local seen = {}

	for link in cellText:gmatch("%[%[([^%]]-)%]%]") do
		local target, display = link:match("^(.-)|(.+)$")
		local value = display or target
		local name = normalizeWhitespace(renderWikitext(value))
		if name ~= "" and not seen[name] then
			seen[name] = true
			table.insert(names, name)
		end
	end

	if #names > 0 then
		return names
	end

	local rawText = normalizeWhitespace(renderWikitext(cellText))
	if rawText == "" then
		return {}
	end

	return splitNames(rawText)
end

local function extractManagerNames(cellText)
	local source = nil
	for line in cellText:gmatch("[^\n]+") do
		local lower = line:lower()
		if lower:find("area managed") or lower:find("managed by") then
			source = line
		end
	end
	source = source or cellText
	local cleaned = normalizeWhitespace(renderWikitext(source))
	cleaned = cleaned:gsub("^area%s+managed%s+by%s*", "")
	cleaned = cleaned:gsub("^managed%s+by%s*", "")
	cleaned = cleaned:gsub("area%s+managed%s+by%s*", "")
	cleaned = cleaned:gsub("%s+area%s+manager.*$", "")
	cleaned = cleaned:gsub("backfilled by.*$", "")
	cleaned = normalizeWhitespace(cleaned)
	if cleaned == "" then
		return nil
	end
	local names = splitNames(cleaned)
	if #names == 0 then
		return nil
	end
	return table.concat(names, ", ")
end

local function extractTeamName(cellText)
	local bold = cellText:match("'''(.-)'''")
	if bold then
		return normalizeWhitespace(renderWikitext(bold))
	end
	return normalizeWhitespace(renderWikitext(cellText))
end

local function splitLineCells(line)
	local isHeader = line:match("^%s*!") ~= nil
	local delimiter = isHeader and "!!" or "||"
	local rawParts = mw.text.split(line, delimiter, true)
	local cells = {}

	for _, part in ipairs(rawParts) do
		local content = part:gsub("^%s*[!|]%s*", "")
		local attr, value = content:match("^%s*([^|]+)%|%s*(.-)%s*$")
		if attr and attr:match("=") then
			content = value
		end
		content = trim(content)
		table.insert(cells, content)
	end

	return cells
end

local function parseTable(lines, startIdx)
	local rows = {}
	local current = nil
	local inRow = false

	local function pushRow()
		if current and #current > 0 then
			table.insert(rows, current)
		end
	end

	for i = startIdx, #lines do
		local line = lines[i]
		if line:match("^%s*|}") then
			pushRow()
			break
		elseif line:match("^%s*|%-") then
			pushRow()
			current = {}
			inRow = true
		elseif line:match("^%s*|%+") then
			-- caption; ignore
		elseif not inRow then
			-- header or pre-row content; ignore
		elseif line:match("^%s*[!|]") then
			local cells = splitLineCells(line)
			for _, cell in ipairs(cells) do
				table.insert(current, cell)
			end
		else
			if current and #current > 0 then
				current[#current] = current[#current] .. "\n" .. line
			end
		end
	end

	return rows
end

local function findProductTeamsTable(lines)
	local productIndex = nil
	for i, line in ipairs(lines) do
		if line:lower():match("^===%s*product teams%s*===") then
			productIndex = i
			break
		end
	end

	if not productIndex then
		return nil
	end

	for i = productIndex, #lines do
		local line = lines[i]
		if line:match("^%s*{|") and line:match("wikitable") then
			return i
		end
	end

	return nil
end

local function addTeam(record, teamName)
	for _, existing in ipairs(record.teams) do
		if existing == teamName then
			return
		end
	end
	table.insert(record.teams, teamName)
end

function p.json()
	local title = mw.title.new("Design")
	if not title then
		return mw.text.jsonEncode({ error = "Page not found" })
	end

	local content = title:getContent()
	if not content then
		return mw.text.jsonEncode({ error = "No content" })
	end

	local lines = mw.text.split(content, "\n", true)
	local tableStart = findProductTeamsTable(lines)
	if not tableStart then
		return mw.text.jsonEncode({ error = "Product teams table not found" })
	end

	local rows = parseTable(lines, tableStart + 1)
	local designers = {}
	local areaManagers = {}

	local currentAreaName = nil
	local currentManager = nil

	for _, row in ipairs(rows) do
		local cellCount = #row
		if cellCount > 0 then
			local teamCell = row[1] or ""
			local managerCell = row[cellCount] or ""
			local designerCell = row[math.min(3, cellCount)] or ""

			local managerText = renderWikitext(managerCell):lower()
			if managerText:find("area managed") then
				local areaName = nil
				local boldArea = managerCell:match("'''(.-)'''")
				if boldArea then
					areaName = normalizeWhitespace(renderWikitext(boldArea))
				else
					local withoutItalics = managerCell:gsub("''.-''", "")
					areaName = normalizeWhitespace(renderWikitext(withoutItalics))
					areaName = areaName:gsub("area managed by.*$", "")
					areaName = normalizeWhitespace(areaName)
				end

				local managerNames = extractManagerNames(managerCell)
				if managerNames then
					local names = splitNames(managerNames)
					local primaryName = names[1]
					currentManager = primaryName
					currentAreaName = areaName ~= "" and areaName or primaryName
					if primaryName then
						areaManagers[mw.ustring.lower(primaryName)] = {
							name = primaryName,
							area = currentAreaName or ""
						}
					end
				end
			end

			local names = extractDesignerNames(designerCell)
			local teamName = extractTeamName(teamCell)

			for _, name in ipairs(names) do
				if name ~= "" then
					local key = mw.ustring.lower(name)
					local existing = designers[key]
					if existing then
						addTeam(existing, teamName)
						table.sort(existing.teams)
						if not existing.manager and currentManager then
							existing.manager = currentManager
						end
					else
						designers[key] = {
							name = name,
							teams = { teamName },
							manager = currentManager
						}
					end
				end
			end
		end
	end

	for key, info in pairs(areaManagers) do
		local existing = designers[key]
		local normalizedArea = (info.area ~= "" and info.area) or "Product & Technology"
		if existing then
			addTeam(existing, normalizedArea)
			table.sort(existing.teams)
			existing.manager = "Rita Ho"
		else
			designers[key] = {
				name = info.name,
				teams = { normalizedArea },
				manager = "Rita Ho"
			}
		end
	end

	local ritaKey = mw.ustring.lower("Rita Ho")
	local rita = designers[ritaKey]
	if rita then
		addTeam(rita, "Product & Technology")
		table.sort(rita.teams)
		rita.manager = "Selena Deckelmann"
	else
		designers[ritaKey] = {
			name = "Rita Ho",
			teams = { "Product & Technology" },
			manager = "Selena Deckelmann"
		}
	end

	local list = {}
	for _, record in pairs(designers) do
		table.sort(record.teams)
		table.insert(list, record)
	end
	table.sort(list, function(a, b) return a.name < b.name end)

	return mw.text.jsonEncode(list)
end

return p