ARBEIT MACHT FREI
Moduł:DesignAssignmentsAPI
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