From bad9ae918c6198c5b75377e97feebb5db2af4c1c Mon Sep 17 00:00:00 2001 From: mbergen Date: Fri, 28 Feb 2025 18:06:22 +0100 Subject: [PATCH 01/50] WIP: Add first draft of SquadAuto rewrite --- lua/wikis/commons/Squad/squad_auto.lua | 356 +++++++++++++++++++++++++ 1 file changed, 356 insertions(+) create mode 100644 lua/wikis/commons/Squad/squad_auto.lua diff --git a/lua/wikis/commons/Squad/squad_auto.lua b/lua/wikis/commons/Squad/squad_auto.lua new file mode 100644 index 00000000000..e967c29faa3 --- /dev/null +++ b/lua/wikis/commons/Squad/squad_auto.lua @@ -0,0 +1,356 @@ +--- +-- @Liquipedia +-- wiki=commons +-- page=Module:Squad/Auto +-- +-- Please see https://github.com/Liquipedia/Lua-Modules to contribute +-- + +local Array = require('Module:Array') +local Class = require('Module:Class') +local Condition = require('Module:Condition') +local FnUtil = require('Module:FnUtil') +local Json = require('Module:Json') +local Logic = require('Module:Logic') +local Lpdb = require('Module:Lpdb') +local Table = require('Module:Table') +local Operator = require('Module:Operator') + +local SquadUtils = require('Module:Squad/Utils') +local SquadCustom = require('Module:Squad/Custom') + +local BooleanOperator = Condition.BooleanOperator +local Comparator = Condition.Comparator + +---@class SquadAuto +---@field args table +---@field config SquadAutoConfig +---@field manualPlayers table? +---@field manualTimeline table? +---@field playersTeamHistory table +local SquadAuto = Class.new(nil, function (self, args) + self.args = arg +end) + +---@class SquadAutoTeam +---@field team string +---@field role string? +---@field position string? +---@field date string? + +---TODO: Unify with SquadPerson +---@class SquadAutoPerson +---@field id string +---@field flag string? +---@field idleavedate string? +---@field page string +---@field thisTeam SquadAutoTeam +---@field oldTeam SquadAutoTeam? +---@field newTeam SquadAutoTeam? +---@field joindate string +---@field joindatedisplay string? +---@field joindateRef table? +---@field leavedate string? +---@field leavedatedisplay string? +---@field leavedateRef table? +---@field faction string? + +---@class SquadAutoConfig +---@field team string +---@field status SquadStatus +---@field type SquadType +---@field title string? +---@field teams string[]? + +---@enum TransferType +SquadAuto.TransferType = { + LEAVE = 'LEAVE', + JOIN = 'JOIN', + CHANGE = 'CHANGE', +} + +---@class TeamHistoryEntry +---@field pagename string +---@field displayname string +---@field flag string +---@field date string +---@field dateDisplay string +---@field type TransferType +---@field references table +---@field wholeTeam boolean +---@field position string + +---Entrypoint for the automated timelin +---TODO: Implement in submodule +function SquadAuto.timeline(args) + args.timeline = true + self:parseConfig(args) +end + +---Entrypoint for SquadAuto tables +---@param args table +function SquadAuto.run(args) + local autosquad = SquadAuto(args) + autosquad:parseConfig(args) + autosquad:queryTransfers() + + mw.logObject(autosquad:selectEntries()) + --return SquadCustom.runAuto(self:filterEntries(), self.config.status, self.config.type, self.config.title) +end + +---Parses the args into a SquadAutoConfig +---@param args table +function SquadAuto:parseConfig(args) + self.config = { + team = args.team or mw.title.getCurrentTitle().text, + status = SquadUtils.StatusToSquadStatus[args.status:lower()], + type = SquadUtils.TypeToSquadType[args.type:lower()], + title = args.title -- TODO: Switch to Former players instead of squad? + } + if args.timeline then + self.manualTimeline = self:readManualTimeline() + else + self.manualPlayers = self:readManualPlayers() + end + + local historicalTemplates = mw.ext.TeamTemplate.raw_historical(self.config.team) + if not historicalTemplates then + error("Missing team template: " .. self.config.team) + end + self.config.teams = Array.append(Array.extractValues(historicalTemplates), self.config.team) + + if self.config.status == SquadUtils.SquadStatus.FORMER_INACTIVE then + error("SquadStatus 'FORMER_INACTIVE' is not supported by SquadAuto.") + end +end + +function SquadAuto:readManualPlayers() +end + +function SquadAuto:readManualTimeline() +end + +function SquadAuto:queryTransfers() + ---Checks whether a given team is the currently queried team + ---@param team string? + ---@return boolean + local function isCurrentTeam(team) + if not team then + return false + end + return Array.find(self.config.teams, function(t) return t == team end) ~= nil + end + + ---@param side 'from' | 'to' + ---@param transfer transfer + ---@return string | nil, boolean + local function parseRelevantTeam(side, transfer) + local mainTeam = transfer[side .. 'teamtemplate'] + if mainTeam and isCurrentTeam(mainTeam) then + return mainTeam, true + end + + local secondaryTeam = transfer.extradata[side .. 'teamsectemplate'] + if secondaryTeam and isCurrentTeam(secondaryTeam) then + return secondaryTeam, false + end + + return nil, false + end + + ---Maps a transfer to a transfertype, with regards to the current team. + ---@param relevantFromTeam string? + ---@param relevantToTeam string? + ---@return TransferType + local function getTransferType(relevantFromTeam, relevantToTeam) + if relevantFromTeam then + if relevantToTeam then + return SquadAuto.TransferType.CHANGE + end + return SquadAuto.TransferType.LEAVE + end + return SquadAuto.TransferType.JOIN + end + + ---Parses the relevant role for the current team from a transfer + ---@param side 'from' | 'to' + ---@param transfer transfer + ---@param team string? + ---@param isMain boolean + ---@return string? + local function parseRelevantRole(side, transfer, team, isMain) + if not team then + return nil + end + + if isMain then + return side == 'from' and transfer.role1 or transfer.role2 + else + return side == 'from' and transfer.extradata.role1sec or transfer.extradata.role2sec + end + end + + --TODO: Cache transfers/teamhistory in pagevars + ---@type table + self.playersTeamHistory = {} + + Lpdb.executeMassQuery( + 'transfer', + { + conditions = self:buildConditions(), + order = 'date asc, objectname desc', + limit = 5000 + }, + function(record) + self.playersTeamHistory[record.player] = self.playersTeamHistory[record.player] or {} + record.extradata = record.extradata or {} + + + local relevantFromTeam, isFromMain = parseRelevantTeam('from', record) + local relevantToTeam, isToMain = parseRelevantTeam('to', record) + local transferType = getTransferType(relevantFromTeam, relevantToTeam) + + ---@type TeamHistoryEntry + local entry = { + type = transferType, + + -- Person related information + pagename = record.player, + displayname = record.extradata.displayname, + flag = record.nationality, + + -- Date and references + date = record.date, + dateDisplay = record.extradata.displaydate, + references = record.reference, + + -- Roles + fromRole = parseRelevantRole('from', record, relevantFromTeam, isFromMain), + toRole = parseRelevantRole('to', record, relevantToTeam, isToMain), + + -- Other + wholeTeam = Logic.readBool(record.wholeteam), + position = record.extradata.position, + } + + -- TODO: Skip this transfer if there is no relevant change + -- E.g. this is grabbed a secondary team, but only main team changed + table.insert(self.playersTeamHistory[record.player], entry) + end + ) + +end + +---Builds the conditions to fetch all transfers related +---to the given team, respecting historical templates. +---@return string +function SquadAuto:buildConditions() + local historicalTemplates = mw.ext.TeamTemplate.raw_historical(self.config.team) + + if not historicalTemplates then + error("Missing team template: " .. self.config.team) + end + + local conditions = Condition.Tree(BooleanOperator.any) + Array.forEach(Array.extendWith(Array.extractValues(historicalTemplates), self.config.team), function (templatename) + conditions:add{ + Condition.Node(Condition.ColumnName('fromteamtemplate'), Comparator.eq, templatename), + Condition.Node(Condition.ColumnName('extradata_fromteamsectemplate'), Comparator.eq, templatename), + Condition.Node(Condition.ColumnName('toteamtemplate'), Comparator.eq, templatename), + Condition.Node(Condition.ColumnName('extradata_toteamsectemplate'), Comparator.eq, templatename) + } + end) + + return conditions:toString() +end + +---comment +---@return table +function SquadAuto:selectEntries() + return Array.flatMap( + Array.extractValues(self.playersTeamHistory), + FnUtil.curry(self._selectHistoryEntries, self) + ) +end + +---Returns a function that maps a set of transfers to a list of +---SquadAutoPersons. +---Behavior depends on the current config: +---If the status is (in)active, then at most one entry will be returned +---If the status is former(_inactive), there might be multiple entries returned +---If the type does not match, no entries are returned +---@param entries TeamHistoryEntry[] +---@return SquadAutoPerson[] +function SquadAuto:_selectHistoryEntries(entries) + -- Select entries to match status + if self.config.status == SquadUtils.SquadStatus.ACTIVE + or self.config.status == SquadUtils.SquadStatus.INACTIVE then + -- Only most recent transfer is relevant + local last = entries[#entries] + if last.type == SquadAuto.TransferType.CHANGE + or last.type == SquadAuto.TransferType.JOIN then + -- When the last transfer is a leave transfer, the person wouldn't be (in)active + return {self:_mapToSquadAutoPerson(last)} + end + end + + if self.config.status == SquadUtils.SquadStatus.FORMER then + local history = {} + + local currentEntry = nil + for index, entry in ipairs(entries) do + if not currentEntry and entry.type ~= SquadAuto.TransferType.JOIN then + mw.log("Invalid transfer history for player " .. entry.pagename) + mw.logObject(entry, "Invalid entry: Missing previous JOIN") + end + end + + return history + end + + return {} +end + +---Maps one or a pair of TeamHistoryEntries to a single SquadAutoPerson +---@param joinEntry TeamHistoryEntry +---@param leaveEntry TeamHistoryEntry | nil +---@return SquadAutoPerson +function SquadAuto:_mapToSquadAutoPerson(joinEntry, leaveEntry) + leaveEntry = leaveEntry or {} + + ---@type SquadAutoPerson + local entry = { + page = joinEntry.pagename, + id = joinEntry.displayname, + flag = joinEntry.flag, + joindate = joinEntry.date, + joindatedisplay = joinEntry.dateDisplay, + joindateRef = joinEntry.references, + + idleavedate = joinEntry.dateDisplay, + leavedate = leaveEntry.date or nil, + leavedatedisplay = leaveEntry.dateDisplay, + leavedateRef = leaveEntry.references, + + thisTeam = { + --TODO + }, + oldTeam = { + --TODO + }, + newTeam = { + --TODO + }, + + faction = '' --TODO + } + + if leaveEntry and not entry.newTeam then + --TODO: Fetch next team for person + end + + return entry +end + + +return SquadAuto From c1f4fad73c8eb21f8562071ad719ae99a29fe427 Mon Sep 17 00:00:00 2001 From: mbergen Date: Fri, 28 Feb 2025 18:10:07 +0100 Subject: [PATCH 02/50] Add another TODO comment --- lua/wikis/commons/Squad/squad_auto.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lua/wikis/commons/Squad/squad_auto.lua b/lua/wikis/commons/Squad/squad_auto.lua index e967c29faa3..a697d04bac9 100644 --- a/lua/wikis/commons/Squad/squad_auto.lua +++ b/lua/wikis/commons/Squad/squad_auto.lua @@ -303,6 +303,10 @@ function SquadAuto:_selectHistoryEntries(entries) mw.log("Invalid transfer history for player " .. entry.pagename) mw.logObject(entry, "Invalid entry: Missing previous JOIN") end + + --TODO: add/merge entry with currentEntry + --Add currentEntry to history + --Reset currentEntry end return history From 00d286a7f9c35e6e2dbc87ad81532d350e00ba17 Mon Sep 17 00:00:00 2001 From: mbergen Date: Wed, 12 Mar 2025 15:03:39 +0100 Subject: [PATCH 03/50] Move file to new naming structure --- .../Squad/{squad_auto.lua => Auto.lua} | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) rename lua/wikis/commons/Squad/{squad_auto.lua => Auto.lua} (91%) diff --git a/lua/wikis/commons/Squad/squad_auto.lua b/lua/wikis/commons/Squad/Auto.lua similarity index 91% rename from lua/wikis/commons/Squad/squad_auto.lua rename to lua/wikis/commons/Squad/Auto.lua index a697d04bac9..93629cf0296 100644 --- a/lua/wikis/commons/Squad/squad_auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -6,6 +6,7 @@ -- Please see https://github.com/Liquipedia/Lua-Modules to contribute -- +local Arguments = require('Module:Arguments') local Array = require('Module:Array') local Class = require('Module:Class') local Condition = require('Module:Condition') @@ -28,8 +29,8 @@ local Comparator = Condition.Comparator ---@field manualPlayers table? ---@field manualTimeline table? ---@field playersTeamHistory table -local SquadAuto = Class.new(nil, function (self, args) - self.args = arg +local SquadAuto = Class.new(nil, function (self, frame) + self.args = Arguments.getArgs(frame) end) ---@class SquadAutoTeam @@ -44,6 +45,8 @@ end) ---@field flag string? ---@field idleavedate string? ---@field page string +---@field name string? +---@field localizedname string? ---@field thisTeam SquadAutoTeam ---@field oldTeam SquadAutoTeam? ---@field newTeam SquadAutoTeam? @@ -54,6 +57,7 @@ end) ---@field leavedatedisplay string? ---@field leavedateRef table? ---@field faction string? +---@field captain boolean? ---@class SquadAutoConfig ---@field team string @@ -82,29 +86,33 @@ SquadAuto.TransferType = { ---Entrypoint for the automated timelin ---TODO: Implement in submodule -function SquadAuto.timeline(args) - args.timeline = true - self:parseConfig(args) +function SquadAuto.timeline(frame) + -- return SquadAuto(frame):timeline() end ---Entrypoint for SquadAuto tables ----@param args table -function SquadAuto.run(args) - local autosquad = SquadAuto(args) - autosquad:parseConfig(args) +---@param frame table +function SquadAuto.run(frame) + local autosquad = SquadAuto(frame) + autosquad:parseConfig() autosquad:queryTransfers() - mw.logObject(autosquad:selectEntries()) - --return SquadCustom.runAuto(self:filterEntries(), self.config.status, self.config.type, self.config.title) + return autosquad:display() +end + +function SquadAuto:display() + local entries = self:selectEntries() + mw.logObject(entries) + return SquadCustom.runAuto(entries, self.config.status, self.config.type, self.config.title) end ---Parses the args into a SquadAutoConfig ----@param args table -function SquadAuto:parseConfig(args) +function SquadAuto:parseConfig() + local args = self.args self.config = { team = args.team or mw.title.getCurrentTitle().text, - status = SquadUtils.StatusToSquadStatus[args.status:lower()], - type = SquadUtils.TypeToSquadType[args.type:lower()], + status = SquadUtils.StatusToSquadStatus[(args.status or ''):lower()], + type = SquadUtils.TypeToSquadType[(args.type or ''):lower()], title = args.title -- TODO: Switch to Former players instead of squad? } if args.timeline then @@ -331,8 +339,8 @@ function SquadAuto:_mapToSquadAutoPerson(joinEntry, leaveEntry) joindatedisplay = joinEntry.dateDisplay, joindateRef = joinEntry.references, - idleavedate = joinEntry.dateDisplay, - leavedate = leaveEntry.date or nil, + idleavedate = leaveEntry.displayname, + leavedate = leaveEntry.date or '', leavedatedisplay = leaveEntry.dateDisplay, leavedateRef = leaveEntry.references, From ab979b51914690158fa49d9a1e44ba943475d64a Mon Sep 17 00:00:00 2001 From: mbergen Date: Sat, 22 Mar 2025 16:18:17 +0100 Subject: [PATCH 04/50] setting teams, adding annotations --- lua/wikis/commons/Squad/Auto.lua | 41 +++++++++++++++++++++++-------- lua/wikis/commons/Squad/Utils.lua | 29 +++++++++++++++++++--- 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 93629cf0296..5a0c06d3161 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -73,7 +73,7 @@ SquadAuto.TransferType = { CHANGE = 'CHANGE', } ----@class TeamHistoryEntry +---@class (exact) TeamHistoryEntry ---@field pagename string ---@field displayname string ---@field flag string @@ -83,6 +83,10 @@ SquadAuto.TransferType = { ---@field references table ---@field wholeTeam boolean ---@field position string +---@field fromTeam string? +---@field fromRole string? +---@field toTeam string? +---@field toRole string? ---Entrypoint for the automated timelin ---TODO: Implement in submodule @@ -236,6 +240,9 @@ function SquadAuto:queryTransfers() fromRole = parseRelevantRole('from', record, relevantFromTeam, isFromMain), toRole = parseRelevantRole('to', record, relevantToTeam, isToMain), + fromTeam = relevantFromTeam, + toTeam = relevantToTeam, + -- Other wholeTeam = Logic.readBool(record.wholeteam), position = record.extradata.position, @@ -306,16 +313,25 @@ function SquadAuto:_selectHistoryEntries(entries) local history = {} local currentEntry = nil - for index, entry in ipairs(entries) do - if not currentEntry and entry.type ~= SquadAuto.TransferType.JOIN then - mw.log("Invalid transfer history for player " .. entry.pagename) - mw.logObject(entry, "Invalid entry: Missing previous JOIN") + + Array.forEach(entries, function (entry) + if not currentEntry then + if entry.type == SquadAuto.TransferType.JOIN then + currentEntry = entry + else + mw.log("Invalid transfer history for player " .. entry.pagename) + mw.logObject(entry, "Invalid entry: Missing previous JOIN. Skipping") + end + return end - --TODO: add/merge entry with currentEntry - --Add currentEntry to history - --Reset currentEntry - end + table.insert(history, self:_mapToSquadAutoPerson(currentEntry, entry)) + if entry.type == "CHANGE" then + currentEntry = entry + else + currentEntry = nil + end + end) return history end @@ -346,12 +362,17 @@ function SquadAuto:_mapToSquadAutoPerson(joinEntry, leaveEntry) thisTeam = { --TODO + team = joinEntry.toTeam, + role = joinEntry.toRole }, oldTeam = { --TODO + team = joinEntry.fromTeam, + role = joinEntry.fromRole }, newTeam = { - --TODO + team = leaveEntry.toTeam, + role = leaveEntry.toRole }, faction = '' --TODO diff --git a/lua/wikis/commons/Squad/Utils.lua b/lua/wikis/commons/Squad/Utils.lua index 29e577fb784..a605d8d5474 100644 --- a/lua/wikis/commons/Squad/Utils.lua +++ b/lua/wikis/commons/Squad/Utils.lua @@ -98,8 +98,8 @@ function SquadUtils.anyInactive(players) end) end ----@param player table ----@return table +---@param player SquadAutoPerson +---@return SquadPersonArgs function SquadUtils.convertAutoParameters(player) local newPlayer = Table.copy(player) local joinReference = TransferRefs.useReferences(player.joindateRef, player.joindate) @@ -122,7 +122,30 @@ function SquadUtils.convertAutoParameters(player) return newPlayer end ----@param args table +---@class SquadPersonArgs +---@field name string? +---@field id string? +---@field link string? +---@field flag string? +---@field position string? +---@field role string? +---@field captain string? +---@field igl string? +---@field newteam string? +---@field newteamrole string? +---@field newrole string? +---@field joindate string? +---@field leavedate string? +---@field inactivedate string? +---@field status string? +---@field type string? +---@field team string? +---@field teamrole string? +---@field newteamdate string? +---@field faction string? +---@field race string? + +---@param args SquadPersonArgs ---@return ModelRow function SquadUtils.readSquadPersonArgs(args) local function getTeamInfo(page, property) From 4bce5d40d52c64e8e3c4c27aa182b9b838c351dc Mon Sep 17 00:00:00 2001 From: mbergen Date: Sun, 6 Apr 2025 17:22:26 +0200 Subject: [PATCH 05/50] Add included/excluded roles --- lua/wikis/commons/Squad/Auto.lua | 90 ++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 11 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 5a0c06d3161..8f913c4c268 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -65,6 +65,7 @@ end) ---@field type SquadType ---@field title string? ---@field teams string[]? +---@field roles {excluded: string[], included: string[]} ---@enum TransferType SquadAuto.TransferType = { @@ -87,6 +88,31 @@ SquadAuto.TransferType = { ---@field fromRole string? ---@field toTeam string? ---@field toRole string? +---@field faction string? + +local DEFAULT_INCLUDED_ROLES = { + [SquadUtils.SquadType.PLAYER] = { + '', + 'Loan', + 'Substitute', + 'Trial', + 'Stand-in', + 'Uncontracted' + }, + [SquadUtils.SquadType.STAFF] = {}, +} + +local DEFAULT_EXCLUDED_ROLES = { + [SquadUtils.SquadType.PLAYER] = {}, + [SquadUtils.SquadType.STAFF] = { + '', + 'Loan', + 'Substitute', + 'Trial', + 'Stand-in', + 'Uncontracted' + }, +} ---Entrypoint for the automated timelin ---TODO: Implement in submodule @@ -113,11 +139,16 @@ end ---Parses the args into a SquadAutoConfig function SquadAuto:parseConfig() local args = self.args + local type = SquadUtils.TypeToSquadType[(args.type or ''):lower()] self.config = { team = args.team or mw.title.getCurrentTitle().text, status = SquadUtils.StatusToSquadStatus[(args.status or ''):lower()], - type = SquadUtils.TypeToSquadType[(args.type or ''):lower()], - title = args.title -- TODO: Switch to Former players instead of squad? + type = type, + title = args.title, -- TODO: Switch to Former players instead of squad? + roles = { + included = Logic.nilIfEmpty(Array.parseCommaSeparatedString(args.roles)) or DEFAULT_INCLUDED_ROLES[type], + excluded = Logic.nilIfEmpty(Array.parseCommaSeparatedString(args.not_roles)) or DEFAULT_EXCLUDED_ROLES[type], + } } if args.timeline then self.manualTimeline = self:readManualTimeline() @@ -134,6 +165,14 @@ function SquadAuto:parseConfig() if self.config.status == SquadUtils.SquadStatus.FORMER_INACTIVE then error("SquadStatus 'FORMER_INACTIVE' is not supported by SquadAuto.") end + + if self.config.status == SquadUtils.SquadStatus.INACTIVE then + table.insert(self.config.roles.included, 'Inactive') + else + table.insert(self.config.roles.excluded, 'Inactive') + end + + mw.logObject(self.config) end function SquadAuto:readManualPlayers() @@ -246,6 +285,7 @@ function SquadAuto:queryTransfers() -- Other wholeTeam = Logic.readBool(record.wholeteam), position = record.extradata.position, + faction = record.extradata.faction } -- TODO: Skip this transfer if there is no relevant change @@ -282,16 +322,40 @@ end ---comment ---@return table function SquadAuto:selectEntries() - return Array.flatMap( - Array.extractValues(self.playersTeamHistory), - FnUtil.curry(self._selectHistoryEntries, self) + return Array.filter( + Array.flatMap( + Array.extractValues(self.playersTeamHistory), + FnUtil.curry(self._selectHistoryEntries, self) + ), + ---@param entry SquadAutoPerson + function(entry) + local result = ( + Logic.isEmpty(self.config.roles.included) + or Array.any( + self.config.roles.included, + FnUtil.curry(Operator.eq, entry.thisTeam.role) + ) + ) and ( + Logic.isEmpty(self.config.roles.excluded) + or Array.all( + self.config.roles.excluded, + FnUtil.curry(Operator.neq, entry.thisTeam.role) + ) + ) + + if not result then + mw.logObject(entry, "Not included") + end + + return result + end ) end ---Returns a function that maps a set of transfers to a list of ---SquadAutoPersons. ----Behavior depends on the current config: ----If the status is (in)active, then at most one entry will be returned +---Behavior depends on therent config: +---If the status is (inive, then at most one entry will be returned ---If the status is former(_inactive), there might be multiple entries returned ---If the type does not match, no entries are returned ---@param entries TeamHistoryEntry[] @@ -321,6 +385,7 @@ function SquadAuto:_selectHistoryEntries(entries) else mw.log("Invalid transfer history for player " .. entry.pagename) mw.logObject(entry, "Invalid entry: Missing previous JOIN. Skipping") + mw.ext.TeamLiquidIntegration.add_category('SquadAuto with invalid player history') end return end @@ -363,19 +428,22 @@ function SquadAuto:_mapToSquadAutoPerson(joinEntry, leaveEntry) thisTeam = { --TODO team = joinEntry.toTeam, - role = joinEntry.toRole + role = joinEntry.toRole, + position = joinEntry.position }, oldTeam = { --TODO team = joinEntry.fromTeam, - role = joinEntry.fromRole + role = joinEntry.fromRole, }, newTeam = { team = leaveEntry.toTeam, - role = leaveEntry.toRole + role = leaveEntry.toRole, }, - faction = '' --TODO + -- From legacy: Prefer leaveEntry faction information + faction = leaveEntry.faction or joinEntry.faction, + race = leaveEntry.faction or joinEntry.faction } if leaveEntry and not entry.newTeam then From e31fcef26526206142941064a48c59bc46b71d69 Mon Sep 17 00:00:00 2001 From: mbergen Date: Thu, 10 Apr 2025 19:18:12 +0200 Subject: [PATCH 06/50] Start with manual input reading --- lua/wikis/commons/Squad/Auto.lua | 45 +++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 8f913c4c268..c209eb86808 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -114,7 +114,7 @@ local DEFAULT_EXCLUDED_ROLES = { }, } ----Entrypoint for the automated timelin +---Entrypoint for the automated timeline ---TODO: Implement in submodule function SquadAuto.timeline(frame) -- return SquadAuto(frame):timeline() @@ -175,7 +175,48 @@ function SquadAuto:parseConfig() mw.logObject(self.config) end +---@return SquadAutoPerson[] function SquadAuto:readManualPlayers() + ---@type SquadAutoPerson[] + local players = {} + + -- TODO: Readd limit to roles? + Array.forEach(self.args, function (entry) + local player = Json.parseIfString(entry) + if Logic.isNotEmpty(player) then + table.insert(players, { + page = player.link or player.id, + id = player.id, + captain = Logic.readBoolOrNil(player.captain), + name = player.name, + localizedname = player.localizedname, + thisTeam = { + team = self.config.team, + role = player.role, + position = player.position + }, + newTeam = { + team = player.newteam, + role = player.newteamrole, + player.newteamdate + }, + flag = player.flag, + oldTeam = { + team = player.oldteam + }, + joindate = (player.joindate or ''):gsub('%?%?','01'), + joindatedisplay = player.joindate, + joindateRef = {}, + leavedate = (player.leavedate or ''):gsub('%?%?','01'), + leavedatedisplay = player.leavedate, + leavedateRef = {}, + faction = player.faction or player.race, + race = player.faction or player.race, + }) + end + end) + + return players end function SquadAuto:readManualTimeline() @@ -426,13 +467,11 @@ function SquadAuto:_mapToSquadAutoPerson(joinEntry, leaveEntry) leavedateRef = leaveEntry.references, thisTeam = { - --TODO team = joinEntry.toTeam, role = joinEntry.toRole, position = joinEntry.position }, oldTeam = { - --TODO team = joinEntry.fromTeam, role = joinEntry.fromRole, }, From 6778b949d4beadb16044f66620f6bec46ddf55cd Mon Sep 17 00:00:00 2001 From: mbergen Date: Thu, 8 May 2025 17:14:56 +0200 Subject: [PATCH 07/50] Implement tabs, manual player additions --- lua/wikis/commons/Squad/Auto.lua | 134 +++++++++++++++++++++++-------- 1 file changed, 101 insertions(+), 33 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index c209eb86808..ae3f1716ff1 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -14,8 +14,9 @@ local FnUtil = require('Module:FnUtil') local Json = require('Module:Json') local Logic = require('Module:Logic') local Lpdb = require('Module:Lpdb') -local Table = require('Module:Table') local Operator = require('Module:Operator') +local Table = require('Module:Table') +local Tabs = require('Module:Tabs') local SquadUtils = require('Module:Squad/Utils') local SquadCustom = require('Module:Squad/Custom') @@ -54,7 +55,7 @@ end) ---@field joindatedisplay string? ---@field joindateRef table? ---@field leavedate string? ----@field leavedatedisplay string? +---@field leavedatedisplay string ---@field leavedateRef table? ---@field faction string? ---@field captain boolean? @@ -114,12 +115,6 @@ local DEFAULT_EXCLUDED_ROLES = { }, } ----Entrypoint for the automated timeline ----TODO: Implement in submodule -function SquadAuto.timeline(frame) - -- return SquadAuto(frame):timeline() -end - ---Entrypoint for SquadAuto tables ---@param frame table function SquadAuto.run(frame) @@ -127,13 +122,10 @@ function SquadAuto.run(frame) autosquad:parseConfig() autosquad:queryTransfers() - return autosquad:display() -end + local entries = autosquad:selectEntries() + Array.forEach(entries, SquadAuto.enrichEntry) -function SquadAuto:display() - local entries = self:selectEntries() - mw.logObject(entries) - return SquadCustom.runAuto(entries, self.config.status, self.config.type, self.config.title) + return autosquad:display(entries) end ---Parses the args into a SquadAutoConfig @@ -144,16 +136,20 @@ function SquadAuto:parseConfig() team = args.team or mw.title.getCurrentTitle().text, status = SquadUtils.StatusToSquadStatus[(args.status or ''):lower()], type = type, - title = args.title, -- TODO: Switch to Former players instead of squad? + title = args.title, roles = { included = Logic.nilIfEmpty(Array.parseCommaSeparatedString(args.roles)) or DEFAULT_INCLUDED_ROLES[type], excluded = Logic.nilIfEmpty(Array.parseCommaSeparatedString(args.not_roles)) or DEFAULT_EXCLUDED_ROLES[type], } } - if args.timeline then - self.manualTimeline = self:readManualTimeline() - else - self.manualPlayers = self:readManualPlayers() + + self.manualPlayers = self:readManualPlayers() + + -- Override default 'Former Squad' title + if self.config.status == SquadUtils.SquadStatus.FORMER + and type == SquadUtils.SquadType.PLAYER + and not self.config.title then + self.config.title = 'Former Players' end local historicalTemplates = mw.ext.TeamTemplate.raw_historical(self.config.team) @@ -171,8 +167,71 @@ function SquadAuto:parseConfig() else table.insert(self.config.roles.excluded, 'Inactive') end +end + +---@param entries SquadAutoPerson[] +---@return Widget|Html|string? +function SquadAuto:display(entries) + if Logic.isEmpty(entries) then + return + end + + if self.config.status == SquadUtils.SquadStatus.FORMER then + return self:displayTabs(entries) + end + + entries = SquadAuto._sortEntries(entries) - mw.logObject(self.config) + return SquadCustom.runAuto(entries, self.config.status, self.config.type, self.config.title) +end + +---@param entries SquadAutoPerson[] +---@return Html|string? +function SquadAuto:displayTabs(entries) + local _, groupedEntries = Array.groupBy( + entries, + ---@param entry SquadAutoPerson + function (entry) + return entry.leavedate:match('(%d%d%d%d)') + end + ) + + ---@type table + local tabs = { + This = Table.size(groupedEntries), + removeEmptyTabs = true + } + + local idx = 1 + for year, group in Table.iter.spairs(groupedEntries) do + tabs['name' .. idx] = year + tabs['content' .. idx] = tostring(SquadCustom.runAuto( + SquadAuto._sortEntries(group), + self.config.status, + self.config.type, + self.config.title + )) + idx = idx + 1 + end + + return Tabs.dynamic(tabs) +end + +---@param entry SquadAutoPerson +function SquadAuto.enrichEntry(entry) + local personInfo = mw.ext.LiquipediaDB.lpdb('player', { + conditions = '[[pagename::' .. string.gsub(entry.page, ' ', '_') .. ']]', + limit = 1, + query = 'pagename, nationality, id, name, localizedname, extradata' + })[1] + + if personInfo then + entry.id = personInfo.id + entry.flag = personInfo.nationality + entry.name = personInfo.name + entry.localizedname = personInfo.localizedname + end + --TODO: Captain from pagevars? end ---@return SquadAutoPerson[] @@ -180,12 +239,13 @@ function SquadAuto:readManualPlayers() ---@type SquadAutoPerson[] local players = {} - -- TODO: Readd limit to roles? + -- TODO: Handle manual 'enrichments' for adding names + -- TODO: Readd limitations to specific roles? Array.forEach(self.args, function (entry) local player = Json.parseIfString(entry) if Logic.isNotEmpty(player) then table.insert(players, { - page = player.link or player.id, + page = player.link or player.id or player.name, id = player.id, captain = Logic.readBoolOrNil(player.captain), name = player.name, @@ -219,9 +279,6 @@ function SquadAuto:readManualPlayers() return players end -function SquadAuto:readManualTimeline() -end - function SquadAuto:queryTransfers() ---Checks whether a given team is the currently queried team ---@param team string? @@ -334,7 +391,6 @@ function SquadAuto:queryTransfers() table.insert(self.playersTeamHistory[record.player], entry) end ) - end ---Builds the conditions to fetch all transfers related @@ -360,13 +416,15 @@ function SquadAuto:buildConditions() return conditions:toString() end ----comment ----@return table +---@return SquadAutoPerson[] function SquadAuto:selectEntries() return Array.filter( - Array.flatMap( - Array.extractValues(self.playersTeamHistory), - FnUtil.curry(self._selectHistoryEntries, self) + Array.extend( + Array.flatMap( + Array.extractValues(self.playersTeamHistory), + FnUtil.curry(self._selectHistoryEntries, self) + ), + self.manualPlayers ), ---@param entry SquadAutoPerson function(entry) @@ -462,8 +520,8 @@ function SquadAuto:_mapToSquadAutoPerson(joinEntry, leaveEntry) joindateRef = joinEntry.references, idleavedate = leaveEntry.displayname, - leavedate = leaveEntry.date or '', - leavedatedisplay = leaveEntry.dateDisplay, + leavedate = leaveEntry.date, + leavedatedisplay = leaveEntry.dateDisplay or '', leavedateRef = leaveEntry.references, thisTeam = { @@ -492,5 +550,15 @@ function SquadAuto:_mapToSquadAutoPerson(joinEntry, leaveEntry) return entry end +---Sorts a list of SquadAutoPersons +-- Active entries (no leavedate) sorted by joindate, +-- Former entries sorted by leavedate +---@param entries SquadAutoPerson[] +---@return unknown[] +function SquadAuto._sortEntries(entries) + return Array.sortBy(entries, function (element) + return {element.leavedate or element.joindate, element.id} + end) +end return SquadAuto From 0beb652e5b8ab19ff46a75fd2355175bc264fb3d Mon Sep 17 00:00:00 2001 From: mbergen Date: Thu, 8 May 2025 18:55:43 +0200 Subject: [PATCH 08/50] Support type inactive via default roles --- lua/wikis/commons/Squad/Auto.lua | 33 ++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index ae3f1716ff1..d88e9af1a32 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -93,12 +93,17 @@ SquadAuto.TransferType = { local DEFAULT_INCLUDED_ROLES = { [SquadUtils.SquadType.PLAYER] = { - '', - 'Loan', - 'Substitute', - 'Trial', - 'Stand-in', - 'Uncontracted' + [SquadUtils.SquadStatus.ACTIVE] = { + '', + 'Loan', + 'Substitute', + 'Trial', + 'Stand-in', + 'Uncontracted' + }, + [SquadUtils.SquadStatus.INACTIVE] = { + 'Inactive' + } }, [SquadUtils.SquadType.STAFF] = {}, } @@ -111,7 +116,8 @@ local DEFAULT_EXCLUDED_ROLES = { 'Substitute', 'Trial', 'Stand-in', - 'Uncontracted' + 'Uncontracted', + 'Inactive' }, } @@ -132,21 +138,24 @@ end function SquadAuto:parseConfig() local args = self.args local type = SquadUtils.TypeToSquadType[(args.type or ''):lower()] + local status = SquadUtils.StatusToSquadStatus[(args.status or ''):lower()] self.config = { team = args.team or mw.title.getCurrentTitle().text, - status = SquadUtils.StatusToSquadStatus[(args.status or ''):lower()], type = type, + status = status, title = args.title, roles = { - included = Logic.nilIfEmpty(Array.parseCommaSeparatedString(args.roles)) or DEFAULT_INCLUDED_ROLES[type], - excluded = Logic.nilIfEmpty(Array.parseCommaSeparatedString(args.not_roles)) or DEFAULT_EXCLUDED_ROLES[type], + included = Logic.nilIfEmpty(Array.parseCommaSeparatedString(args.roles)) + or DEFAULT_INCLUDED_ROLES[type][status], + excluded = Logic.nilIfEmpty(Array.parseCommaSeparatedString(args.not_roles)) + or DEFAULT_EXCLUDED_ROLES[type], } } self.manualPlayers = self:readManualPlayers() -- Override default 'Former Squad' title - if self.config.status == SquadUtils.SquadStatus.FORMER + if status == SquadUtils.SquadStatus.FORMER and type == SquadUtils.SquadType.PLAYER and not self.config.title then self.config.title = 'Former Players' @@ -451,7 +460,7 @@ function SquadAuto:selectEntries() ) end ----Returns a function that maps a set of transfers to a list of +---Returns a function that maps a set of transfers to a list of ---SquadAutoPersons. ---Behavior depends on therent config: ---If the status is (inive, then at most one entry will be returned From 8060211fdb731618f213d34f1dd7d4a0153b9279 Mon Sep 17 00:00:00 2001 From: mbergen Date: Sat, 10 May 2025 12:43:41 +0200 Subject: [PATCH 09/50] Implement fetching of next team --- lua/definitions/liquipedia_db.lua | 2 +- lua/wikis/commons/Squad/Auto.lua | 48 ++++++++++++++++++++++++++----- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/lua/definitions/liquipedia_db.lua b/lua/definitions/liquipedia_db.lua index 3fff616e01b..0576b34f455 100644 --- a/lua/definitions/liquipedia_db.lua +++ b/lua/definitions/liquipedia_db.lua @@ -63,7 +63,7 @@ local lpdb = {} ---@field alternativeid string ---@field name string ---@field localizedname string ----@field iamge string +---@field image string ---@field type string ---@field nationality string ---@field nationality2 string diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index d88e9af1a32..8a83d476160 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -368,6 +368,13 @@ function SquadAuto:queryTransfers() local relevantToTeam, isToMain = parseRelevantTeam('to', record) local transferType = getTransferType(relevantFromTeam, relevantToTeam) + -- For leave transfers: Pass on new team for display as next team + if transferType == "LEAVE" and Logic.isEmpty(relevantToTeam) then + relevantToTeam = isFromMain + and Logic.nilIfEmpty(record.toteamtemplate) + or record.extradata.toteamsectemplate + end + ---@type TeamHistoryEntry local entry = { type = transferType, @@ -451,10 +458,6 @@ function SquadAuto:selectEntries() ) ) - if not result then - mw.logObject(entry, "Not included") - end - return result end ) @@ -547,18 +550,49 @@ function SquadAuto:_mapToSquadAutoPerson(joinEntry, leaveEntry) role = leaveEntry.toRole, }, - -- From legacy: Prefer leaveEntry faction information + -- From legacy: Prefer faction information from leaveEntry faction = leaveEntry.faction or joinEntry.faction, race = leaveEntry.faction or joinEntry.faction } - if leaveEntry and not entry.newTeam then - --TODO: Fetch next team for person + -- On leave: Fetch the next team a person joined + if Logic.isNotEmpty(leaveEntry) and Logic.isEmpty(entry.newTeam.team) then + local newTeam, newRole = SquadAuto._fetchNextTeam(joinEntry.pagename, leaveEntry.date) + if newTeam then + entry.newTeam.team = newTeam + entry.newTeam.role = newRole + end end return entry end +---Fetches the next team a person joined after a given date +---@param pagename string +---@param date string +---@return string? +---@return string? +function SquadAuto._fetchNextTeam(pagename, date) + local conditions = Condition.Tree(BooleanOperator.all) + :add{ + Condition.Node(Condition.ColumnName('player'), Comparator.eq, string.gsub(pagename, ' ', '_')), + Condition.Tree(BooleanOperator.any):add{ + Condition.Node(Condition.ColumnName('date'), Comparator.gt, date), + } + } + + local transfer = mw.ext.LiquipediaDB.lpdb('transfer', { + conditions = conditions:toString(), + limit = 1, + order = 'date asc, objectname desc', + query = 'toteamtemplate, role2' + })[1] or {} + + -- TODO: Check if fetched transfer is in fact a join transfer (empty fromTeam)? + + return transfer.toteamtemplate, transfer.role2 +end + ---Sorts a list of SquadAutoPersons -- Active entries (no leavedate) sorted by joindate, -- Former entries sorted by leavedate From 063b50530e95373c7ef554eac07043810a27bc65 Mon Sep 17 00:00:00 2001 From: mbergen Date: Sat, 10 May 2025 13:38:36 +0200 Subject: [PATCH 10/50] Fix handling of inactive persons --- lua/wikis/commons/Squad/Auto.lua | 38 +++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 8a83d476160..9b79e37c526 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -369,7 +369,7 @@ function SquadAuto:queryTransfers() local transferType = getTransferType(relevantFromTeam, relevantToTeam) -- For leave transfers: Pass on new team for display as next team - if transferType == "LEAVE" and Logic.isEmpty(relevantToTeam) then + if transferType == SquadAuto.TransferType.LEAVE and Logic.isEmpty(relevantToTeam) then relevantToTeam = isFromMain and Logic.nilIfEmpty(record.toteamtemplate) or record.extradata.toteamsectemplate @@ -402,8 +402,13 @@ function SquadAuto:queryTransfers() faction = record.extradata.faction } - -- TODO: Skip this transfer if there is no relevant change - -- E.g. this is grabbed a secondary team, but only main team changed + -- Skip this transfer if there is no relevant change, i.e. the role in this team didn't change + -- E.g. this is grabbed by secondary team, but only main team changed + if relevantFromTeam == relevantToTeam + and entry.fromRole == entry.toRole then + return + end + table.insert(self.playersTeamHistory[record.player], entry) end ) @@ -463,27 +468,32 @@ function SquadAuto:selectEntries() ) end ----Returns a function that maps a set of transfers to a list of ----SquadAutoPersons. ----Behavior depends on therent config: ----If the status is (inive, then at most one entry will be returned +---Returns a function that maps a set of transfers to a list of SquadAutoPersons. +---Behavior depends on the current config: +---If the status is (in)active, then at most one entry will be returned ---If the status is former(_inactive), there might be multiple entries returned ---If the type does not match, no entries are returned ---@param entries TeamHistoryEntry[] ---@return SquadAutoPerson[] function SquadAuto:_selectHistoryEntries(entries) -- Select entries to match status - if self.config.status == SquadUtils.SquadStatus.ACTIVE - or self.config.status == SquadUtils.SquadStatus.INACTIVE then + if self.config.status == SquadUtils.SquadStatus.ACTIVE then -- Only most recent transfer is relevant local last = entries[#entries] if last.type == SquadAuto.TransferType.CHANGE or last.type == SquadAuto.TransferType.JOIN then - -- When the last transfer is a leave transfer, the person wouldn't be (in)active + -- When the last transfer is a leave transfer, the person wouldn't be active return {self:_mapToSquadAutoPerson(last)} end end + if self.config.status == SquadUtils.SquadStatus.INACTIVE then + local last, secondToLast = entries[#entries], entries[#entries - 1] + if secondToLast and last.type == SquadAuto.TransferType.CHANGE then + return {self:_mapToSquadAutoPerson(secondToLast, last)} + end + end + if self.config.status == SquadUtils.SquadStatus.FORMER then local history = {} @@ -564,6 +574,14 @@ function SquadAuto:_mapToSquadAutoPerson(joinEntry, leaveEntry) end end + -- Special case: Person went inactive. + -- Set thisTeam.role to inactive and remove newTeam.role, + -- otherwise Squad doesn't display the entries + if leaveEntry.toRole == "Inactive" then + entry.thisTeam.role = entry.newTeam.role + entry.newTeam.role = "" + end + return entry end From 65abcafe458403f0a1f25ed09853bacf2571c159 Mon Sep 17 00:00:00 2001 From: mbergen Date: Sat, 10 May 2025 14:40:08 +0200 Subject: [PATCH 11/50] Only apply inactive modification for InactiveSquad --- lua/wikis/commons/Squad/Auto.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 9b79e37c526..eeccb7f0846 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -577,7 +577,8 @@ function SquadAuto:_mapToSquadAutoPerson(joinEntry, leaveEntry) -- Special case: Person went inactive. -- Set thisTeam.role to inactive and remove newTeam.role, -- otherwise Squad doesn't display the entries - if leaveEntry.toRole == "Inactive" then + if self.config.status == SquadUtils.SquadStatus.INACTIVE + and leaveEntry.toRole == "Inactive" then entry.thisTeam.role = entry.newTeam.role entry.newTeam.role = "" end From 2526983da51a4c0510153763cc2c7f76c3eb5951 Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Mon, 12 May 2025 14:30:12 +0200 Subject: [PATCH 12/50] Update lua/wikis/commons/Squad/Auto.lua --- lua/wikis/commons/Squad/Auto.lua | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index eeccb7f0846..a409dff107a 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -171,11 +171,6 @@ function SquadAuto:parseConfig() error("SquadStatus 'FORMER_INACTIVE' is not supported by SquadAuto.") end - if self.config.status == SquadUtils.SquadStatus.INACTIVE then - table.insert(self.config.roles.included, 'Inactive') - else - table.insert(self.config.roles.excluded, 'Inactive') - end end ---@param entries SquadAutoPerson[] From 5ad40abcfd09d9975f7a9b4126f5bf9b3ac6d53f Mon Sep 17 00:00:00 2001 From: mbergen Date: Wed, 14 May 2025 12:08:30 +0200 Subject: [PATCH 13/50] Convert indentation to tabs --- lua/wikis/commons/Squad/Auto.lua | 846 +++++++++++++++---------------- 1 file changed, 423 insertions(+), 423 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index a409dff107a..bb20c9c2921 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -31,7 +31,7 @@ local Comparator = Condition.Comparator ---@field manualTimeline table? ---@field playersTeamHistory table local SquadAuto = Class.new(nil, function (self, frame) - self.args = Arguments.getArgs(frame) + self.args = Arguments.getArgs(frame) end) ---@class SquadAutoTeam @@ -92,375 +92,375 @@ SquadAuto.TransferType = { ---@field faction string? local DEFAULT_INCLUDED_ROLES = { - [SquadUtils.SquadType.PLAYER] = { - [SquadUtils.SquadStatus.ACTIVE] = { - '', - 'Loan', - 'Substitute', - 'Trial', - 'Stand-in', - 'Uncontracted' - }, - [SquadUtils.SquadStatus.INACTIVE] = { - 'Inactive' - } - }, - [SquadUtils.SquadType.STAFF] = {}, + [SquadUtils.SquadType.PLAYER] = { + [SquadUtils.SquadStatus.ACTIVE] = { + '', + 'Loan', + 'Substitute', + 'Trial', + 'Stand-in', + 'Uncontracted' + }, + [SquadUtils.SquadStatus.INACTIVE] = { + 'Inactive' + } + }, + [SquadUtils.SquadType.STAFF] = {}, } local DEFAULT_EXCLUDED_ROLES = { - [SquadUtils.SquadType.PLAYER] = {}, - [SquadUtils.SquadType.STAFF] = { - '', - 'Loan', - 'Substitute', - 'Trial', - 'Stand-in', - 'Uncontracted', - 'Inactive' - }, + [SquadUtils.SquadType.PLAYER] = {}, + [SquadUtils.SquadType.STAFF] = { + '', + 'Loan', + 'Substitute', + 'Trial', + 'Stand-in', + 'Uncontracted', + 'Inactive' + }, } ---Entrypoint for SquadAuto tables ---@param frame table function SquadAuto.run(frame) - local autosquad = SquadAuto(frame) - autosquad:parseConfig() - autosquad:queryTransfers() + local autosquad = SquadAuto(frame) + autosquad:parseConfig() + autosquad:queryTransfers() - local entries = autosquad:selectEntries() - Array.forEach(entries, SquadAuto.enrichEntry) + local entries = autosquad:selectEntries() + Array.forEach(entries, SquadAuto.enrichEntry) - return autosquad:display(entries) + return autosquad:display(entries) end ---Parses the args into a SquadAutoConfig function SquadAuto:parseConfig() - local args = self.args - local type = SquadUtils.TypeToSquadType[(args.type or ''):lower()] - local status = SquadUtils.StatusToSquadStatus[(args.status or ''):lower()] - self.config = { - team = args.team or mw.title.getCurrentTitle().text, - type = type, - status = status, - title = args.title, - roles = { - included = Logic.nilIfEmpty(Array.parseCommaSeparatedString(args.roles)) - or DEFAULT_INCLUDED_ROLES[type][status], - excluded = Logic.nilIfEmpty(Array.parseCommaSeparatedString(args.not_roles)) - or DEFAULT_EXCLUDED_ROLES[type], - } - } - - self.manualPlayers = self:readManualPlayers() - - -- Override default 'Former Squad' title - if status == SquadUtils.SquadStatus.FORMER - and type == SquadUtils.SquadType.PLAYER - and not self.config.title then - self.config.title = 'Former Players' - end - - local historicalTemplates = mw.ext.TeamTemplate.raw_historical(self.config.team) - if not historicalTemplates then - error("Missing team template: " .. self.config.team) - end - self.config.teams = Array.append(Array.extractValues(historicalTemplates), self.config.team) - - if self.config.status == SquadUtils.SquadStatus.FORMER_INACTIVE then - error("SquadStatus 'FORMER_INACTIVE' is not supported by SquadAuto.") - end + local args = self.args + local type = SquadUtils.TypeToSquadType[(args.type or ''):lower()] + local status = SquadUtils.StatusToSquadStatus[(args.status or ''):lower()] + self.config = { + team = args.team or mw.title.getCurrentTitle().text, + type = type, + status = status, + title = args.title, + roles = { + included = Logic.nilIfEmpty(Array.parseCommaSeparatedString(args.roles)) + or DEFAULT_INCLUDED_ROLES[type][status], + excluded = Logic.nilIfEmpty(Array.parseCommaSeparatedString(args.not_roles)) + or DEFAULT_EXCLUDED_ROLES[type], + } + } + + self.manualPlayers = self:readManualPlayers() + + -- Override default 'Former Squad' title + if status == SquadUtils.SquadStatus.FORMER + and type == SquadUtils.SquadType.PLAYER + and not self.config.title then + self.config.title = 'Former Players' + end + + local historicalTemplates = mw.ext.TeamTemplate.raw_historical(self.config.team) + if not historicalTemplates then + error("Missing team template: " .. self.config.team) + end + self.config.teams = Array.append(Array.extractValues(historicalTemplates), self.config.team) + + if self.config.status == SquadUtils.SquadStatus.FORMER_INACTIVE then + error("SquadStatus 'FORMER_INACTIVE' is not supported by SquadAuto.") + end end ---@param entries SquadAutoPerson[] ---@return Widget|Html|string? function SquadAuto:display(entries) - if Logic.isEmpty(entries) then - return - end + if Logic.isEmpty(entries) then + return + end - if self.config.status == SquadUtils.SquadStatus.FORMER then - return self:displayTabs(entries) - end + if self.config.status == SquadUtils.SquadStatus.FORMER then + return self:displayTabs(entries) + end - entries = SquadAuto._sortEntries(entries) + entries = SquadAuto._sortEntries(entries) - return SquadCustom.runAuto(entries, self.config.status, self.config.type, self.config.title) + return SquadCustom.runAuto(entries, self.config.status, self.config.type, self.config.title) end ---@param entries SquadAutoPerson[] ---@return Html|string? function SquadAuto:displayTabs(entries) - local _, groupedEntries = Array.groupBy( - entries, - ---@param entry SquadAutoPerson - function (entry) - return entry.leavedate:match('(%d%d%d%d)') - end - ) - - ---@type table + local _, groupedEntries = Array.groupBy( + entries, + ---@param entry SquadAutoPerson + function (entry) + return entry.leavedate:match('(%d%d%d%d)') + end + ) + + ---@type table local tabs = { This = Table.size(groupedEntries), - removeEmptyTabs = true + removeEmptyTabs = true } - local idx = 1 + local idx = 1 for year, group in Table.iter.spairs(groupedEntries) do tabs['name' .. idx] = year - tabs['content' .. idx] = tostring(SquadCustom.runAuto( - SquadAuto._sortEntries(group), - self.config.status, - self.config.type, - self.config.title - )) - idx = idx + 1 + tabs['content' .. idx] = tostring(SquadCustom.runAuto( + SquadAuto._sortEntries(group), + self.config.status, + self.config.type, + self.config.title + )) + idx = idx + 1 end - return Tabs.dynamic(tabs) + return Tabs.dynamic(tabs) end ---@param entry SquadAutoPerson function SquadAuto.enrichEntry(entry) - local personInfo = mw.ext.LiquipediaDB.lpdb('player', { + local personInfo = mw.ext.LiquipediaDB.lpdb('player', { conditions = '[[pagename::' .. string.gsub(entry.page, ' ', '_') .. ']]', limit = 1, query = 'pagename, nationality, id, name, localizedname, extradata' })[1] if personInfo then - entry.id = personInfo.id - entry.flag = personInfo.nationality - entry.name = personInfo.name - entry.localizedname = personInfo.localizedname - end - --TODO: Captain from pagevars? + entry.id = personInfo.id + entry.flag = personInfo.nationality + entry.name = personInfo.name + entry.localizedname = personInfo.localizedname + end + --TODO: Captain from pagevars? end ---@return SquadAutoPerson[] function SquadAuto:readManualPlayers() - ---@type SquadAutoPerson[] - local players = {} - - -- TODO: Handle manual 'enrichments' for adding names - -- TODO: Readd limitations to specific roles? - Array.forEach(self.args, function (entry) - local player = Json.parseIfString(entry) - if Logic.isNotEmpty(player) then - table.insert(players, { - page = player.link or player.id or player.name, - id = player.id, - captain = Logic.readBoolOrNil(player.captain), - name = player.name, - localizedname = player.localizedname, - thisTeam = { - team = self.config.team, - role = player.role, - position = player.position - }, - newTeam = { - team = player.newteam, - role = player.newteamrole, - player.newteamdate - }, - flag = player.flag, - oldTeam = { - team = player.oldteam - }, - joindate = (player.joindate or ''):gsub('%?%?','01'), - joindatedisplay = player.joindate, - joindateRef = {}, - leavedate = (player.leavedate or ''):gsub('%?%?','01'), - leavedatedisplay = player.leavedate, - leavedateRef = {}, - faction = player.faction or player.race, - race = player.faction or player.race, - }) - end - end) - - return players + ---@type SquadAutoPerson[] + local players = {} + + -- TODO: Handle manual 'enrichments' for adding names + -- TODO: Readd limitations to specific roles? + Array.forEach(self.args, function (entry) + local player = Json.parseIfString(entry) + if Logic.isNotEmpty(player) then + table.insert(players, { + page = player.link or player.id or player.name, + id = player.id, + captain = Logic.readBoolOrNil(player.captain), + name = player.name, + localizedname = player.localizedname, + thisTeam = { + team = self.config.team, + role = player.role, + position = player.position + }, + newTeam = { + team = player.newteam, + role = player.newteamrole, + player.newteamdate + }, + flag = player.flag, + oldTeam = { + team = player.oldteam + }, + joindate = (player.joindate or ''):gsub('%?%?','01'), + joindatedisplay = player.joindate, + joindateRef = {}, + leavedate = (player.leavedate or ''):gsub('%?%?','01'), + leavedatedisplay = player.leavedate, + leavedateRef = {}, + faction = player.faction or player.race, + race = player.faction or player.race, + }) + end + end) + + return players end function SquadAuto:queryTransfers() - ---Checks whether a given team is the currently queried team - ---@param team string? - ---@return boolean - local function isCurrentTeam(team) - if not team then - return false - end - return Array.find(self.config.teams, function(t) return t == team end) ~= nil - end - - ---@param side 'from' | 'to' - ---@param transfer transfer - ---@return string | nil, boolean - local function parseRelevantTeam(side, transfer) - local mainTeam = transfer[side .. 'teamtemplate'] - if mainTeam and isCurrentTeam(mainTeam) then - return mainTeam, true - end - - local secondaryTeam = transfer.extradata[side .. 'teamsectemplate'] - if secondaryTeam and isCurrentTeam(secondaryTeam) then - return secondaryTeam, false - end - - return nil, false - end - - ---Maps a transfer to a transfertype, with regards to the current team. - ---@param relevantFromTeam string? - ---@param relevantToTeam string? - ---@return TransferType - local function getTransferType(relevantFromTeam, relevantToTeam) - if relevantFromTeam then - if relevantToTeam then - return SquadAuto.TransferType.CHANGE - end - return SquadAuto.TransferType.LEAVE - end - return SquadAuto.TransferType.JOIN - end - - ---Parses the relevant role for the current team from a transfer - ---@param side 'from' | 'to' - ---@param transfer transfer - ---@param team string? - ---@param isMain boolean - ---@return string? - local function parseRelevantRole(side, transfer, team, isMain) - if not team then - return nil - end - - if isMain then - return side == 'from' and transfer.role1 or transfer.role2 - else - return side == 'from' and transfer.extradata.role1sec or transfer.extradata.role2sec - end - end - - --TODO: Cache transfers/teamhistory in pagevars - ---@type table - self.playersTeamHistory = {} - - Lpdb.executeMassQuery( - 'transfer', - { - conditions = self:buildConditions(), - order = 'date asc, objectname desc', - limit = 5000 - }, - function(record) - self.playersTeamHistory[record.player] = self.playersTeamHistory[record.player] or {} - record.extradata = record.extradata or {} - - - local relevantFromTeam, isFromMain = parseRelevantTeam('from', record) - local relevantToTeam, isToMain = parseRelevantTeam('to', record) - local transferType = getTransferType(relevantFromTeam, relevantToTeam) - - -- For leave transfers: Pass on new team for display as next team - if transferType == SquadAuto.TransferType.LEAVE and Logic.isEmpty(relevantToTeam) then - relevantToTeam = isFromMain - and Logic.nilIfEmpty(record.toteamtemplate) - or record.extradata.toteamsectemplate - end - - ---@type TeamHistoryEntry - local entry = { - type = transferType, - - -- Person related information - pagename = record.player, - displayname = record.extradata.displayname, - flag = record.nationality, - - -- Date and references - date = record.date, - dateDisplay = record.extradata.displaydate, - references = record.reference, - - -- Roles - fromRole = parseRelevantRole('from', record, relevantFromTeam, isFromMain), - toRole = parseRelevantRole('to', record, relevantToTeam, isToMain), - - fromTeam = relevantFromTeam, - toTeam = relevantToTeam, - - -- Other - wholeTeam = Logic.readBool(record.wholeteam), - position = record.extradata.position, - faction = record.extradata.faction - } - - -- Skip this transfer if there is no relevant change, i.e. the role in this team didn't change - -- E.g. this is grabbed by secondary team, but only main team changed - if relevantFromTeam == relevantToTeam - and entry.fromRole == entry.toRole then - return - end - - table.insert(self.playersTeamHistory[record.player], entry) - end - ) + ---Checks whether a given team is the currently queried team + ---@param team string? + ---@return boolean + local function isCurrentTeam(team) + if not team then + return false + end + return Array.find(self.config.teams, function(t) return t == team end) ~= nil + end + + ---@param side 'from' | 'to' + ---@param transfer transfer + ---@return string | nil, boolean + local function parseRelevantTeam(side, transfer) + local mainTeam = transfer[side .. 'teamtemplate'] + if mainTeam and isCurrentTeam(mainTeam) then + return mainTeam, true + end + + local secondaryTeam = transfer.extradata[side .. 'teamsectemplate'] + if secondaryTeam and isCurrentTeam(secondaryTeam) then + return secondaryTeam, false + end + + return nil, false + end + + ---Maps a transfer to a transfertype, with regards to the current team. + ---@param relevantFromTeam string? + ---@param relevantToTeam string? + ---@return TransferType + local function getTransferType(relevantFromTeam, relevantToTeam) + if relevantFromTeam then + if relevantToTeam then + return SquadAuto.TransferType.CHANGE + end + return SquadAuto.TransferType.LEAVE + end + return SquadAuto.TransferType.JOIN + end + + ---Parses the relevant role for the current team from a transfer + ---@param side 'from' | 'to' + ---@param transfer transfer + ---@param team string? + ---@param isMain boolean + ---@return string? + local function parseRelevantRole(side, transfer, team, isMain) + if not team then + return nil + end + + if isMain then + return side == 'from' and transfer.role1 or transfer.role2 + else + return side == 'from' and transfer.extradata.role1sec or transfer.extradata.role2sec + end + end + + --TODO: Cache transfers/teamhistory in pagevars + ---@type table + self.playersTeamHistory = {} + + Lpdb.executeMassQuery( + 'transfer', + { + conditions = self:buildConditions(), + order = 'date asc, objectname desc', + limit = 5000 + }, + function(record) + self.playersTeamHistory[record.player] = self.playersTeamHistory[record.player] or {} + record.extradata = record.extradata or {} + + + local relevantFromTeam, isFromMain = parseRelevantTeam('from', record) + local relevantToTeam, isToMain = parseRelevantTeam('to', record) + local transferType = getTransferType(relevantFromTeam, relevantToTeam) + + -- For leave transfers: Pass on new team for display as next team + if transferType == SquadAuto.TransferType.LEAVE and Logic.isEmpty(relevantToTeam) then + relevantToTeam = isFromMain + and Logic.nilIfEmpty(record.toteamtemplate) + or record.extradata.toteamsectemplate + end + + ---@type TeamHistoryEntry + local entry = { + type = transferType, + + -- Person related information + pagename = record.player, + displayname = record.extradata.displayname, + flag = record.nationality, + + -- Date and references + date = record.date, + dateDisplay = record.extradata.displaydate, + references = record.reference, + + -- Roles + fromRole = parseRelevantRole('from', record, relevantFromTeam, isFromMain), + toRole = parseRelevantRole('to', record, relevantToTeam, isToMain), + + fromTeam = relevantFromTeam, + toTeam = relevantToTeam, + + -- Other + wholeTeam = Logic.readBool(record.wholeteam), + position = record.extradata.position, + faction = record.extradata.faction + } + + -- Skip this transfer if there is no relevant change, i.e. the role in this team didn't change + -- E.g. this is grabbed by secondary team, but only main team changed + if relevantFromTeam == relevantToTeam + and entry.fromRole == entry.toRole then + return + end + + table.insert(self.playersTeamHistory[record.player], entry) + end + ) end ---Builds the conditions to fetch all transfers related ---to the given team, respecting historical templates. ---@return string function SquadAuto:buildConditions() - local historicalTemplates = mw.ext.TeamTemplate.raw_historical(self.config.team) - - if not historicalTemplates then - error("Missing team template: " .. self.config.team) - end - - local conditions = Condition.Tree(BooleanOperator.any) - Array.forEach(Array.extendWith(Array.extractValues(historicalTemplates), self.config.team), function (templatename) - conditions:add{ - Condition.Node(Condition.ColumnName('fromteamtemplate'), Comparator.eq, templatename), - Condition.Node(Condition.ColumnName('extradata_fromteamsectemplate'), Comparator.eq, templatename), - Condition.Node(Condition.ColumnName('toteamtemplate'), Comparator.eq, templatename), - Condition.Node(Condition.ColumnName('extradata_toteamsectemplate'), Comparator.eq, templatename) - } - end) - - return conditions:toString() + local historicalTemplates = mw.ext.TeamTemplate.raw_historical(self.config.team) + + if not historicalTemplates then + error("Missing team template: " .. self.config.team) + end + + local conditions = Condition.Tree(BooleanOperator.any) + Array.forEach(Array.extendWith(Array.extractValues(historicalTemplates), self.config.team), function (templatename) + conditions:add{ + Condition.Node(Condition.ColumnName('fromteamtemplate'), Comparator.eq, templatename), + Condition.Node(Condition.ColumnName('extradata_fromteamsectemplate'), Comparator.eq, templatename), + Condition.Node(Condition.ColumnName('toteamtemplate'), Comparator.eq, templatename), + Condition.Node(Condition.ColumnName('extradata_toteamsectemplate'), Comparator.eq, templatename) + } + end) + + return conditions:toString() end ---@return SquadAutoPerson[] function SquadAuto:selectEntries() - return Array.filter( - Array.extend( - Array.flatMap( - Array.extractValues(self.playersTeamHistory), - FnUtil.curry(self._selectHistoryEntries, self) - ), - self.manualPlayers - ), - ---@param entry SquadAutoPerson - function(entry) - local result = ( - Logic.isEmpty(self.config.roles.included) - or Array.any( - self.config.roles.included, - FnUtil.curry(Operator.eq, entry.thisTeam.role) - ) - ) and ( - Logic.isEmpty(self.config.roles.excluded) - or Array.all( - self.config.roles.excluded, - FnUtil.curry(Operator.neq, entry.thisTeam.role) - ) - ) - - return result - end - ) + return Array.filter( + Array.extend( + Array.flatMap( + Array.extractValues(self.playersTeamHistory), + FnUtil.curry(self._selectHistoryEntries, self) + ), + self.manualPlayers + ), + ---@param entry SquadAutoPerson + function(entry) + local result = ( + Logic.isEmpty(self.config.roles.included) + or Array.any( + self.config.roles.included, + FnUtil.curry(Operator.eq, entry.thisTeam.role) + ) + ) and ( + Logic.isEmpty(self.config.roles.excluded) + or Array.all( + self.config.roles.excluded, + FnUtil.curry(Operator.neq, entry.thisTeam.role) + ) + ) + + return result + end + ) end ---Returns a function that maps a set of transfers to a list of SquadAutoPersons. @@ -471,53 +471,53 @@ end ---@param entries TeamHistoryEntry[] ---@return SquadAutoPerson[] function SquadAuto:_selectHistoryEntries(entries) - -- Select entries to match status - if self.config.status == SquadUtils.SquadStatus.ACTIVE then - -- Only most recent transfer is relevant - local last = entries[#entries] - if last.type == SquadAuto.TransferType.CHANGE - or last.type == SquadAuto.TransferType.JOIN then - -- When the last transfer is a leave transfer, the person wouldn't be active - return {self:_mapToSquadAutoPerson(last)} - end - end - - if self.config.status == SquadUtils.SquadStatus.INACTIVE then - local last, secondToLast = entries[#entries], entries[#entries - 1] - if secondToLast and last.type == SquadAuto.TransferType.CHANGE then - return {self:_mapToSquadAutoPerson(secondToLast, last)} - end - end - - if self.config.status == SquadUtils.SquadStatus.FORMER then - local history = {} - - local currentEntry = nil - - Array.forEach(entries, function (entry) - if not currentEntry then - if entry.type == SquadAuto.TransferType.JOIN then - currentEntry = entry - else - mw.log("Invalid transfer history for player " .. entry.pagename) - mw.logObject(entry, "Invalid entry: Missing previous JOIN. Skipping") - mw.ext.TeamLiquidIntegration.add_category('SquadAuto with invalid player history') - end - return - end - - table.insert(history, self:_mapToSquadAutoPerson(currentEntry, entry)) - if entry.type == "CHANGE" then - currentEntry = entry - else - currentEntry = nil - end - end) - - return history - end - - return {} + -- Select entries to match status + if self.config.status == SquadUtils.SquadStatus.ACTIVE then + -- Only most recent transfer is relevant + local last = entries[#entries] + if last.type == SquadAuto.TransferType.CHANGE + or last.type == SquadAuto.TransferType.JOIN then + -- When the last transfer is a leave transfer, the person wouldn't be active + return {self:_mapToSquadAutoPerson(last)} + end + end + + if self.config.status == SquadUtils.SquadStatus.INACTIVE then + local last, secondToLast = entries[#entries], entries[#entries - 1] + if secondToLast and last.type == SquadAuto.TransferType.CHANGE then + return {self:_mapToSquadAutoPerson(secondToLast, last)} + end + end + + if self.config.status == SquadUtils.SquadStatus.FORMER then + local history = {} + + local currentEntry = nil + + Array.forEach(entries, function (entry) + if not currentEntry then + if entry.type == SquadAuto.TransferType.JOIN then + currentEntry = entry + else + mw.log("Invalid transfer history for player " .. entry.pagename) + mw.logObject(entry, "Invalid entry: Missing previous JOIN. Skipping") + mw.ext.TeamLiquidIntegration.add_category('SquadAuto with invalid player history') + end + return + end + + table.insert(history, self:_mapToSquadAutoPerson(currentEntry, entry)) + if entry.type == "CHANGE" then + currentEntry = entry + else + currentEntry = nil + end + end) + + return history + end + + return {} end ---Maps one or a pair of TeamHistoryEntries to a single SquadAutoPerson @@ -525,60 +525,60 @@ end ---@param leaveEntry TeamHistoryEntry | nil ---@return SquadAutoPerson function SquadAuto:_mapToSquadAutoPerson(joinEntry, leaveEntry) - leaveEntry = leaveEntry or {} - - ---@type SquadAutoPerson - local entry = { - page = joinEntry.pagename, - id = joinEntry.displayname, - flag = joinEntry.flag, - joindate = joinEntry.date, - joindatedisplay = joinEntry.dateDisplay, - joindateRef = joinEntry.references, - - idleavedate = leaveEntry.displayname, - leavedate = leaveEntry.date, - leavedatedisplay = leaveEntry.dateDisplay or '', - leavedateRef = leaveEntry.references, - - thisTeam = { - team = joinEntry.toTeam, - role = joinEntry.toRole, - position = joinEntry.position - }, - oldTeam = { - team = joinEntry.fromTeam, - role = joinEntry.fromRole, - }, - newTeam = { - team = leaveEntry.toTeam, - role = leaveEntry.toRole, - }, - - -- From legacy: Prefer faction information from leaveEntry - faction = leaveEntry.faction or joinEntry.faction, - race = leaveEntry.faction or joinEntry.faction - } - - -- On leave: Fetch the next team a person joined - if Logic.isNotEmpty(leaveEntry) and Logic.isEmpty(entry.newTeam.team) then - local newTeam, newRole = SquadAuto._fetchNextTeam(joinEntry.pagename, leaveEntry.date) - if newTeam then - entry.newTeam.team = newTeam - entry.newTeam.role = newRole - end - end - - -- Special case: Person went inactive. - -- Set thisTeam.role to inactive and remove newTeam.role, - -- otherwise Squad doesn't display the entries - if self.config.status == SquadUtils.SquadStatus.INACTIVE - and leaveEntry.toRole == "Inactive" then - entry.thisTeam.role = entry.newTeam.role - entry.newTeam.role = "" - end - - return entry + leaveEntry = leaveEntry or {} + + ---@type SquadAutoPerson + local entry = { + page = joinEntry.pagename, + id = joinEntry.displayname, + flag = joinEntry.flag, + joindate = joinEntry.date, + joindatedisplay = joinEntry.dateDisplay, + joindateRef = joinEntry.references, + + idleavedate = leaveEntry.displayname, + leavedate = leaveEntry.date, + leavedatedisplay = leaveEntry.dateDisplay or '', + leavedateRef = leaveEntry.references, + + thisTeam = { + team = joinEntry.toTeam, + role = joinEntry.toRole, + position = joinEntry.position + }, + oldTeam = { + team = joinEntry.fromTeam, + role = joinEntry.fromRole, + }, + newTeam = { + team = leaveEntry.toTeam, + role = leaveEntry.toRole, + }, + + -- From legacy: Prefer faction information from leaveEntry + faction = leaveEntry.faction or joinEntry.faction, + race = leaveEntry.faction or joinEntry.faction + } + + -- On leave: Fetch the next team a person joined + if Logic.isNotEmpty(leaveEntry) and Logic.isEmpty(entry.newTeam.team) then + local newTeam, newRole = SquadAuto._fetchNextTeam(joinEntry.pagename, leaveEntry.date) + if newTeam then + entry.newTeam.team = newTeam + entry.newTeam.role = newRole + end + end + + -- Special case: Person went inactive. + -- Set thisTeam.role to inactive and remove newTeam.role, + -- otherwise Squad doesn't display the entries + if self.config.status == SquadUtils.SquadStatus.INACTIVE + and leaveEntry.toRole == "Inactive" then + entry.thisTeam.role = entry.newTeam.role + entry.newTeam.role = "" + end + + return entry end ---Fetches the next team a person joined after a given date @@ -587,24 +587,24 @@ end ---@return string? ---@return string? function SquadAuto._fetchNextTeam(pagename, date) - local conditions = Condition.Tree(BooleanOperator.all) - :add{ - Condition.Node(Condition.ColumnName('player'), Comparator.eq, string.gsub(pagename, ' ', '_')), - Condition.Tree(BooleanOperator.any):add{ - Condition.Node(Condition.ColumnName('date'), Comparator.gt, date), - } - } - - local transfer = mw.ext.LiquipediaDB.lpdb('transfer', { + local conditions = Condition.Tree(BooleanOperator.all) + :add{ + Condition.Node(Condition.ColumnName('player'), Comparator.eq, string.gsub(pagename, ' ', '_')), + Condition.Tree(BooleanOperator.any):add{ + Condition.Node(Condition.ColumnName('date'), Comparator.gt, date), + } + } + + local transfer = mw.ext.LiquipediaDB.lpdb('transfer', { conditions = conditions:toString(), limit = 1, - order = 'date asc, objectname desc', + order = 'date asc, objectname desc', query = 'toteamtemplate, role2' })[1] or {} - -- TODO: Check if fetched transfer is in fact a join transfer (empty fromTeam)? + -- TODO: Check if fetched transfer is in fact a join transfer (empty fromTeam)? - return transfer.toteamtemplate, transfer.role2 + return transfer.toteamtemplate, transfer.role2 end ---Sorts a list of SquadAutoPersons @@ -613,9 +613,9 @@ end ---@param entries SquadAutoPerson[] ---@return unknown[] function SquadAuto._sortEntries(entries) - return Array.sortBy(entries, function (element) - return {element.leavedate or element.joindate, element.id} - end) + return Array.sortBy(entries, function (element) + return {element.leavedate or element.joindate, element.id} + end) end return SquadAuto From c88a7d43c4fe7899809cd9524a41868e3ec364b2 Mon Sep 17 00:00:00 2001 From: mbergen Date: Sat, 17 May 2025 15:06:27 +0200 Subject: [PATCH 14/50] Add enrichment from manualInput --- lua/wikis/commons/Squad/Auto.lua | 113 ++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 41 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index bb20c9c2921..b4c31a17802 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -15,6 +15,7 @@ local Json = require('Module:Json') local Logic = require('Module:Logic') local Lpdb = require('Module:Lpdb') local Operator = require('Module:Operator') +local Page = require('Module:Page') local Table = require('Module:Table') local Tabs = require('Module:Tabs') @@ -40,14 +41,18 @@ end) ---@field position string? ---@field date string? ----TODO: Unify with SquadPerson ----@class SquadAutoPerson +---@class SquadAutoBase ---@field id string ---@field flag string? ----@field idleavedate string? ---@field page string ---@field name string? ---@field localizedname string? +---@field faction string? +---@field captain boolean? + +---TODO: Unify with SquadPerson +---@class SquadAutoPerson: SquadAutoBase +---@field idleavedate string? ---@field thisTeam SquadAutoTeam ---@field oldTeam SquadAutoTeam? ---@field newTeam SquadAutoTeam? @@ -57,8 +62,6 @@ end) ---@field leavedate string? ---@field leavedatedisplay string ---@field leavedateRef table? ----@field faction string? ----@field captain boolean? ---@class SquadAutoConfig ---@field team string @@ -129,7 +132,7 @@ function SquadAuto.run(frame) autosquad:queryTransfers() local entries = autosquad:selectEntries() - Array.forEach(entries, SquadAuto.enrichEntry) + Array.forEach(entries, FnUtil.curry(SquadAuto.enrichEntry, autosquad)) return autosquad:display(entries) end @@ -152,7 +155,7 @@ function SquadAuto:parseConfig() } } - self.manualPlayers = self:readManualPlayers() + self.manualPlayers, self.enrichmentInfo = self:readManualRowInput() -- Override default 'Former Squad' title if status == SquadUtils.SquadStatus.FORMER @@ -222,65 +225,93 @@ function SquadAuto:displayTabs(entries) end ---@param entry SquadAutoPerson -function SquadAuto.enrichEntry(entry) +function SquadAuto:enrichEntry(entry) + local pagename = Page.pageifyLink(entry.page) + local enrichment = self.enrichmentInfo[pagename] + if enrichment then + Table.mergeInto(entry, enrichment) + end + local personInfo = mw.ext.LiquipediaDB.lpdb('player', { - conditions = '[[pagename::' .. string.gsub(entry.page, ' ', '_') .. ']]', + conditions = '[[pagename::' .. pagename .. ']]', limit = 1, query = 'pagename, nationality, id, name, localizedname, extradata' })[1] if personInfo then - entry.id = personInfo.id - entry.flag = personInfo.nationality - entry.name = personInfo.name - entry.localizedname = personInfo.localizedname + entry.id = Logic.nilIfEmpty(entry.id) or personInfo.id + entry.flag = Logic.nilIfEmpty(entry.flag) or personInfo.nationality + entry.name = Logic.nilIfEmpty(entry.name) or personInfo.name + entry.localizedname = Logic.nilIfEmpty(entry.localizedname) or personInfo.localizedname end - --TODO: Captain from pagevars? + + --TODO: Captain from pagevar set in infobox? end ----@return SquadAutoPerson[] -function SquadAuto:readManualPlayers() +---@return SquadAutoPerson[] manualPersons +---@return table enrichmentInfo +function SquadAuto:readManualRowInput() ---@type SquadAutoPerson[] - local players = {} + local persons = {} + local enrichmentInfo = {} - -- TODO: Handle manual 'enrichments' for adding names - -- TODO: Readd limitations to specific roles? Array.forEach(self.args, function (entry) - local player = Json.parseIfString(entry) - if Logic.isNotEmpty(player) then - table.insert(players, { - page = player.link or player.id or player.name, - id = player.id, - captain = Logic.readBoolOrNil(player.captain), - name = player.name, - localizedname = player.localizedname, + local person = Json.parseIfString(entry) + + if Logic.isEmpty(person) then + return + end + + local page = Page.pageifyLink(person.link or person.id or person.name) + assert(page, "Missing identifier or link for SquadAutoRow " .. entry) + + if self.config.type == SquadUtils.SquadType.STAFF and Logic.isNotEmpty(person.role) then + -- Only allow manual entries for STAFF (organization) tables + table.insert(persons, { + page = page, + id = person.id, + captain = Logic.readBoolOrNil(person.captain), + name = person.name, + localizedname = person.localizedname, thisTeam = { team = self.config.team, - role = player.role, - position = player.position + role = person.role, + position = person.position }, newTeam = { - team = player.newteam, - role = player.newteamrole, - player.newteamdate + team = person.newteam, + role = person.newteamrole, + person.newteamdate }, - flag = player.flag, + flag = person.flag, oldTeam = { - team = player.oldteam + team = person.oldteam }, - joindate = (player.joindate or ''):gsub('%?%?','01'), - joindatedisplay = player.joindate, + joindate = (person.joindate or ''):gsub('%?%?','01'), + joindatedisplay = person.joindate, joindateRef = {}, - leavedate = (player.leavedate or ''):gsub('%?%?','01'), - leavedatedisplay = player.leavedate, + leavedate = (person.leavedate or ''):gsub('%?%?','01'), + leavedatedisplay = person.leavedate, leavedateRef = {}, - faction = player.faction or player.race, - race = player.faction or player.race, + faction = person.faction or person.race, + race = person.faction or person.race, }) + else + -- For PLAYER tables, or when no role is given: Treat as override + enrichmentInfo[page] = { + id = person.id, + captain = Logic.readBoolOrNil(person.captain), + name = person.name, + localizedname = person.localizedname, + flag = person.flag, + faction = person.faction or person.race, + } end end) - return players + mw.logObject(enrichmentInfo) + + return persons, enrichmentInfo end function SquadAuto:queryTransfers() From 69f1522c32e2c9f072b6aa2ce7255cb8e89b8afd Mon Sep 17 00:00:00 2001 From: mbergen Date: Tue, 20 May 2025 18:13:51 +0200 Subject: [PATCH 15/50] per review --- lua/wikis/commons/Squad/Auto.lua | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index b4c31a17802..2fa808552a4 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -18,6 +18,7 @@ local Operator = require('Module:Operator') local Page = require('Module:Page') local Table = require('Module:Table') local Tabs = require('Module:Tabs') +local TeamTemplate = require('Module:TeamTemplate') local SquadUtils = require('Module:Squad/Utils') local SquadCustom = require('Module:Squad/Custom') @@ -164,14 +165,14 @@ function SquadAuto:parseConfig() self.config.title = 'Former Players' end - local historicalTemplates = mw.ext.TeamTemplate.raw_historical(self.config.team) + local historicalTemplates = TeamTemplate.queryHistorical(self.config.team) if not historicalTemplates then - error("Missing team template: " .. self.config.team) + error(TeamTemplate.noTeamMessage(self.config.team)) end self.config.teams = Array.append(Array.extractValues(historicalTemplates), self.config.team) if self.config.status == SquadUtils.SquadStatus.FORMER_INACTIVE then - error("SquadStatus 'FORMER_INACTIVE' is not supported by SquadAuto.") + error('SquadStatus \'FORMER_INACTIVE\' is not supported by SquadAuto.') end end @@ -263,7 +264,7 @@ function SquadAuto:readManualRowInput() end local page = Page.pageifyLink(person.link or person.id or person.name) - assert(page, "Missing identifier or link for SquadAutoRow " .. entry) + assert(page, 'Missing identifier or link for SquadAutoRow ' .. entry) if self.config.type == SquadUtils.SquadType.STAFF and Logic.isNotEmpty(person.role) then -- Only allow manual entries for STAFF (organization) tables @@ -447,7 +448,7 @@ function SquadAuto:buildConditions() local historicalTemplates = mw.ext.TeamTemplate.raw_historical(self.config.team) if not historicalTemplates then - error("Missing team template: " .. self.config.team) + error('Missing team template: ' .. self.config.team) end local conditions = Condition.Tree(BooleanOperator.any) @@ -530,15 +531,15 @@ function SquadAuto:_selectHistoryEntries(entries) if entry.type == SquadAuto.TransferType.JOIN then currentEntry = entry else - mw.log("Invalid transfer history for player " .. entry.pagename) - mw.logObject(entry, "Invalid entry: Missing previous JOIN. Skipping") + mw.log('Invalid transfer history for player ' .. entry.pagename) + mw.logObject(entry, 'Invalid entry: Missing previous JOIN. Skipping') mw.ext.TeamLiquidIntegration.add_category('SquadAuto with invalid player history') end return end table.insert(history, self:_mapToSquadAutoPerson(currentEntry, entry)) - if entry.type == "CHANGE" then + if entry.type == 'CHANGE' then currentEntry = entry else currentEntry = nil @@ -604,9 +605,9 @@ function SquadAuto:_mapToSquadAutoPerson(joinEntry, leaveEntry) -- Set thisTeam.role to inactive and remove newTeam.role, -- otherwise Squad doesn't display the entries if self.config.status == SquadUtils.SquadStatus.INACTIVE - and leaveEntry.toRole == "Inactive" then + and leaveEntry.toRole == 'Inactive' then entry.thisTeam.role = entry.newTeam.role - entry.newTeam.role = "" + entry.newTeam.role = '' end return entry @@ -642,7 +643,7 @@ end -- Active entries (no leavedate) sorted by joindate, -- Former entries sorted by leavedate ---@param entries SquadAutoPerson[] ----@return unknown[] +---@return SquadAutoPerson[] function SquadAuto._sortEntries(entries) return Array.sortBy(entries, function (element) return {element.leavedate or element.joindate, element.id} From 3155f4c0489a513533c4da32c1df140571cdf0c7 Mon Sep 17 00:00:00 2001 From: mbergen Date: Tue, 20 May 2025 18:18:00 +0200 Subject: [PATCH 16/50] Remove tostring --- lua/wikis/commons/Squad/Auto.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 2fa808552a4..f65e345c626 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -213,12 +213,12 @@ function SquadAuto:displayTabs(entries) local idx = 1 for year, group in Table.iter.spairs(groupedEntries) do tabs['name' .. idx] = year - tabs['content' .. idx] = tostring(SquadCustom.runAuto( + tabs['content' .. idx] = SquadCustom.runAuto( SquadAuto._sortEntries(group), self.config.status, self.config.type, self.config.title - )) + ) idx = idx + 1 end From abf2d384c5df9d5bcf184a7016f8466feadfb4f8 Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Wed, 29 Oct 2025 13:41:05 +0100 Subject: [PATCH 17/50] Apply suggestions from review --- lua/wikis/commons/Squad/Auto.lua | 53 ++++++++++++++------------------ 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index f65e345c626..e244898c2d4 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -1,27 +1,28 @@ --- -- @Liquipedia --- wiki=commons -- page=Module:Squad/Auto -- -- Please see https://github.com/Liquipedia/Lua-Modules to contribute -- -local Arguments = require('Module:Arguments') -local Array = require('Module:Array') -local Class = require('Module:Class') -local Condition = require('Module:Condition') -local FnUtil = require('Module:FnUtil') -local Json = require('Module:Json') -local Logic = require('Module:Logic') -local Lpdb = require('Module:Lpdb') -local Operator = require('Module:Operator') -local Page = require('Module:Page') -local Table = require('Module:Table') -local Tabs = require('Module:Tabs') -local TeamTemplate = require('Module:TeamTemplate') - -local SquadUtils = require('Module:Squad/Utils') -local SquadCustom = require('Module:Squad/Custom') +local Lua = require('Module:Lua') + +local Arguments = Lua.import('Module:Arguments') +local Array = Lua.import('Module:Array') +local Class = Lua.import('Module:Class') +local Condition = Lua.import('Module:Condition') +local FnUtil = Lua.import('Module:FnUtil') +local Json = Lua.import('Module:Json') +local Logic = Lua.import('Module:Logic') +local Lpdb = Lua.import('Module:Lpdb') +local Operator = Lua.import('Module:Operator') +local Page = Lua.import('Module:Page') +local Table = Lua.import('Module:Table') +local Tabs = Lua.import('Module:Tabs') +local TeamTemplate = Lua.import('Module:TeamTemplate') + +local SquadUtils = Lua.import('Module:Squad/Utils') +local SquadCustom = Lua.import('Module:Squad/Custom') local BooleanOperator = Condition.BooleanOperator local Comparator = Condition.Comparator @@ -127,6 +128,7 @@ local DEFAULT_EXCLUDED_ROLES = { ---Entrypoint for SquadAuto tables ---@param frame table +---@return Widget|Html|string? function SquadAuto.run(frame) local autosquad = SquadAuto(frame) autosquad:parseConfig() @@ -174,7 +176,6 @@ function SquadAuto:parseConfig() if self.config.status == SquadUtils.SquadStatus.FORMER_INACTIVE then error('SquadStatus \'FORMER_INACTIVE\' is not supported by SquadAuto.') end - end ---@param entries SquadAutoPerson[] @@ -310,8 +311,6 @@ function SquadAuto:readManualRowInput() end end) - mw.logObject(enrichmentInfo) - return persons, enrichmentInfo end @@ -323,7 +322,7 @@ function SquadAuto:queryTransfers() if not team then return false end - return Array.find(self.config.teams, function(t) return t == team end) ~= nil + return Array.any(self.config.teams, function(t) return t == team end) end ---@param side 'from' | 'to' @@ -445,14 +444,8 @@ end ---to the given team, respecting historical templates. ---@return string function SquadAuto:buildConditions() - local historicalTemplates = mw.ext.TeamTemplate.raw_historical(self.config.team) - - if not historicalTemplates then - error('Missing team template: ' .. self.config.team) - end - local conditions = Condition.Tree(BooleanOperator.any) - Array.forEach(Array.extendWith(Array.extractValues(historicalTemplates), self.config.team), function (templatename) + Array.forEach(self.config.teams, function (templatename) conditions:add{ Condition.Node(Condition.ColumnName('fromteamtemplate'), Comparator.eq, templatename), Condition.Node(Condition.ColumnName('extradata_fromteamsectemplate'), Comparator.eq, templatename), @@ -539,7 +532,7 @@ function SquadAuto:_selectHistoryEntries(entries) end table.insert(history, self:_mapToSquadAutoPerson(currentEntry, entry)) - if entry.type == 'CHANGE' then + if entry.type == SquadAuto.TransferType.CHANGE then currentEntry = entry else currentEntry = nil @@ -634,7 +627,7 @@ function SquadAuto._fetchNextTeam(pagename, date) query = 'toteamtemplate, role2' })[1] or {} - -- TODO: Check if fetched transfer is in fact a join transfer (empty fromTeam)? + -- TODO: (Optional) Check if fetched transfer is in fact a join transfer (empty fromTeam)? return transfer.toteamtemplate, transfer.role2 end From 355cf0808c6275257c363290698fb2e8215b75dc Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Wed, 29 Oct 2025 15:45:33 +0100 Subject: [PATCH 18/50] Fix handling of former inactive players --- lua/wikis/commons/Squad/Auto.lua | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index e244898c2d4..ade978c0301 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -96,6 +96,8 @@ SquadAuto.TransferType = { ---@field toRole string? ---@field faction string? +local ROLE_INACTIVE = 'Inactive' + local DEFAULT_INCLUDED_ROLES = { [SquadUtils.SquadType.PLAYER] = { [SquadUtils.SquadStatus.ACTIVE] = { @@ -107,7 +109,7 @@ local DEFAULT_INCLUDED_ROLES = { 'Uncontracted' }, [SquadUtils.SquadStatus.INACTIVE] = { - 'Inactive' + ROLE_INACTIVE } }, [SquadUtils.SquadType.STAFF] = {}, @@ -116,13 +118,15 @@ local DEFAULT_INCLUDED_ROLES = { local DEFAULT_EXCLUDED_ROLES = { [SquadUtils.SquadType.PLAYER] = {}, [SquadUtils.SquadType.STAFF] = { - '', - 'Loan', - 'Substitute', - 'Trial', - 'Stand-in', - 'Uncontracted', - 'Inactive' + DEFAULT = { + '', + 'Loan', + 'Substitute', + 'Trial', + 'Stand-in', + 'Uncontracted', + ROLE_INACTIVE + }, }, } @@ -152,9 +156,9 @@ function SquadAuto:parseConfig() title = args.title, roles = { included = Logic.nilIfEmpty(Array.parseCommaSeparatedString(args.roles)) - or DEFAULT_INCLUDED_ROLES[type][status], + or DEFAULT_INCLUDED_ROLES[type][status]or DEFAULT_INCLUDED_ROLES[type].DEFAULT, excluded = Logic.nilIfEmpty(Array.parseCommaSeparatedString(args.not_roles)) - or DEFAULT_EXCLUDED_ROLES[type], + or DEFAULT_EXCLUDED_ROLES[type][status] or DEFAULT_EXCLUDED_ROLES[type].DEFAULT, } } @@ -509,7 +513,7 @@ function SquadAuto:_selectHistoryEntries(entries) if self.config.status == SquadUtils.SquadStatus.INACTIVE then local last, secondToLast = entries[#entries], entries[#entries - 1] - if secondToLast and last.type == SquadAuto.TransferType.CHANGE then + if secondToLast and last.type == SquadAuto.TransferType.CHANGE and last.toRole == ROLE_INACTIVE then return {self:_mapToSquadAutoPerson(secondToLast, last)} end end From cd3b10c635cc70bf720c43d53f2899a86e2e5ce7 Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Wed, 29 Oct 2025 15:55:22 +0100 Subject: [PATCH 19/50] Do not use single tabs --- lua/wikis/commons/Squad/Auto.lua | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index ade978c0301..e398ac92265 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -199,7 +199,7 @@ function SquadAuto:display(entries) end ---@param entries SquadAutoPerson[] ----@return Html|string? +---@return Widget|Html|string? function SquadAuto:displayTabs(entries) local _, groupedEntries = Array.groupBy( entries, @@ -209,9 +209,19 @@ function SquadAuto:displayTabs(entries) end ) + local tabCount = Table.size(groupedEntries) + if tabCount == 1 then + return SquadCustom.runAuto( + SquadAuto._sortEntries(entries), + self.config.status, + self.config.type, + self.config.title + ) + end + ---@type table local tabs = { - This = Table.size(groupedEntries), + This = tabCount, removeEmptyTabs = true } From a1e2121b0f84fff27430959584c8d15237e9b594 Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Wed, 29 Oct 2025 15:55:44 +0100 Subject: [PATCH 20/50] extract ROLES_PLAYER table --- lua/wikis/commons/Squad/Auto.lua | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index e398ac92265..cc034aa19f5 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -98,16 +98,19 @@ SquadAuto.TransferType = { local ROLE_INACTIVE = 'Inactive' +-- TODO: Replace with Module:Roles +local ROLES_PLAYER = { + '', + 'Loan', + 'Substitute', + 'Trial', + 'Stand-in', + 'Uncontracted' +} + local DEFAULT_INCLUDED_ROLES = { [SquadUtils.SquadType.PLAYER] = { - [SquadUtils.SquadStatus.ACTIVE] = { - '', - 'Loan', - 'Substitute', - 'Trial', - 'Stand-in', - 'Uncontracted' - }, + DEFAULT = ROLES_PLAYER, [SquadUtils.SquadStatus.INACTIVE] = { ROLE_INACTIVE } @@ -118,15 +121,10 @@ local DEFAULT_INCLUDED_ROLES = { local DEFAULT_EXCLUDED_ROLES = { [SquadUtils.SquadType.PLAYER] = {}, [SquadUtils.SquadType.STAFF] = { - DEFAULT = { - '', - 'Loan', - 'Substitute', - 'Trial', - 'Stand-in', - 'Uncontracted', + DEFAULT = Array.extend( + ROLES_PLAYER, ROLE_INACTIVE - }, + ), }, } From 7b9b50e5de50a5f063cb3f1911fd4b9bb906ce2e Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Wed, 29 Oct 2025 15:55:54 +0100 Subject: [PATCH 21/50] Support non-historical TTs --- lua/wikis/commons/Squad/Auto.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index cc034aa19f5..f267d7f0931 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -169,11 +169,12 @@ function SquadAuto:parseConfig() self.config.title = 'Former Players' end - local historicalTemplates = TeamTemplate.queryHistorical(self.config.team) - if not historicalTemplates then + local historicalTemplates = TeamTemplate.queryHistorical(self.config.team) or {} + self.config.teams = Array.append(Array.extractValues(historicalTemplates), TeamTemplate.resolve(self.config.team)) + + if Logic.isEmpty(self.config.teams) then error(TeamTemplate.noTeamMessage(self.config.team)) end - self.config.teams = Array.append(Array.extractValues(historicalTemplates), self.config.team) if self.config.status == SquadUtils.SquadStatus.FORMER_INACTIVE then error('SquadStatus \'FORMER_INACTIVE\' is not supported by SquadAuto.') From 8524e1e6bf7a96341aca27e1805b97c09e4fb49f Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Wed, 29 Oct 2025 15:56:12 +0100 Subject: [PATCH 22/50] Use newer names for display, fix querying of newteam --- lua/wikis/commons/Squad/Auto.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index f267d7f0931..0e7798fcc8a 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -568,7 +568,7 @@ function SquadAuto:_mapToSquadAutoPerson(joinEntry, leaveEntry) ---@type SquadAutoPerson local entry = { page = joinEntry.pagename, - id = joinEntry.displayname, + id = leaveEntry.displayname or joinEntry.displayname, flag = joinEntry.flag, joindate = joinEntry.date, joindatedisplay = joinEntry.dateDisplay, @@ -627,7 +627,10 @@ end function SquadAuto._fetchNextTeam(pagename, date) local conditions = Condition.Tree(BooleanOperator.all) :add{ - Condition.Node(Condition.ColumnName('player'), Comparator.eq, string.gsub(pagename, ' ', '_')), + Condition.Tree(BooleanOperator.any):add{ + Condition.Node(Condition.ColumnName('player'), Comparator.eq, pagename), + Condition.Node(Condition.ColumnName('player'), Comparator.eq, string.gsub(pagename, ' ', '_')), + }, Condition.Tree(BooleanOperator.any):add{ Condition.Node(Condition.ColumnName('date'), Comparator.gt, date), } From f4eae2f3dcc24892e515d39bcb613d67099e929d Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Wed, 29 Oct 2025 18:05:00 +0100 Subject: [PATCH 23/50] Cache queried transfers in variables --- lua/wikis/commons/Squad/Auto.lua | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 0e7798fcc8a..44c36eede91 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -17,6 +17,7 @@ local Logic = Lua.import('Module:Logic') local Lpdb = Lua.import('Module:Lpdb') local Operator = Lua.import('Module:Operator') local Page = Lua.import('Module:Page') +local PageVariableNamespace = Lua.import('Module:PageVariableNamespace') local Table = Lua.import('Module:Table') local Tabs = Lua.import('Module:Tabs') local TeamTemplate = Lua.import('Module:TeamTemplate') @@ -27,6 +28,8 @@ local SquadCustom = Lua.import('Module:Squad/Custom') local BooleanOperator = Condition.BooleanOperator local Comparator = Condition.Comparator +local pageVars = PageVariableNamespace() + ---@class SquadAuto ---@field args table ---@field config SquadAutoConfig @@ -387,9 +390,14 @@ function SquadAuto:queryTransfers() end end - --TODO: Cache transfers/teamhistory in pagevars + local teamHistoryKey = self.config.team .. '_all_transfers' + ---@type table - self.playersTeamHistory = {} + self.playersTeamHistory = Json.parseIfTable(pageVars:get(teamHistoryKey)) or {} + + if Logic.isNotEmpty(self.playersTeamHistory) then + return + end Lpdb.executeMassQuery( 'transfer', @@ -451,6 +459,7 @@ function SquadAuto:queryTransfers() table.insert(self.playersTeamHistory[record.player], entry) end ) + pageVars:set(teamHistoryKey, Json.stringify(self.playersTeamHistory)) end ---Builds the conditions to fetch all transfers related From 8357ccd62a029b4c140fcbc745ebcc80470348b7 Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Wed, 29 Oct 2025 18:17:58 +0100 Subject: [PATCH 24/50] Correctly display formerly inactive players --- lua/wikis/commons/Squad/Auto.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 44c36eede91..9f8547242d9 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -116,7 +116,11 @@ local DEFAULT_INCLUDED_ROLES = { DEFAULT = ROLES_PLAYER, [SquadUtils.SquadStatus.INACTIVE] = { ROLE_INACTIVE - } + }, + [SquadUtils.SquadStatus.FORMER] = Array.extend( + ROLES_PLAYER, + ROLE_INACTIVE + ), }, [SquadUtils.SquadType.STAFF] = {}, } From cfeb803aa6a33a8f5cbabc81289ac0b1cfdf6ec3 Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Thu, 30 Oct 2025 13:34:16 +0100 Subject: [PATCH 25/50] Apply suggestions from code review Co-authored-by: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> --- lua/wikis/commons/Squad/Auto.lua | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 9f8547242d9..c884365124d 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -342,7 +342,7 @@ function SquadAuto:queryTransfers() if not team then return false end - return Array.any(self.config.teams, function(t) return t == team end) + return Array.any(self.config.teams, FnUtil.curry(Operator.eq, team)) end ---@param side 'from' | 'to' @@ -640,9 +640,7 @@ end function SquadAuto._fetchNextTeam(pagename, date) local conditions = Condition.Tree(BooleanOperator.all) :add{ - Condition.Tree(BooleanOperator.any):add{ - Condition.Node(Condition.ColumnName('player'), Comparator.eq, pagename), - Condition.Node(Condition.ColumnName('player'), Comparator.eq, string.gsub(pagename, ' ', '_')), + Condition.Util.anyOf(Condition.ColumnName('player'), {pagename, string.gsub(pagename, ' ', '_')}), }, Condition.Tree(BooleanOperator.any):add{ Condition.Node(Condition.ColumnName('date'), Comparator.gt, date), From aec078ba76a58caaa71b5cae180a3f19a19638d2 Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Thu, 30 Oct 2025 13:46:28 +0100 Subject: [PATCH 26/50] Use emptyOr --- lua/wikis/commons/Squad/Auto.lua | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index c884365124d..832e692d9c5 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -74,7 +74,7 @@ end) ---@field type SquadType ---@field title string? ---@field teams string[]? ----@field roles {excluded: string[], included: string[]} +---@field roles {excluded: string[]?, included: string[]?} ---@enum TransferType SquadAuto.TransferType = { @@ -160,10 +160,16 @@ function SquadAuto:parseConfig() status = status, title = args.title, roles = { - included = Logic.nilIfEmpty(Array.parseCommaSeparatedString(args.roles)) - or DEFAULT_INCLUDED_ROLES[type][status]or DEFAULT_INCLUDED_ROLES[type].DEFAULT, - excluded = Logic.nilIfEmpty(Array.parseCommaSeparatedString(args.not_roles)) - or DEFAULT_EXCLUDED_ROLES[type][status] or DEFAULT_EXCLUDED_ROLES[type].DEFAULT, + included = Logic.emptyOr( + Array.parseCommaSeparatedString(args.roles), + DEFAULT_INCLUDED_ROLES[type][status], + DEFAULT_INCLUDED_ROLES[type].DEFAULT + ), + excluded = Logic.emptyOr( + Array.parseCommaSeparatedString(args.not_roles), + DEFAULT_EXCLUDED_ROLES[type][status], + DEFAULT_EXCLUDED_ROLES[type].DEFAULT + ) } } From 594898472a24b3db3b82536c30d69e8de2ea75b4 Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Thu, 30 Oct 2025 13:46:46 +0100 Subject: [PATCH 27/50] Use Side enum --- lua/wikis/commons/Squad/Auto.lua | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 832e692d9c5..350e2c6954e 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -99,6 +99,12 @@ SquadAuto.TransferType = { ---@field toRole string? ---@field faction string? +---@enum Side +local Side = { + from = 'from', + to = 'to', +} + local ROLE_INACTIVE = 'Inactive' -- TODO: Replace with Module:Roles @@ -136,7 +142,7 @@ local DEFAULT_EXCLUDED_ROLES = { } ---Entrypoint for SquadAuto tables ----@param frame table +---@param frame Frame|table ---@return Widget|Html|string? function SquadAuto.run(frame) local autosquad = SquadAuto(frame) @@ -351,7 +357,7 @@ function SquadAuto:queryTransfers() return Array.any(self.config.teams, FnUtil.curry(Operator.eq, team)) end - ---@param side 'from' | 'to' + ---@param side Side ---@param transfer transfer ---@return string | nil, boolean local function parseRelevantTeam(side, transfer) @@ -383,7 +389,7 @@ function SquadAuto:queryTransfers() end ---Parses the relevant role for the current team from a transfer - ---@param side 'from' | 'to' + ---@param side Side ---@param transfer transfer ---@param team string? ---@param isMain boolean @@ -394,9 +400,9 @@ function SquadAuto:queryTransfers() end if isMain then - return side == 'from' and transfer.role1 or transfer.role2 + return side == Side.from and transfer.role1 or transfer.role2 else - return side == 'from' and transfer.extradata.role1sec or transfer.extradata.role2sec + return side == Side.from and transfer.extradata.role1sec or transfer.extradata.role2sec end end @@ -421,8 +427,8 @@ function SquadAuto:queryTransfers() record.extradata = record.extradata or {} - local relevantFromTeam, isFromMain = parseRelevantTeam('from', record) - local relevantToTeam, isToMain = parseRelevantTeam('to', record) + local relevantFromTeam, isFromMain = parseRelevantTeam(Side.from, record) + local relevantToTeam, isToMain = parseRelevantTeam(Side.to, record) local transferType = getTransferType(relevantFromTeam, relevantToTeam) -- For leave transfers: Pass on new team for display as next team @@ -447,8 +453,8 @@ function SquadAuto:queryTransfers() references = record.reference, -- Roles - fromRole = parseRelevantRole('from', record, relevantFromTeam, isFromMain), - toRole = parseRelevantRole('to', record, relevantToTeam, isToMain), + fromRole = parseRelevantRole(Side.from, record, relevantFromTeam, isFromMain), + toRole = parseRelevantRole(Side.to, record, relevantToTeam, isToMain), fromTeam = relevantFromTeam, toTeam = relevantToTeam, @@ -647,7 +653,6 @@ function SquadAuto._fetchNextTeam(pagename, date) local conditions = Condition.Tree(BooleanOperator.all) :add{ Condition.Util.anyOf(Condition.ColumnName('player'), {pagename, string.gsub(pagename, ' ', '_')}), - }, Condition.Tree(BooleanOperator.any):add{ Condition.Node(Condition.ColumnName('date'), Comparator.gt, date), } From 3420480c0a9062dbd15daf5387ed85c8fcdc202f Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Thu, 30 Oct 2025 13:47:12 +0100 Subject: [PATCH 28/50] Make enum name more specific --- lua/wikis/commons/Squad/Auto.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 350e2c6954e..981c29981d7 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -99,7 +99,7 @@ SquadAuto.TransferType = { ---@field toRole string? ---@field faction string? ----@enum Side +---@enum TransferSide local Side = { from = 'from', to = 'to', @@ -357,7 +357,7 @@ function SquadAuto:queryTransfers() return Array.any(self.config.teams, FnUtil.curry(Operator.eq, team)) end - ---@param side Side + ---@param side TransferSide ---@param transfer transfer ---@return string | nil, boolean local function parseRelevantTeam(side, transfer) @@ -389,7 +389,7 @@ function SquadAuto:queryTransfers() end ---Parses the relevant role for the current team from a transfer - ---@param side Side + ---@param side TransferSide ---@param transfer transfer ---@param team string? ---@param isMain boolean From 18ac09d5b34232ec84a0d9d6b115bd78c85ff50e Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Fri, 31 Oct 2025 16:28:04 +0100 Subject: [PATCH 29/50] Implement sort using SquadAuto/rank --- lua/wikis/commons/Squad/Auto.lua | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 981c29981d7..f58c2a69e50 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -25,6 +25,8 @@ local TeamTemplate = Lua.import('Module:TeamTemplate') local SquadUtils = Lua.import('Module:Squad/Utils') local SquadCustom = Lua.import('Module:Squad/Custom') +local SquadAutoRank = Lua.import('Module:SquadAuto/rank', {loadData=true}) + local BooleanOperator = Condition.BooleanOperator local Comparator = Condition.Comparator @@ -105,6 +107,9 @@ local Side = { to = 'to', } +-- Default key for SquadAuto/rank +local DEFAULT_RANK_KEY = '' + local ROLE_INACTIVE = 'Inactive' -- TODO: Replace with Module:Roles @@ -211,7 +216,8 @@ function SquadAuto:display(entries) return self:displayTabs(entries) end - entries = SquadAuto._sortEntries(entries) + local useRankSort = self.config.status == SquadUtils.SquadStatus.ACTIVE + entries = SquadAuto._sortEntries(entries, useRankSort) return SquadCustom.runAuto(entries, self.config.status, self.config.type, self.config.title) end @@ -674,10 +680,16 @@ end -- Active entries (no leavedate) sorted by joindate, -- Former entries sorted by leavedate ---@param entries SquadAutoPerson[] +---@param useRankSort boolean? ---@return SquadAutoPerson[] -function SquadAuto._sortEntries(entries) +function SquadAuto._sortEntries(entries, useRankSort) return Array.sortBy(entries, function (element) - return {element.leavedate or element.joindate, element.id} + return { + useRankSort and SquadAutoRank[element.thisTeam.position] or SquadAutoRank[DEFAULT_RANK_KEY], + useRankSort and SquadAutoRank[element.thisTeam.role] or SquadAutoRank[DEFAULT_RANK_KEY], + element.leavedate or element.joindate, + element.id + } end) end From 9d20af5bf9ece6c5f1a4c991e91eda0cc4ff2dfe Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Fri, 22 May 2026 11:45:31 +0200 Subject: [PATCH 30/50] Allow same-day transfers for next team Co-authored-by: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> --- lua/wikis/commons/Squad/Auto.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index f58c2a69e50..02410014bd7 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -659,9 +659,8 @@ function SquadAuto._fetchNextTeam(pagename, date) local conditions = Condition.Tree(BooleanOperator.all) :add{ Condition.Util.anyOf(Condition.ColumnName('player'), {pagename, string.gsub(pagename, ' ', '_')}), - Condition.Tree(BooleanOperator.any):add{ - Condition.Node(Condition.ColumnName('date'), Comparator.gt, date), - } + Condition.Node(Condition.ColumnName('date'), Comparator.ge, date), + Condition.Node(Condition.ColumnName('toteamtemplate', Comparator.neq, ''), } local transfer = mw.ext.LiquipediaDB.lpdb('transfer', { From 0130cb0da14c2d43c064c2f970291b2adf19a2f6 Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Sat, 23 May 2026 16:31:37 +0200 Subject: [PATCH 31/50] Fix parentheses --- lua/wikis/commons/Squad/Auto.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 02410014bd7..f11d378c14a 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -660,7 +660,7 @@ function SquadAuto._fetchNextTeam(pagename, date) :add{ Condition.Util.anyOf(Condition.ColumnName('player'), {pagename, string.gsub(pagename, ' ', '_')}), Condition.Node(Condition.ColumnName('date'), Comparator.ge, date), - Condition.Node(Condition.ColumnName('toteamtemplate', Comparator.neq, ''), + Condition.Node(Condition.ColumnName('toteamtemplate', Comparator.neq, '')), } local transfer = mw.ext.LiquipediaDB.lpdb('transfer', { From f1929d30a672269f3444f8ef7c37e6321df0eaff Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Sat, 23 May 2026 16:39:56 +0200 Subject: [PATCH 32/50] Actually fix parentheses --- lua/wikis/commons/Squad/Auto.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index f11d378c14a..21f3a8696b6 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -660,7 +660,7 @@ function SquadAuto._fetchNextTeam(pagename, date) :add{ Condition.Util.anyOf(Condition.ColumnName('player'), {pagename, string.gsub(pagename, ' ', '_')}), Condition.Node(Condition.ColumnName('date'), Comparator.ge, date), - Condition.Node(Condition.ColumnName('toteamtemplate', Comparator.neq, '')), + Condition.Node(Condition.ColumnName('toteamtemplate'), Comparator.neq, ''), } local transfer = mw.ext.LiquipediaDB.lpdb('transfer', { From 4c129c25568f42852d1e0c2ff27a0e04db07ebd5 Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Sun, 24 May 2026 11:23:30 +0200 Subject: [PATCH 33/50] Start removing SquadAutoPerson->SquadPersonArgs conversion --- lua/wikis/ageofempires/Info.lua | 1 + lua/wikis/commons/Squad/Auto.lua | 108 ++++++++++++++++-------------- lua/wikis/commons/Squad/Utils.lua | 8 ++- 3 files changed, 66 insertions(+), 51 deletions(-) diff --git a/lua/wikis/ageofempires/Info.lua b/lua/wikis/ageofempires/Info.lua index 3d95d0ef309..24652158dd4 100644 --- a/lua/wikis/ageofempires/Info.lua +++ b/lua/wikis/ageofempires/Info.lua @@ -103,6 +103,7 @@ return { hasPosition = false, hasSpecialTeam = false, allowManual = true, + standardizedAuto = true, }, match2 = { status = 2, diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 21f3a8696b6..5bd5bd450f9 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -205,7 +205,7 @@ function SquadAuto:parseConfig() end end ----@param entries SquadAutoPerson[] +---@param entries SquadPersonArgs[] ---@return Widget|Html|string? function SquadAuto:display(entries) if Logic.isEmpty(entries) then @@ -222,12 +222,12 @@ function SquadAuto:display(entries) return SquadCustom.runAuto(entries, self.config.status, self.config.type, self.config.title) end ----@param entries SquadAutoPerson[] +---@param entries SquadPersonArgs[] ---@return Widget|Html|string? function SquadAuto:displayTabs(entries) local _, groupedEntries = Array.groupBy( entries, - ---@param entry SquadAutoPerson + ---@param entry SquadPersonArgs function (entry) return entry.leavedate:match('(%d%d%d%d)') end @@ -264,9 +264,9 @@ function SquadAuto:displayTabs(entries) return Tabs.dynamic(tabs) end ----@param entry SquadAutoPerson +---@param entry SquadPersonArgs function SquadAuto:enrichEntry(entry) - local pagename = Page.pageifyLink(entry.page) + local pagename = Page.pageifyLink(entry.link) local enrichment = self.enrichmentInfo[pagename] if enrichment then Table.mergeInto(entry, enrichment) @@ -275,23 +275,22 @@ function SquadAuto:enrichEntry(entry) local personInfo = mw.ext.LiquipediaDB.lpdb('player', { conditions = '[[pagename::' .. pagename .. ']]', limit = 1, - query = 'pagename, nationality, id, name, localizedname, extradata' + query = 'pagename, nationality, id, name, extradata' })[1] if personInfo then entry.id = Logic.nilIfEmpty(entry.id) or personInfo.id entry.flag = Logic.nilIfEmpty(entry.flag) or personInfo.nationality entry.name = Logic.nilIfEmpty(entry.name) or personInfo.name - entry.localizedname = Logic.nilIfEmpty(entry.localizedname) or personInfo.localizedname end --TODO: Captain from pagevar set in infobox? end ----@return SquadAutoPerson[] manualPersons +---@return SquadPersonArgs[] manualPersons ---@return table enrichmentInfo function SquadAuto:readManualRowInput() - ---@type SquadAutoPerson[] + ---@type SquadPersonArgs[] local persons = {} local enrichmentInfo = {} @@ -302,43 +301,43 @@ function SquadAuto:readManualRowInput() return end - local page = Page.pageifyLink(person.link or person.id or person.name) - assert(page, 'Missing identifier or link for SquadAutoRow ' .. entry) + local link = Page.pageifyLink(person.link or person.id or person.name) + assert(link, 'Missing identifier or link for SquadAutoRow ' .. entry) if self.config.type == SquadUtils.SquadType.STAFF and Logic.isNotEmpty(person.role) then -- Only allow manual entries for STAFF (organization) tables - table.insert(persons, { - page = page, - id = person.id, - captain = Logic.readBoolOrNil(person.captain), + ---@type SquadPersonArgs + local manualPerson = { name = person.name, - localizedname = person.localizedname, - thisTeam = { - team = self.config.team, - role = person.role, - position = person.position - }, - newTeam = { - team = person.newteam, - role = person.newteamrole, - person.newteamdate - }, + id = person.id, + link = link, flag = person.flag, - oldTeam = { - team = person.oldteam - }, - joindate = (person.joindate or ''):gsub('%?%?','01'), - joindatedisplay = person.joindate, - joindateRef = {}, - leavedate = (person.leavedate or ''):gsub('%?%?','01'), - leavedatedisplay = person.leavedate, - leavedateRef = {}, + position = person.position, + role = person.role, + captain = person.captain, + + newteam = person.newteam, + newrole = person.newteamrole, + + joindate = person.joindate, + leavedate = person.leavedate, + inactivedate = person.inactivedate, + team = person.role == 'Loan' and person.oldteam or nil, + + -- TODO: (Supported by Squad) + -- status + -- type + -- teamrole + -- newteamrole + -- newteamdate + faction = person.faction or person.race, race = person.faction or person.race, - }) + } + table.insert(persons, manualPerson) else -- For PLAYER tables, or when no role is given: Treat as override - enrichmentInfo[page] = { + enrichmentInfo[link] = { id = person.id, captain = Logic.readBoolOrNil(person.captain), name = person.name, @@ -501,7 +500,7 @@ function SquadAuto:buildConditions() return conditions:toString() end ----@return SquadAutoPerson[] +---@return SquadPersonArgs[] function SquadAuto:selectEntries() return Array.filter( Array.extend( @@ -511,19 +510,19 @@ function SquadAuto:selectEntries() ), self.manualPlayers ), - ---@param entry SquadAutoPerson + ---@param entry SquadPersonArgs function(entry) local result = ( Logic.isEmpty(self.config.roles.included) or Array.any( self.config.roles.included, - FnUtil.curry(Operator.eq, entry.thisTeam.role) + FnUtil.curry(Operator.eq, entry.role) ) ) and ( Logic.isEmpty(self.config.roles.excluded) or Array.all( self.config.roles.excluded, - FnUtil.curry(Operator.neq, entry.thisTeam.role) + FnUtil.curry(Operator.neq, entry.role) ) ) @@ -538,7 +537,7 @@ end ---If the status is former(_inactive), there might be multiple entries returned ---If the type does not match, no entries are returned ---@param entries TeamHistoryEntry[] ----@return SquadAutoPerson[] +---@return SquadPersonArgs[] function SquadAuto:_selectHistoryEntries(entries) -- Select entries to match status if self.config.status == SquadUtils.SquadStatus.ACTIVE then @@ -547,14 +546,14 @@ function SquadAuto:_selectHistoryEntries(entries) if last.type == SquadAuto.TransferType.CHANGE or last.type == SquadAuto.TransferType.JOIN then -- When the last transfer is a leave transfer, the person wouldn't be active - return {self:_mapToSquadAutoPerson(last)} + return {self:_mapToSquadPerson(last)} end end if self.config.status == SquadUtils.SquadStatus.INACTIVE then local last, secondToLast = entries[#entries], entries[#entries - 1] if secondToLast and last.type == SquadAuto.TransferType.CHANGE and last.toRole == ROLE_INACTIVE then - return {self:_mapToSquadAutoPerson(secondToLast, last)} + return {self:_mapToSquadPerson(secondToLast, last)} end end @@ -575,7 +574,7 @@ function SquadAuto:_selectHistoryEntries(entries) return end - table.insert(history, self:_mapToSquadAutoPerson(currentEntry, entry)) + table.insert(history, self:_mapToSquadPerson(currentEntry, entry)) if entry.type == SquadAuto.TransferType.CHANGE then currentEntry = entry else @@ -591,16 +590,25 @@ end ---Maps one or a pair of TeamHistoryEntries to a single SquadAutoPerson ---@param joinEntry TeamHistoryEntry +---@param inactiveEntry TeamHistoryEntry | nil ---@param leaveEntry TeamHistoryEntry | nil ----@return SquadAutoPerson -function SquadAuto:_mapToSquadAutoPerson(joinEntry, leaveEntry) +---@return SquadPersonArgs +function SquadAuto:_mapToSquadPerson(joinEntry, inactiveEntry, leaveEntry) leaveEntry = leaveEntry or {} - ---@type SquadAutoPerson - local entry = { - page = joinEntry.pagename, + ---@type SquadPersonArgs + local entry = { id = leaveEntry.displayname or joinEntry.displayname, + link = joinEntry.pagename, flag = joinEntry.flag, + + position = joinEntry.position, + role = joinEntry.toRole, + + newteam = leaveEntry.toTeam, + newteamrole = leaveEntry.toRole, + newteamdate = leaveEntry.date, + joindate = joinEntry.date, joindatedisplay = joinEntry.dateDisplay, joindateRef = joinEntry.references, diff --git a/lua/wikis/commons/Squad/Utils.lua b/lua/wikis/commons/Squad/Utils.lua index 47d5fdc007e..2a1158e35cf 100644 --- a/lua/wikis/commons/Squad/Utils.lua +++ b/lua/wikis/commons/Squad/Utils.lua @@ -132,6 +132,12 @@ end ---@param player SquadAutoPerson ---@return SquadPersonArgs function SquadUtils.convertAutoParameters(player) + if Info.config.squads.standardizedAuto then + -- Temporary until all wikis have enabled the new version of automated squads + ---@diagnostic disable-next-line: return-type-mismatch + return player + end + local newPlayer = Table.copy(player) local joinReference = TransferRefs.useReferences(player.joindateRef, player.joindate) local leaveReference = TransferRefs.useReferences(player.leavedateRef, player.leavedate) @@ -164,7 +170,7 @@ end ---@field igl string? ---@field newteam string? ---@field newteamrole string? ----@field newrole string? +---@field newrole string? -- Alternative to newteamrole ---@field joindate string? ---@field leavedate string? ---@field inactivedate string? From 25ad42cf14d643d7dca1ce18c03737d019e0b837 Mon Sep 17 00:00:00 2001 From: mbergen Date: Sun, 24 May 2026 15:40:25 +0200 Subject: [PATCH 34/50] Further conversion to SquadPersonArgs --- lua/wikis/commons/Squad/Auto.lua | 78 ++++++++++++++++--------------- lua/wikis/commons/Squad/Utils.lua | 41 ++++++++++------ 2 files changed, 67 insertions(+), 52 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 5bd5bd450f9..8d0c63745e6 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -18,9 +18,11 @@ local Lpdb = Lua.import('Module:Lpdb') local Operator = Lua.import('Module:Operator') local Page = Lua.import('Module:Page') local PageVariableNamespace = Lua.import('Module:PageVariableNamespace') +local String = Lua.import('Module:StringUtils') local Table = Lua.import('Module:Table') local Tabs = Lua.import('Module:Tabs') local TeamTemplate = Lua.import('Module:TeamTemplate') +local TransferRefs = Lua.import('Module:Transfer/References') local SquadUtils = Lua.import('Module:Squad/Utils') local SquadCustom = Lua.import('Module:Squad/Custom') @@ -594,10 +596,20 @@ end ---@param leaveEntry TeamHistoryEntry | nil ---@return SquadPersonArgs function SquadAuto:_mapToSquadPerson(joinEntry, inactiveEntry, leaveEntry) + inactiveEntry = inactiveEntry or {} leaveEntry = leaveEntry or {} + local joinReference = TransferRefs.useReferences(joinEntry.references, joinEntry.date) + local inactiveReference = TransferRefs.useReferences(inactiveEntry.references, inactiveEntry.date) + local leaveReference = TransferRefs.useReferences(leaveEntry.references, leaveEntry.date) + + local joindate = (joinEntry.dateDisplay or joinEntry.date) .. ' ' .. joinReference + local inactivedate = (inactiveEntry.dateDisplay or inactiveEntry.date) .. ' ' .. inactiveReference + local leavedate = (leaveEntry.dateDisplay or leaveEntry.date) .. ' ' .. leaveReference + ---@type SquadPersonArgs local entry = { + -- name id = leaveEntry.displayname or joinEntry.displayname, link = joinEntry.pagename, flag = joinEntry.flag, @@ -609,60 +621,52 @@ function SquadAuto:_mapToSquadPerson(joinEntry, inactiveEntry, leaveEntry) newteamrole = leaveEntry.toRole, newteamdate = leaveEntry.date, - joindate = joinEntry.date, - joindatedisplay = joinEntry.dateDisplay, - joindateRef = joinEntry.references, + joindate = joindate, + joindateref = joinEntry.references, - idleavedate = leaveEntry.displayname, - leavedate = leaveEntry.date, - leavedatedisplay = leaveEntry.dateDisplay or '', - leavedateRef = leaveEntry.references, + inactivedate = String.nilIfEmpty(inactivedate), + inactivedateref = inactiveEntry.references, - thisTeam = { - team = joinEntry.toTeam, - role = joinEntry.toRole, - position = joinEntry.position - }, - oldTeam = { - team = joinEntry.fromTeam, - role = joinEntry.fromRole, - }, - newTeam = { - team = leaveEntry.toTeam, - role = leaveEntry.toRole, - }, + leavedate = String.nilIfEmpty(leavedate), + leavedateref = leaveEntry.references, + + -- Injected in SquadController.execute: + -- status + -- type + + -- Used as loanedto, loanedtorole: + team = joinEntry.toRole == 'Loan' and joinEntry.fromTeam or nil, + teamrole = joinEntry.fromRole, + + -- TODO: Fill for current-inactive transfers + -- activeteam, + -- activeteamrole, -- From legacy: Prefer faction information from leaveEntry faction = leaveEntry.faction or joinEntry.faction, race = leaveEntry.faction or joinEntry.faction + -- game, } -- On leave: Fetch the next team a person joined - if Logic.isNotEmpty(leaveEntry) and Logic.isEmpty(entry.newTeam.team) then - local newTeam, newRole = SquadAuto._fetchNextTeam(joinEntry.pagename, leaveEntry.date) + if Logic.isNotEmpty(leaveEntry) and Logic.isEmpty(entry.newteam) then + local newTeam, newRole, newDate = SquadAuto._fetchNextTeam(joinEntry.pagename, leaveEntry.date) if newTeam then - entry.newTeam.team = newTeam - entry.newTeam.role = newRole + entry.newteam = newTeam + entry.newteamrole = newRole + entry.newteamdate = newDate end end - -- Special case: Person went inactive. - -- Set thisTeam.role to inactive and remove newTeam.role, - -- otherwise Squad doesn't display the entries - if self.config.status == SquadUtils.SquadStatus.INACTIVE - and leaveEntry.toRole == 'Inactive' then - entry.thisTeam.role = entry.newTeam.role - entry.newTeam.role = '' - end - return entry end ---Fetches the next team a person joined after a given date ---@param pagename string ---@param date string ----@return string? ----@return string? +---@return string? newTeam +---@return string? newRole +---@return string? newDate function SquadAuto._fetchNextTeam(pagename, date) local conditions = Condition.Tree(BooleanOperator.all) :add{ @@ -675,12 +679,12 @@ function SquadAuto._fetchNextTeam(pagename, date) conditions = conditions:toString(), limit = 1, order = 'date asc, objectname desc', - query = 'toteamtemplate, role2' + query = 'toteamtemplate, role2, date' })[1] or {} -- TODO: (Optional) Check if fetched transfer is in fact a join transfer (empty fromTeam)? - return transfer.toteamtemplate, transfer.role2 + return transfer.toteamtemplate, transfer.role2, transfer.date end ---Sorts a list of SquadAutoPersons diff --git a/lua/wikis/commons/Squad/Utils.lua b/lua/wikis/commons/Squad/Utils.lua index 2a1158e35cf..bc22f2f9143 100644 --- a/lua/wikis/commons/Squad/Utils.lua +++ b/lua/wikis/commons/Squad/Utils.lua @@ -129,15 +129,17 @@ function SquadUtils.readWrapperArgs(args) return SquadUtils.createWrapperData(players, squadType, squadStatus, args.title, args) end ----@param player SquadAutoPerson +---@param player SquadAutoPerson|SquadPersonArgs ---@return SquadPersonArgs function SquadUtils.convertAutoParameters(player) if Info.config.squads.standardizedAuto then -- Temporary until all wikis have enabled the new version of automated squads - ---@diagnostic disable-next-line: return-type-mismatch + ---@cast player -SquadAutoPerson return player end + ---@cast player -SquadPersonArgs + ---@type SquadPersonArgs local newPlayer = Table.copy(player) local joinReference = TransferRefs.useReferences(player.joindateRef, player.joindate) local leaveReference = TransferRefs.useReferences(player.leavedateRef, player.leavedate) @@ -160,27 +162,33 @@ function SquadUtils.convertAutoParameters(player) end ---@class SquadPersonArgs ----@field name string? ----@field id string? ----@field link string? +---@field name string? Real name +---@field id string? Display name +---@field link string? Page name ---@field flag string? ---@field position string? ---@field role string? ----@field captain string? ----@field igl string? ----@field newteam string? +---@field captain string? Truthy, only when role is empty +---@field igl string? Truthy, alternative to captain +---@field newteam string? as team template ---@field newteamrole string? ---@field newrole string? -- Alternative to newteamrole ----@field joindate string? ----@field leavedate string? ----@field inactivedate string? ----@field status string? ----@field type string? ----@field team string? ----@field teamrole string? +---@field joindate string? including reference +---@field leavedate string? including reference +---@field inactivedate string? including reference +---@field status SquadStatus? +---@field type SquadStatus? +---@field team string? as loanedto +---@field teamrole string? as loanedtorole ---@field newteamdate string? ---@field faction string? ---@field race string? +---@field activeteam string? +---@field activeteamrole string? +---@field game game? +---@field joindateref table? +---@field leavedateref table? +---@field inactivedateref table? ---@param args SquadPersonArgs ---@return ModelRow @@ -213,8 +221,11 @@ function SquadUtils.readSquadPersonArgs(args) newteamtemplate = getTeamInfo(args.newteam, 'templatename'), joindate = ReferenceCleaner.clean{input = args.joindate}, + joindateref = args.joindateref, leavedate = ReferenceCleaner.clean{input = args.leavedate}, + leavedateref = args.leavedateref, inactivedate = ReferenceCleaner.clean{input = args.inactivedate}, + inactivedateref = args.inactivedateref, status = SquadUtils.SquadStatusToStorageValue[args.status], type = SquadUtils.SquadTypeToStorageValue[args.type], From 8bc9f24c93c6e46a08f740e85ae9314b92d05856 Mon Sep 17 00:00:00 2001 From: mbergen Date: Sun, 24 May 2026 15:45:32 +0200 Subject: [PATCH 35/50] Fix references --- lua/wikis/commons/Squad/Auto.lua | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 8d0c63745e6..5d9ebff2692 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -603,9 +603,14 @@ function SquadAuto:_mapToSquadPerson(joinEntry, inactiveEntry, leaveEntry) local inactiveReference = TransferRefs.useReferences(inactiveEntry.references, inactiveEntry.date) local leaveReference = TransferRefs.useReferences(leaveEntry.references, leaveEntry.date) - local joindate = (joinEntry.dateDisplay or joinEntry.date) .. ' ' .. joinReference - local inactivedate = (inactiveEntry.dateDisplay or inactiveEntry.date) .. ' ' .. inactiveReference - local leavedate = (leaveEntry.dateDisplay or leaveEntry.date) .. ' ' .. leaveReference + + local function attachReference(entry, reference) + return (entry.dateDisplay or entry.date or '') .. ' ' .. reference + end + + local joindate = attachReference(joinEntry, joinReference) + local inactivedate = attachReference(inactiveEntry, inactiveReference) + local leavedate = attachReference(leaveEntry, leaveReference) ---@type SquadPersonArgs local entry = { @@ -690,14 +695,14 @@ end ---Sorts a list of SquadAutoPersons -- Active entries (no leavedate) sorted by joindate, -- Former entries sorted by leavedate ----@param entries SquadAutoPerson[] +---@param entries SquadPersonArgs[] ---@param useRankSort boolean? ---@return SquadAutoPerson[] function SquadAuto._sortEntries(entries, useRankSort) return Array.sortBy(entries, function (element) return { - useRankSort and SquadAutoRank[element.thisTeam.position] or SquadAutoRank[DEFAULT_RANK_KEY], - useRankSort and SquadAutoRank[element.thisTeam.role] or SquadAutoRank[DEFAULT_RANK_KEY], + useRankSort and SquadAutoRank[element.position] or SquadAutoRank[DEFAULT_RANK_KEY], + useRankSort and SquadAutoRank[element.role] or SquadAutoRank[DEFAULT_RANK_KEY], element.leavedate or element.joindate, element.id } From 5a147822d61c88f805256371ffd46c6998b4d65c Mon Sep 17 00:00:00 2001 From: mbergen Date: Sun, 24 May 2026 16:27:04 +0200 Subject: [PATCH 36/50] Correctly determine entries for mapping --- lua/wikis/commons/Squad/Auto.lua | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 5d9ebff2692..da1669aac37 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -562,12 +562,12 @@ function SquadAuto:_selectHistoryEntries(entries) if self.config.status == SquadUtils.SquadStatus.FORMER then local history = {} - local currentEntry = nil + local joinEntry, changeEntry Array.forEach(entries, function (entry) - if not currentEntry then + if not joinEntry then if entry.type == SquadAuto.TransferType.JOIN then - currentEntry = entry + joinEntry = entry else mw.log('Invalid transfer history for player ' .. entry.pagename) mw.logObject(entry, 'Invalid entry: Missing previous JOIN. Skipping') @@ -576,11 +576,14 @@ function SquadAuto:_selectHistoryEntries(entries) return end - table.insert(history, self:_mapToSquadPerson(currentEntry, entry)) - if entry.type == SquadAuto.TransferType.CHANGE then - currentEntry = entry + if entry.type == SquadAuto.TransferType.CHANGE and entry.toRole == ROLE_INACTIVE then + if not changeEntry then + changeEntry = entry + end else - currentEntry = nil + table.insert(history, self:_mapToSquadPerson(joinEntry, changeEntry, entry)) + joinEntry = nil + changeEntry = nil end end) From dbff97648e1f5def0de9ddb344008f715dbcf923 Mon Sep 17 00:00:00 2001 From: mbergen Date: Sun, 24 May 2026 19:51:45 +0200 Subject: [PATCH 37/50] Fix grouping for status --- lua/wikis/commons/Squad/Auto.lua | 45 ++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index da1669aac37..c0558449895 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -214,7 +214,8 @@ function SquadAuto:display(entries) return end - if self.config.status == SquadUtils.SquadStatus.FORMER then + if self.config.status == SquadUtils.SquadStatus.FORMER + or self.config.status == SquadUtils.SquadStatus.FORMER_INACTIVE then return self:displayTabs(entries) end @@ -559,31 +560,43 @@ function SquadAuto:_selectHistoryEntries(entries) end end - if self.config.status == SquadUtils.SquadStatus.FORMER then + if self.config.status == SquadUtils.SquadStatus.FORMER + or self.config.status == SquadUtils.SquadStatus.FORMER_INACTIVE then local history = {} - local joinEntry, changeEntry + local joinEntry, inactiveEntry Array.forEach(entries, function (entry) - if not joinEntry then - if entry.type == SquadAuto.TransferType.JOIN then - joinEntry = entry - else + if entry.type == SquadAuto.TransferType.JOIN then + if joinEntry then mw.log('Invalid transfer history for player ' .. entry.pagename) - mw.logObject(entry, 'Invalid entry: Missing previous JOIN. Skipping') + mw.logObject(entry, 'Invalid entry: Duplicate JOIN. Skipping') mw.ext.TeamLiquidIntegration.add_category('SquadAuto with invalid player history') + return end + joinEntry = entry + return + end + if not joinEntry then + mw.log('Invalid transfer history for player ' .. entry.pagename) + mw.logObject(entry, 'Invalid entry: Missing previous JOIN. Skipping') + mw.ext.TeamLiquidIntegration.add_category('SquadAuto with invalid player history') return end if entry.type == SquadAuto.TransferType.CHANGE and entry.toRole == ROLE_INACTIVE then - if not changeEntry then - changeEntry = entry - end - else - table.insert(history, self:_mapToSquadPerson(joinEntry, changeEntry, entry)) - joinEntry = nil - changeEntry = nil + -- FORMER_INACTIVE enables the Inactive Date display + self.config.status = SquadUtils.SquadStatus.FORMER_INACTIVE + inactiveEntry = entry + return + end + + table.insert(history, self:_mapToSquadPerson(joinEntry, inactiveEntry, entry)) + joinEntry = nil + inactiveEntry = nil + + if entry.type == SquadAuto.TransferType.CHANGE then + joinEntry = entry end end) @@ -690,8 +703,6 @@ function SquadAuto._fetchNextTeam(pagename, date) query = 'toteamtemplate, role2, date' })[1] or {} - -- TODO: (Optional) Check if fetched transfer is in fact a join transfer (empty fromTeam)? - return transfer.toteamtemplate, transfer.role2, transfer.date end From dbf89e671170308080da87cbba66a9920ac371e9 Mon Sep 17 00:00:00 2001 From: mbergen Date: Sun, 24 May 2026 19:56:14 +0200 Subject: [PATCH 38/50] Fix sort --- lua/wikis/commons/Squad/Auto.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index c0558449895..b08bdc7770a 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -717,7 +717,7 @@ function SquadAuto._sortEntries(entries, useRankSort) return { useRankSort and SquadAutoRank[element.position] or SquadAutoRank[DEFAULT_RANK_KEY], useRankSort and SquadAutoRank[element.role] or SquadAutoRank[DEFAULT_RANK_KEY], - element.leavedate or element.joindate, + element.leavedate or element.joindate or '', element.id } end) From 55037b159b82aac0dbf773e81b0ea494d1d37186 Mon Sep 17 00:00:00 2001 From: mbergen Date: Sun, 24 May 2026 20:10:57 +0200 Subject: [PATCH 39/50] Use RoleUtil to determine where player belongs --- lua/wikis/commons/Squad/Auto.lua | 42 +++++++------------------------- 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index b08bdc7770a..61708c69ebf 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -18,6 +18,7 @@ local Lpdb = Lua.import('Module:Lpdb') local Operator = Lua.import('Module:Operator') local Page = Lua.import('Module:Page') local PageVariableNamespace = Lua.import('Module:PageVariableNamespace') +local RoleUtil = Lua.import('Module:Role/Util') local String = Lua.import('Module:StringUtils') local Table = Lua.import('Module:Table') local Tabs = Lua.import('Module:Tabs') @@ -78,7 +79,6 @@ end) ---@field type SquadType ---@field title string? ---@field teams string[]? ----@field roles {excluded: string[]?, included: string[]?} ---@enum TransferType SquadAuto.TransferType = { @@ -171,19 +171,7 @@ function SquadAuto:parseConfig() team = args.team or mw.title.getCurrentTitle().text, type = type, status = status, - title = args.title, - roles = { - included = Logic.emptyOr( - Array.parseCommaSeparatedString(args.roles), - DEFAULT_INCLUDED_ROLES[type][status], - DEFAULT_INCLUDED_ROLES[type].DEFAULT - ), - excluded = Logic.emptyOr( - Array.parseCommaSeparatedString(args.not_roles), - DEFAULT_EXCLUDED_ROLES[type][status], - DEFAULT_EXCLUDED_ROLES[type].DEFAULT - ) - } + title = args.title } self.manualPlayers, self.enrichmentInfo = self:readManualRowInput() @@ -201,10 +189,6 @@ function SquadAuto:parseConfig() if Logic.isEmpty(self.config.teams) then error(TeamTemplate.noTeamMessage(self.config.team)) end - - if self.config.status == SquadUtils.SquadStatus.FORMER_INACTIVE then - error('SquadStatus \'FORMER_INACTIVE\' is not supported by SquadAuto.') - end end ---@param entries SquadPersonArgs[] @@ -515,21 +499,13 @@ function SquadAuto:selectEntries() ), ---@param entry SquadPersonArgs function(entry) - local result = ( - Logic.isEmpty(self.config.roles.included) - or Array.any( - self.config.roles.included, - FnUtil.curry(Operator.eq, entry.role) - ) - ) and ( - Logic.isEmpty(self.config.roles.excluded) - or Array.all( - self.config.roles.excluded, - FnUtil.curry(Operator.neq, entry.role) - ) - ) - - return result + local roles = RoleUtil.readRoleArgs(table.concat({entry.role, entry.position}, ',')) + local hasStaffRoles = Array.any(roles, function(role) return role.type == RoleUtil.ROLE_TYPE.STAFF end) + + if hasStaffRoles then + return self.config.type == SquadUtils.SquadType.STAFF + end + return self.config.type == SquadUtils.SquadType.PLAYER end ) end From 85374f6fa286c98d18426528dafd629dd478c28d Mon Sep 17 00:00:00 2001 From: mbergen Date: Sun, 24 May 2026 20:25:44 +0200 Subject: [PATCH 40/50] Fix role-based selection, remove leftover config --- lua/wikis/commons/Squad/Auto.lua | 53 +++++++++----------------------- 1 file changed, 15 insertions(+), 38 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 61708c69ebf..62c4857c5d2 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -114,40 +114,6 @@ local DEFAULT_RANK_KEY = '' local ROLE_INACTIVE = 'Inactive' --- TODO: Replace with Module:Roles -local ROLES_PLAYER = { - '', - 'Loan', - 'Substitute', - 'Trial', - 'Stand-in', - 'Uncontracted' -} - -local DEFAULT_INCLUDED_ROLES = { - [SquadUtils.SquadType.PLAYER] = { - DEFAULT = ROLES_PLAYER, - [SquadUtils.SquadStatus.INACTIVE] = { - ROLE_INACTIVE - }, - [SquadUtils.SquadStatus.FORMER] = Array.extend( - ROLES_PLAYER, - ROLE_INACTIVE - ), - }, - [SquadUtils.SquadType.STAFF] = {}, -} - -local DEFAULT_EXCLUDED_ROLES = { - [SquadUtils.SquadType.PLAYER] = {}, - [SquadUtils.SquadType.STAFF] = { - DEFAULT = Array.extend( - ROLES_PLAYER, - ROLE_INACTIVE - ), - }, -} - ---Entrypoint for SquadAuto tables ---@param frame Frame|table ---@return Widget|Html|string? @@ -497,15 +463,26 @@ function SquadAuto:selectEntries() ), self.manualPlayers ), + --- Selects the appropriate entries based on the role. ---@param entry SquadPersonArgs function(entry) local roles = RoleUtil.readRoleArgs(table.concat({entry.role, entry.position}, ',')) - local hasStaffRoles = Array.any(roles, function(role) return role.type == RoleUtil.ROLE_TYPE.STAFF end) + local hasStaffRoles = Array.any(roles, function(role) + return role.type == RoleUtil.ROLE_TYPE.STAFF + or role.type == RoleUtil.ROLE_TYPE.UNKNOWN -- Unknown roles are assumed to be non-player + end) + local roleIsInactive = entry.role == ROLE_INACTIVE + + if self.config.type == SquadUtils.SquadType.STAFF then + return hasStaffRoles and not roleIsInactive + end - if hasStaffRoles then - return self.config.type == SquadUtils.SquadType.STAFF + if self.config.status == SquadUtils.SquadStatus.INACTIVE then + -- "Inactive" currently produces a false-positive hasStaffRoles + return roleIsInactive end - return self.config.type == SquadUtils.SquadType.PLAYER + + return not hasStaffRoles and not roleIsInactive end ) end From 68e32fbeaca6c057231bb633f6277450dfa49372 Mon Sep 17 00:00:00 2001 From: mbergen Date: Sun, 24 May 2026 20:28:33 +0200 Subject: [PATCH 41/50] Remove unused types --- lua/wikis/commons/Squad/Auto.lua | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index 62c4857c5d2..cbf2d615dee 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -51,28 +51,6 @@ end) ---@field position string? ---@field date string? ----@class SquadAutoBase ----@field id string ----@field flag string? ----@field page string ----@field name string? ----@field localizedname string? ----@field faction string? ----@field captain boolean? - ----TODO: Unify with SquadPerson ----@class SquadAutoPerson: SquadAutoBase ----@field idleavedate string? ----@field thisTeam SquadAutoTeam ----@field oldTeam SquadAutoTeam? ----@field newTeam SquadAutoTeam? ----@field joindate string ----@field joindatedisplay string? ----@field joindateRef table? ----@field leavedate string? ----@field leavedatedisplay string ----@field leavedateRef table? - ---@class SquadAutoConfig ---@field team string ---@field status SquadStatus @@ -241,7 +219,7 @@ function SquadAuto:enrichEntry(entry) end ---@return SquadPersonArgs[] manualPersons ----@return table enrichmentInfo +---@return table enrichmentInfo function SquadAuto:readManualRowInput() ---@type SquadPersonArgs[] local persons = {} @@ -278,8 +256,6 @@ function SquadAuto:readManualRowInput() team = person.role == 'Loan' and person.oldteam or nil, -- TODO: (Supported by Squad) - -- status - -- type -- teamrole -- newteamrole -- newteamdate @@ -294,7 +270,6 @@ function SquadAuto:readManualRowInput() id = person.id, captain = Logic.readBoolOrNil(person.captain), name = person.name, - localizedname = person.localizedname, flag = person.flag, faction = person.faction or person.race, } From 09b8197e1acc4ab4e318f9e29a2fdf81fb741c61 Mon Sep 17 00:00:00 2001 From: mbergen Date: Sun, 24 May 2026 20:42:40 +0200 Subject: [PATCH 42/50] Improve handling of inactive role --- lua/wikis/commons/Squad/Auto.lua | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index cbf2d615dee..f7aca6fb03d 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -441,23 +441,25 @@ function SquadAuto:selectEntries() --- Selects the appropriate entries based on the role. ---@param entry SquadPersonArgs function(entry) + if self.config.status == SquadUtils.SquadStatus.INACTIVE then + -- For SquadStatus.INACTIVE the entries are already preselected + -- and won't have the role set to Inactive. + -- This also matches manual Squad, where status is inactive and role can e.g. be "On Loan" + + return true + end + local roles = RoleUtil.readRoleArgs(table.concat({entry.role, entry.position}, ',')) local hasStaffRoles = Array.any(roles, function(role) return role.type == RoleUtil.ROLE_TYPE.STAFF or role.type == RoleUtil.ROLE_TYPE.UNKNOWN -- Unknown roles are assumed to be non-player end) - local roleIsInactive = entry.role == ROLE_INACTIVE if self.config.type == SquadUtils.SquadType.STAFF then - return hasStaffRoles and not roleIsInactive + return hasStaffRoles end - if self.config.status == SquadUtils.SquadStatus.INACTIVE then - -- "Inactive" currently produces a false-positive hasStaffRoles - return roleIsInactive - end - - return not hasStaffRoles and not roleIsInactive + return not hasStaffRoles end ) end @@ -474,9 +476,9 @@ function SquadAuto:_selectHistoryEntries(entries) if self.config.status == SquadUtils.SquadStatus.ACTIVE then -- Only most recent transfer is relevant local last = entries[#entries] - if last.type == SquadAuto.TransferType.CHANGE - or last.type == SquadAuto.TransferType.JOIN then - -- When the last transfer is a leave transfer, the person wouldn't be active + if (last.type == SquadAuto.TransferType.CHANGE or last.type == SquadAuto.TransferType.JOIN) + and last.toRole ~= ROLE_INACTIVE then + -- When the last transfer is a leave transfer, or the role is inactive, the person wouldn't be active return {self:_mapToSquadPerson(last)} end end @@ -634,12 +636,12 @@ function SquadAuto._fetchNextTeam(pagename, date) return transfer.toteamtemplate, transfer.role2, transfer.date end ----Sorts a list of SquadAutoPersons +---Sorts a list of SquadPersonArgs -- Active entries (no leavedate) sorted by joindate, -- Former entries sorted by leavedate ---@param entries SquadPersonArgs[] ---@param useRankSort boolean? ----@return SquadAutoPerson[] +---@return SquadPersonArgs[] function SquadAuto._sortEntries(entries, useRankSort) return Array.sortBy(entries, function (element) return { From 0aa32051c232421b3b34c6ae3c8e6ead3601e9de Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Mon, 25 May 2026 13:15:44 +0200 Subject: [PATCH 43/50] Apply suggestions from code review Co-authored-by: hjpalpha <75081997+hjpalpha@users.noreply.github.com> --- lua/wikis/commons/Squad/Auto.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index f7aca6fb03d..b97d61b661f 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -469,6 +469,7 @@ end ---If the status is (in)active, then at most one entry will be returned ---If the status is former(_inactive), there might be multiple entries returned ---If the type does not match, no entries are returned +---@private ---@param entries TeamHistoryEntry[] ---@return SquadPersonArgs[] function SquadAuto:_selectHistoryEntries(entries) @@ -537,6 +538,7 @@ function SquadAuto:_selectHistoryEntries(entries) end ---Maps one or a pair of TeamHistoryEntries to a single SquadAutoPerson +---@private ---@param joinEntry TeamHistoryEntry ---@param inactiveEntry TeamHistoryEntry | nil ---@param leaveEntry TeamHistoryEntry | nil @@ -613,6 +615,7 @@ function SquadAuto:_mapToSquadPerson(joinEntry, inactiveEntry, leaveEntry) end ---Fetches the next team a person joined after a given date +---@private ---@param pagename string ---@param date string ---@return string? newTeam @@ -639,6 +642,7 @@ end ---Sorts a list of SquadPersonArgs -- Active entries (no leavedate) sorted by joindate, -- Former entries sorted by leavedate +---@private ---@param entries SquadPersonArgs[] ---@param useRankSort boolean? ---@return SquadPersonArgs[] From 0a16d2034dc8e1bb7c063a57f8ea1da2adc56170 Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Mon, 25 May 2026 13:30:35 +0200 Subject: [PATCH 44/50] Add legacy mode to replace template invokes --- lua/wikis/commons/Squad/Auto.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index b97d61b661f..a709fa4c866 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -12,6 +12,7 @@ local Array = Lua.import('Module:Array') local Class = Lua.import('Module:Class') local Condition = Lua.import('Module:Condition') local FnUtil = Lua.import('Module:FnUtil') +local Info = Lua.import('Module:Info') local Json = Lua.import('Module:Json') local Logic = Lua.import('Module:Logic') local Lpdb = Lua.import('Module:Lpdb') @@ -96,6 +97,19 @@ local ROLE_INACTIVE = 'Inactive' ---@param frame Frame|table ---@return Widget|Html|string? function SquadAuto.run(frame) + if not Info.config.squads.standardizedAuto then + -- Legacy mode: Call old SquadAuto + local OldSquadAuto = Lua.import('Module:SquadAuto') + + local type = SquadUtils.TypeToSquadType[(frame.args.type or ''):lower()] + if type == SquadUtils.SquadType.STAFF then + -- Old module needs special type argument for organization tables + frame.args.type = 'Organization_' .. frame.args.status + end + + return OldSquadAuto[frame.args.status](frame) + end + local autosquad = SquadAuto(frame) autosquad:parseConfig() autosquad:queryTransfers() From de1cbf43ab782b56a62959d7fd6234e254c91e31 Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Mon, 25 May 2026 13:35:14 +0200 Subject: [PATCH 45/50] Remove change to info module --- lua/wikis/ageofempires/Info.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/wikis/ageofempires/Info.lua b/lua/wikis/ageofempires/Info.lua index 24652158dd4..3d95d0ef309 100644 --- a/lua/wikis/ageofempires/Info.lua +++ b/lua/wikis/ageofempires/Info.lua @@ -103,7 +103,6 @@ return { hasPosition = false, hasSpecialTeam = false, allowManual = true, - standardizedAuto = true, }, match2 = { status = 2, From 689ff92bc8ae4fa0e1490031a16bdaea564f847e Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Mon, 25 May 2026 13:56:31 +0200 Subject: [PATCH 46/50] Set type for legacy call --- lua/wikis/commons/Squad/Auto.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index a709fa4c866..c80a83050e2 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -102,9 +102,11 @@ function SquadAuto.run(frame) local OldSquadAuto = Lua.import('Module:SquadAuto') local type = SquadUtils.TypeToSquadType[(frame.args.type or ''):lower()] + -- Old module needs special type argument if type == SquadUtils.SquadType.STAFF then - -- Old module needs special type argument for organization tables frame.args.type = 'Organization_' .. frame.args.status + else + frame.args.type = 'Player_' .. frame.args.status end return OldSquadAuto[frame.args.status](frame) From 5f766ce4dc61761eb5d10ab4639ce7b767d906d2 Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Mon, 25 May 2026 14:08:23 +0200 Subject: [PATCH 47/50] Improve annotations --- lua/wikis/commons/Squad/Auto.lua | 43 ++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index c80a83050e2..e8cb80bcfa6 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -95,7 +95,7 @@ local ROLE_INACTIVE = 'Inactive' ---Entrypoint for SquadAuto tables ---@param frame Frame|table ----@return Widget|Html|string? +---@return Renderable? function SquadAuto.run(frame) if not Info.config.squads.standardizedAuto then -- Legacy mode: Call old SquadAuto @@ -113,17 +113,21 @@ function SquadAuto.run(frame) end local autosquad = SquadAuto(frame) - autosquad:parseConfig() - autosquad:queryTransfers() - - local entries = autosquad:selectEntries() - Array.forEach(entries, FnUtil.curry(SquadAuto.enrichEntry, autosquad)) + autosquad:build() + return autosquad:display() +end - return autosquad:display(entries) +---Handles all necessary steps to fetch and sort data +function SquadAuto:build() + self:_parseConfig() + self:_queryTransfers() + local entries = self:_selectEntries() + Array.forEach(entries, FnUtil.curry(SquadAuto._enrichEntry, self)) end ---Parses the args into a SquadAutoConfig -function SquadAuto:parseConfig() +---@private +function SquadAuto:_parseConfig() local args = self.args local type = SquadUtils.TypeToSquadType[(args.type or ''):lower()] local status = SquadUtils.StatusToSquadStatus[(args.status or ''):lower()] @@ -134,7 +138,7 @@ function SquadAuto:parseConfig() title = args.title } - self.manualPlayers, self.enrichmentInfo = self:readManualRowInput() + self.manualPlayers, self.enrichmentInfo = self:_readManualRowInput() -- Override default 'Former Squad' title if status == SquadUtils.SquadStatus.FORMER @@ -169,6 +173,7 @@ function SquadAuto:display(entries) return SquadCustom.runAuto(entries, self.config.status, self.config.type, self.config.title) end +---@private ---@param entries SquadPersonArgs[] ---@return Widget|Html|string? function SquadAuto:displayTabs(entries) @@ -190,7 +195,7 @@ function SquadAuto:displayTabs(entries) ) end - ---@type table + ---@type table local tabs = { This = tabCount, removeEmptyTabs = true @@ -211,8 +216,9 @@ function SquadAuto:displayTabs(entries) return Tabs.dynamic(tabs) end +---@private ---@param entry SquadPersonArgs -function SquadAuto:enrichEntry(entry) +function SquadAuto:_enrichEntry(entry) local pagename = Page.pageifyLink(entry.link) local enrichment = self.enrichmentInfo[pagename] if enrichment then @@ -234,9 +240,10 @@ function SquadAuto:enrichEntry(entry) --TODO: Captain from pagevar set in infobox? end +---@private ---@return SquadPersonArgs[] manualPersons ---@return table enrichmentInfo -function SquadAuto:readManualRowInput() +function SquadAuto:_readManualRowInput() ---@type SquadPersonArgs[] local persons = {} local enrichmentInfo = {} @@ -295,7 +302,8 @@ function SquadAuto:readManualRowInput() return persons, enrichmentInfo end -function SquadAuto:queryTransfers() +---@private +function SquadAuto:_queryTransfers() ---Checks whether a given team is the currently queried team ---@param team string? ---@return boolean @@ -367,7 +375,7 @@ function SquadAuto:queryTransfers() Lpdb.executeMassQuery( 'transfer', { - conditions = self:buildConditions(), + conditions = self:_buildConditions(), order = 'date asc, objectname desc', limit = 5000 }, @@ -429,8 +437,9 @@ end ---Builds the conditions to fetch all transfers related ---to the given team, respecting historical templates. +---@private ---@return string -function SquadAuto:buildConditions() +function SquadAuto:_buildConditions() local conditions = Condition.Tree(BooleanOperator.any) Array.forEach(self.config.teams, function (templatename) conditions:add{ @@ -444,8 +453,9 @@ function SquadAuto:buildConditions() return conditions:toString() end +---@private ---@return SquadPersonArgs[] -function SquadAuto:selectEntries() +function SquadAuto:_selectEntries() return Array.filter( Array.extend( Array.flatMap( @@ -456,6 +466,7 @@ function SquadAuto:selectEntries() ), --- Selects the appropriate entries based on the role. ---@param entry SquadPersonArgs + ---@return boolean function(entry) if self.config.status == SquadUtils.SquadStatus.INACTIVE then -- For SquadStatus.INACTIVE the entries are already preselected From e2d56634d107f86b2b163429604da6194a7b5ed3 Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Mon, 25 May 2026 14:27:44 +0200 Subject: [PATCH 48/50] Use RoleData.sortOrder --- lua/wikis/commons/Squad/Auto.lua | 62 ++++++++++++++++---------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/lua/wikis/commons/Squad/Auto.lua b/lua/wikis/commons/Squad/Auto.lua index e8cb80bcfa6..462877e5bd8 100644 --- a/lua/wikis/commons/Squad/Auto.lua +++ b/lua/wikis/commons/Squad/Auto.lua @@ -29,8 +29,6 @@ local TransferRefs = Lua.import('Module:Transfer/References') local SquadUtils = Lua.import('Module:Squad/Utils') local SquadCustom = Lua.import('Module:Squad/Custom') -local SquadAutoRank = Lua.import('Module:SquadAuto/rank', {loadData=true}) - local BooleanOperator = Condition.BooleanOperator local Comparator = Condition.Comparator @@ -46,12 +44,6 @@ local SquadAuto = Class.new(nil, function (self, frame) self.args = Arguments.getArgs(frame) end) ----@class SquadAutoTeam ----@field team string ----@field role string? ----@field position string? ----@field date string? - ---@class SquadAutoConfig ---@field team string ---@field status SquadStatus @@ -82,14 +74,16 @@ SquadAuto.TransferType = { ---@field toRole string? ---@field faction string? +---@class SquadAutoPerson: SquadPersonArgs +---@field roleData RoleData? +---@field positionData RoleData? + ---@enum TransferSide local Side = { from = 'from', to = 'to', } --- Default key for SquadAuto/rank -local DEFAULT_RANK_KEY = '' local ROLE_INACTIVE = 'Inactive' @@ -155,7 +149,7 @@ function SquadAuto:_parseConfig() end end ----@param entries SquadPersonArgs[] +---@param entries SquadAutoPerson[] ---@return Widget|Html|string? function SquadAuto:display(entries) if Logic.isEmpty(entries) then @@ -174,12 +168,12 @@ function SquadAuto:display(entries) end ---@private ----@param entries SquadPersonArgs[] +---@param entries SquadAutoPerson[] ---@return Widget|Html|string? function SquadAuto:displayTabs(entries) local _, groupedEntries = Array.groupBy( entries, - ---@param entry SquadPersonArgs + ---@param entry SquadAutoPerson function (entry) return entry.leavedate:match('(%d%d%d%d)') end @@ -217,7 +211,7 @@ function SquadAuto:displayTabs(entries) end ---@private ----@param entry SquadPersonArgs +---@param entry SquadAutoPerson function SquadAuto:_enrichEntry(entry) local pagename = Page.pageifyLink(entry.link) local enrichment = self.enrichmentInfo[pagename] @@ -241,10 +235,10 @@ function SquadAuto:_enrichEntry(entry) end ---@private ----@return SquadPersonArgs[] manualPersons ----@return table enrichmentInfo +---@return SquadAutoPerson[] manualPersons +---@return table enrichmentInfo function SquadAuto:_readManualRowInput() - ---@type SquadPersonArgs[] + ---@type SquadAutoPerson[] local persons = {} local enrichmentInfo = {} @@ -260,7 +254,7 @@ function SquadAuto:_readManualRowInput() if self.config.type == SquadUtils.SquadType.STAFF and Logic.isNotEmpty(person.role) then -- Only allow manual entries for STAFF (organization) tables - ---@type SquadPersonArgs + ---@type SquadAutoPerson local manualPerson = { name = person.name, id = person.id, @@ -285,6 +279,10 @@ function SquadAuto:_readManualRowInput() faction = person.faction or person.race, race = person.faction or person.race, + + -- Used only by SquadAuto + roleData = RoleUtil.readRoleArgs(person.role), + positionData = RoleUtil.readRoleArgs(person.position) } table.insert(persons, manualPerson) else @@ -454,7 +452,7 @@ function SquadAuto:_buildConditions() end ---@private ----@return SquadPersonArgs[] +---@return SquadAutoPerson[] function SquadAuto:_selectEntries() return Array.filter( Array.extend( @@ -465,7 +463,7 @@ function SquadAuto:_selectEntries() self.manualPlayers ), --- Selects the appropriate entries based on the role. - ---@param entry SquadPersonArgs + ---@param entry SquadAutoPerson ---@return boolean function(entry) if self.config.status == SquadUtils.SquadStatus.INACTIVE then @@ -476,7 +474,7 @@ function SquadAuto:_selectEntries() return true end - local roles = RoleUtil.readRoleArgs(table.concat({entry.role, entry.position}, ',')) + local roles = {entry.roleData, entry.positionData} local hasStaffRoles = Array.any(roles, function(role) return role.type == RoleUtil.ROLE_TYPE.STAFF or role.type == RoleUtil.ROLE_TYPE.UNKNOWN -- Unknown roles are assumed to be non-player @@ -498,7 +496,7 @@ end ---If the type does not match, no entries are returned ---@private ---@param entries TeamHistoryEntry[] ----@return SquadPersonArgs[] +---@return SquadAutoPerson[] function SquadAuto:_selectHistoryEntries(entries) -- Select entries to match status if self.config.status == SquadUtils.SquadStatus.ACTIVE then @@ -569,7 +567,7 @@ end ---@param joinEntry TeamHistoryEntry ---@param inactiveEntry TeamHistoryEntry | nil ---@param leaveEntry TeamHistoryEntry | nil ----@return SquadPersonArgs +---@return SquadAutoPerson function SquadAuto:_mapToSquadPerson(joinEntry, inactiveEntry, leaveEntry) inactiveEntry = inactiveEntry or {} leaveEntry = leaveEntry or {} @@ -587,7 +585,7 @@ function SquadAuto:_mapToSquadPerson(joinEntry, inactiveEntry, leaveEntry) local inactivedate = attachReference(inactiveEntry, inactiveReference) local leavedate = attachReference(leaveEntry, leaveReference) - ---@type SquadPersonArgs + ---@type SquadAutoPerson local entry = { -- name id = leaveEntry.displayname or joinEntry.displayname, @@ -624,8 +622,12 @@ function SquadAuto:_mapToSquadPerson(joinEntry, inactiveEntry, leaveEntry) -- From legacy: Prefer faction information from leaveEntry faction = leaveEntry.faction or joinEntry.faction, - race = leaveEntry.faction or joinEntry.faction + race = leaveEntry.faction or joinEntry.faction, -- game, + + -- Used only by SquadAuto + roleData = RoleUtil.readRoleArgs(joinEntry.toRole), + positionData = RoleUtil.readRoleArgs(joinEntry.position) } -- On leave: Fetch the next team a person joined @@ -666,18 +668,18 @@ function SquadAuto._fetchNextTeam(pagename, date) return transfer.toteamtemplate, transfer.role2, transfer.date end ----Sorts a list of SquadPersonArgs +---Sorts a list of persons -- Active entries (no leavedate) sorted by joindate, -- Former entries sorted by leavedate ---@private ----@param entries SquadPersonArgs[] +---@param entries SquadAutoPerson[] ---@param useRankSort boolean? ----@return SquadPersonArgs[] +---@return SquadAutoPerson[] function SquadAuto._sortEntries(entries, useRankSort) return Array.sortBy(entries, function (element) return { - useRankSort and SquadAutoRank[element.position] or SquadAutoRank[DEFAULT_RANK_KEY], - useRankSort and SquadAutoRank[element.role] or SquadAutoRank[DEFAULT_RANK_KEY], + useRankSort and (element.positionData or {}).sortOrder or 0, + useRankSort and (element.roleData or {}).sortOrder or 0, element.leavedate or element.joindate or '', element.id } From 58225bc67bc3839034be6c74e33687b688fdc046 Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Mon, 25 May 2026 14:31:34 +0200 Subject: [PATCH 49/50] "fix" annotation in Squad/Utils --- lua/wikis/commons/Squad/Utils.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/wikis/commons/Squad/Utils.lua b/lua/wikis/commons/Squad/Utils.lua index bc22f2f9143..4a78534366c 100644 --- a/lua/wikis/commons/Squad/Utils.lua +++ b/lua/wikis/commons/Squad/Utils.lua @@ -129,12 +129,12 @@ function SquadUtils.readWrapperArgs(args) return SquadUtils.createWrapperData(players, squadType, squadStatus, args.title, args) end ----@param player SquadAutoPerson|SquadPersonArgs +---@param player table|SquadPersonArgs ---@return SquadPersonArgs function SquadUtils.convertAutoParameters(player) if Info.config.squads.standardizedAuto then -- Temporary until all wikis have enabled the new version of automated squads - ---@cast player -SquadAutoPerson + ---@cast player SquadPersonArgs return player end ---@cast player -SquadPersonArgs From 0b68700d82867dd110784f6f851f8a8d6277599b Mon Sep 17 00:00:00 2001 From: SyntacticSalt Date: Mon, 25 May 2026 17:43:33 +0200 Subject: [PATCH 50/50] Move disabling mapping into Controller --- lua/wikis/commons/Squad/Controller.lua | 7 +++++-- lua/wikis/commons/Squad/Utils.lua | 9 +-------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/lua/wikis/commons/Squad/Controller.lua b/lua/wikis/commons/Squad/Controller.lua index 653de56ecb2..94e65fe0d1b 100644 --- a/lua/wikis/commons/Squad/Controller.lua +++ b/lua/wikis/commons/Squad/Controller.lua @@ -89,8 +89,11 @@ end ---@param customTitle string? ---@return Widget function SquadController.runAuto(players, squadStatus, squadType, customTitle, adjustLpdb) - local mappedPlayers = Array.map(players, SquadUtils.convertAutoParameters) - local squadData = SquadUtils.createWrapperData(mappedPlayers, squadType, squadStatus, customTitle) + -- Temporary until all wikis have enabled the new version of automated squads + if not Info.config.squads.standardizedAuto then + players = Array.map(players, SquadUtils.convertAutoParameters) + end + local squadData = SquadUtils.createWrapperData(players, squadType, squadStatus, customTitle) return SquadController.execute(squadData, adjustLpdb) end diff --git a/lua/wikis/commons/Squad/Utils.lua b/lua/wikis/commons/Squad/Utils.lua index 4a78534366c..ff820d00d7a 100644 --- a/lua/wikis/commons/Squad/Utils.lua +++ b/lua/wikis/commons/Squad/Utils.lua @@ -129,16 +129,9 @@ function SquadUtils.readWrapperArgs(args) return SquadUtils.createWrapperData(players, squadType, squadStatus, args.title, args) end ----@param player table|SquadPersonArgs +---@param player table ---@return SquadPersonArgs function SquadUtils.convertAutoParameters(player) - if Info.config.squads.standardizedAuto then - -- Temporary until all wikis have enabled the new version of automated squads - ---@cast player SquadPersonArgs - return player - end - ---@cast player -SquadPersonArgs - ---@type SquadPersonArgs local newPlayer = Table.copy(player) local joinReference = TransferRefs.useReferences(player.joindateRef, player.joindate)