From 534f94cc2ae7eb37bb7cabf9d8a03ea6ed5dd0d2 Mon Sep 17 00:00:00 2001 From: hjpalpha Date: Sun, 20 Sep 2026 10:06:31 +0000 Subject: [PATCH 01/12] extract the config parsing --- .../ParticipantTable/Lib/ParseInput.lua | 72 +++++++++++++++++++ lua/wikis/commons/ParticipantTable/Base.lua | 41 +---------- .../commons/ParticipantTable/Starcraft.lua | 41 ++--------- lua/wikis/starcraft/Info.lua | 4 ++ lua/wikis/starcraft2/Info.lua | 4 ++ lua/wikis/stormgate/Info.lua | 4 ++ lua/wikis/warcraft/Info.lua | 4 ++ 7 files changed, 95 insertions(+), 75 deletions(-) create mode 100644 lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua diff --git a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua new file mode 100644 index 00000000000..dfa45d4fcec --- /dev/null +++ b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua @@ -0,0 +1,72 @@ +--- +-- @Liquipedia +-- page=Module:Features/ParticipantTable/Lib/ParseInput +-- +-- Please see https://github.com/Liquipedia/Lua-Modules to contribute +-- + +local Lua = require('Module:Lua') + +local DateExt = Lua.import('Module:Date/Ext') +local Faction = Lua.import('Module:Faction') +local Info = Lua.import('Module:Info', {loadData = true}) +local Logic = Lua.import('Module:Logic') +local Lpdb = Lua.import('Module:Lpdb') +local Namespace = Lua.import('Module:Namespace') +local Table = Lua.import('Module:Table') +local TournamentStructure = Lua.import('Module:TournamentStructure') +local Variables = Lua.import('Module:Variables') + +local Parser = {} + +---@param args table +---@param parentConfig ParticipantTableConfig? +---@return ParticipantTableConfig +function Parser.readConfig(args, parentConfig) + parentConfig = parentConfig or {} + + local showTeams = not Logic.readBool(args.disable_teams) + + local config = { + lpdbPrefix = args.lpdbPrefix or parentConfig.lpdbPrefix or Variables.varDefault('lpdbPrefix'), + noStorage = Logic.readBool(args.noStorage or parentConfig.noStorage or + Lpdb.isStorageDisabled() or not Namespace.isMain()), + matchGroupSpec = TournamentStructure.readMatchGroupsSpec(args), + syncPlayers = Logic.nilOr(Logic.readBoolOrNil(args.syncPlayers), parentConfig.syncPlayers, true), + showCountBySection = Logic.readBool(args.showCountBySection or parentConfig.showCountBySection), + count = tonumber(args.count), + colSpan = parentConfig.colSpan or tonumber(args.colspan) or 4, + onlyNotable = Logic.readBool(args.onlyNotable or parentConfig.onlyNotable), + resolveDate = args.date or parentConfig.resolveDate or DateExt.getContextualDate(), + sortPlayers = Logic.nilOr(Logic.readBoolOrNil(args.sortPlayers), Logic.readBoolOrNil(args.sortPlayers), + (Info.config.participants or {}).sortPlayersInTable), + sortOpponents = Logic.nilOr(Logic.readBoolOrNil(args.sortOpponents), parentConfig.sortOpponents, true), + showTeams = showTeams, + title = args.title, + importOnlyQualified = Logic.readBool(args.onlyQualified), + display = not Logic.readBool(args.hidden), + showTitle = not Logic.readBool(args.hideTitle), + -- the following configs only apply to faction table version + soloAsFactionTable = Logic.nilOr(Logic.readBoolOrNil(args.soloAsFactionTable), + (Info.config.participants or {}).soloAsFactionTable), + displayUnknownColumn = Logic.readBoolOrNil(args.unknowncolumn), + displayRandomColumn = Logic.readBoolOrNil(args.randomcolumn), + displayMultipleFactionColumn = Logic.readBoolOrNil(args.multiplecolumn), + isRandomEvent = Logic.nilOr(Logic.readBoolOrNil(args.is_random_event), parentConfig.isRandomEvent), + manualFactionCounts = Table.map(Faction.knownFactions, function(key, faction) + return faction, tonumber(args[Faction.toName(faction):lower()]) + end), + factionColumnWidth = tonumber(args.entrywidth) or showTeams and 212 or 156, + } + + config.width = parentConfig.width + if not config.width then + local columnWidth = parentConfig.columnWidth or tonumber(args.entrywidth) or showTeams and 212 or 156 + config.width = (columnWidth * config.colSpan) .. 'px' + end + config.columnWidth = config.columnWidth or ((100 / config.colSpan) .. '%') + + return config +end + +return Parser diff --git a/lua/wikis/commons/ParticipantTable/Base.lua b/lua/wikis/commons/ParticipantTable/Base.lua index 10634c66f42..8f5db8cf696 100644 --- a/lua/wikis/commons/ParticipantTable/Base.lua +++ b/lua/wikis/commons/ParticipantTable/Base.lua @@ -27,6 +27,7 @@ local TournamentStructure = Lua.import('Module:TournamentStructure') local Variables = Lua.import('Module:Variables') local Import = Lua.import('Module:ParticipantTable/Import') +local Parser = Lua.import('Module:Features/ParticipantTable/Lib/ParseInput') local Display = Lua.import('Module:Features/ParticipantTable/Components/Wrapper') @@ -52,48 +53,12 @@ end ---@return self function ParticipantTable:read() - self.config = self.readConfig(self.args) + self.config = Parser.readConfig(self.args) self:readSections() return self end ----@param args table ----@param parentConfig ParticipantTableConfig? ----@return ParticipantTableConfig -function ParticipantTable.readConfig(args, parentConfig) - parentConfig = parentConfig or {} - - local config = { - lpdbPrefix = args.lpdbPrefix or parentConfig.lpdbPrefix or Variables.varDefault('lpdbPrefix'), - noStorage = Logic.readBool(args.noStorage or parentConfig.noStorage or - Lpdb.isStorageDisabled() or not Namespace.isMain()), - matchGroupSpec = TournamentStructure.readMatchGroupsSpec(args), - syncPlayers = Logic.nilOr(Logic.readBoolOrNil(args.syncPlayers), parentConfig.syncPlayers, true), - showCountBySection = Logic.readBool(args.showCountBySection or parentConfig.showCountBySection), - count = tonumber(args.count), - colSpan = parentConfig.colSpan or tonumber(args.colspan) or 4, - onlyNotable = Logic.readBool(args.onlyNotable or parentConfig.onlyNotable), - resolveDate = args.date or parentConfig.resolveDate or DateExt.getContextualDate(), - sortPlayers = Logic.readBool(args.sortPlayers or parentConfig.sortPlayers), - sortOpponents = Logic.nilOr(Logic.readBoolOrNil(args.sortOpponents), parentConfig.sortOpponents, true), - showTeams = not Logic.readBool(args.disable_teams), - title = args.title, - importOnlyQualified = Logic.readBool(args.onlyQualified), - display = not Logic.readBool(args.hidden), - showTitle = not Logic.readBool(args.hideTitle), - } - - config.width = parentConfig.width - if not config.width then - local columnWidth = parentConfig.columnWidth or tonumber(args.entrywidth) or config.showTeams and 212 or 156 - config.width = (columnWidth * config.colSpan) .. 'px' - end - config.columnWidth = config.columnWidth or ((100 / config.colSpan) .. '%') - - return config -end - function ParticipantTable:readSections() self.sections = {} Array.forEach(self:fetchSectionsArgs(), function(sectionArgs) @@ -144,7 +109,7 @@ end ---@param args table function ParticipantTable:readSection(args) - local config = self.readConfig(args, self.config) + local config = Parser.readConfig(args, self.config) local section = {config = config} local entriesByName = {} diff --git a/lua/wikis/commons/ParticipantTable/Starcraft.lua b/lua/wikis/commons/ParticipantTable/Starcraft.lua index 76985e92dd1..565d249b427 100644 --- a/lua/wikis/commons/ParticipantTable/Starcraft.lua +++ b/lua/wikis/commons/ParticipantTable/Starcraft.lua @@ -20,7 +20,7 @@ local FactionTable = Lua.import('Module:Features/ParticipantTable/Components/Fac ---@class StarcraftParticipantTable: ParticipantTable ---@operator call(Frame): StarcraftParticipantTable ----@field config StarcraftParticipantTableConfig +---@field config ParticipantTableConfig ---@field sections StarcraftParticipantTableSection[] local StarcraftParticipantTable = Class.new(ParticipantTable) @@ -30,37 +30,10 @@ function StarcraftParticipantTable.run(frame) return StarcraftParticipantTable(frame):read():store():create() end ----@param args table ----@param parentConfig StarcraftParticipantTableConfig? ----@return StarcraftParticipantTableConfig -function StarcraftParticipantTable.readConfig(args, parentConfig) - local config = ParticipantTable.readConfig(args, parentConfig) --[[@as StarcraftParticipantTableConfig]] - parentConfig = parentConfig or {} - - config.displayUnknownColumn = Logic.readBoolOrNil(args.unknowncolumn) - config.displayRandomColumn = Logic.readBoolOrNil(args.randomcolumn) - config.displayMultipleFactionColumn = Logic.readBoolOrNil(args.multiplecolumn) - config.showCountByFaction = Logic.readBool(args.showCountByRace or args.count) - config.isRandomEvent = Logic.nilOr(Logic.readBoolOrNil(args.is_random_event), parentConfig.isRandomEvent) - config.isQualified = Logic.nilOr(Logic.readBoolOrNil(args.isQualified), parentConfig.isQualified) - config.sortPlayers = true - --only relevant for solo case since there we need columnWidth in px since colSpan is calculated dynamically - config.soloColumnWidth = tonumber(args.entrywidth) or config.showTeams and 212 or 156 - - config.manualFactionCounts = {} - Array.forEach(Faction.knownFactions, function(faction) - config.manualFactionCounts[faction] = tonumber(args[Faction.toName(faction):lower()]) - end) - - config.soloAsFactionTable = not Logic.readBool(args.soloNotAsRaceTable) - - return config -end - ---@param sectionArgs table ---@param key string|number ---@param index number ----@param config StarcraftParticipantTableConfig +---@param config ParticipantTableConfig ---@return StarcraftParticipantTableEntry function StarcraftParticipantTable:readEntry(sectionArgs, key, index, config) local prefix = 'p' .. index @@ -107,7 +80,6 @@ function StarcraftParticipantTable:readEntry(sectionArgs, key, index, config) dq = Logic.readBool(opponentArgs.dq), note = opponentArgs.note, opponent = opponent, - isQualified = Logic.nilOr(Logic.readBoolOrNil(sectionArgs[key .. 'qualified']), config.isQualified), inputIndex = index, seed = opponentArgs.seed, } @@ -115,18 +87,13 @@ end ---@param lpdbData table ---@param entry StarcraftParticipantTableEntry ----@param config StarcraftParticipantTableConfig +---@param config ParticipantTableConfig function StarcraftParticipantTable:adjustLpdbData(lpdbData, entry, config) if config.isRandomEvent then lpdbData.opponentplayers.p1faction = Faction.read('r') end - local isQualified = entry.isQualified or config.isQualified - - lpdbData.extradata.isqualified = tostring(isQualified) lpdbData.extradata.mod = Variables.varDefault('tournament_mod') - - lpdbData.qualified = isQualified and 1 or nil end ---@return boolean @@ -211,7 +178,7 @@ function StarcraftParticipantTable:_getFactionNumbers() end ---@param entry StarcraftParticipantTableEntry ----@param config StarcraftParticipantTableConfig +---@param config ParticipantTableConfig function StarcraftParticipantTable:setCustomPageVariables(entry, config) if config.isRandomEvent then Variables.varDefine(entry.opponent.players[1].displayName .. '_faction', Faction.read('r')) diff --git a/lua/wikis/starcraft/Info.lua b/lua/wikis/starcraft/Info.lua index 8e3b9162d9e..74d78e75f2b 100644 --- a/lua/wikis/starcraft/Info.lua +++ b/lua/wikis/starcraft/Info.lua @@ -47,5 +47,9 @@ return { }, }, defaultMaxPlayersPerPlacement = 35, + participants = { + soloAsFactionTable = true, + sortPlayersInTable = true, + }, }, } diff --git a/lua/wikis/starcraft2/Info.lua b/lua/wikis/starcraft2/Info.lua index 13ea979d4ae..7572f3fd137 100644 --- a/lua/wikis/starcraft2/Info.lua +++ b/lua/wikis/starcraft2/Info.lua @@ -89,5 +89,9 @@ return { swiss = {'matchdiff', 'gamediff'}, }, }, + participants = { + soloAsFactionTable = true, + sortPlayersInTable = true, + }, }, } diff --git a/lua/wikis/stormgate/Info.lua b/lua/wikis/stormgate/Info.lua index 76add681236..13a0aab076c 100644 --- a/lua/wikis/stormgate/Info.lua +++ b/lua/wikis/stormgate/Info.lua @@ -47,6 +47,10 @@ return { swiss = {'matchdiff', 'gamediff'}, }, }, + participants = { + soloAsFactionTable = true, + sortPlayersInTable = true, + }, }, defaultRoundPrecision = 0, } diff --git a/lua/wikis/warcraft/Info.lua b/lua/wikis/warcraft/Info.lua index 3b175c2778b..d50a7392197 100644 --- a/lua/wikis/warcraft/Info.lua +++ b/lua/wikis/warcraft/Info.lua @@ -73,5 +73,9 @@ return { }, }, defaultMaxPlayersPerPlacement = 20, + participants = { + soloAsFactionTable = true, + sortPlayersInTable = true, + }, }, } From 638e8dc5aa80a2e04739cd1ee73d8687c79f622a Mon Sep 17 00:00:00 2001 From: hjpalpha Date: Sun, 20 Sep 2026 10:09:22 +0000 Subject: [PATCH 02/12] adjust types accordingly --- .../commons/Features/ParticipantTable/Types.lua | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/lua/wikis/commons/Features/ParticipantTable/Types.lua b/lua/wikis/commons/Features/ParticipantTable/Types.lua index 60e62ac3775..0989a9e764a 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Types.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Types.lua @@ -34,6 +34,13 @@ local Types = {} ---@field width string ---@field columnWidth string ---@field showTitle boolean only applies for the title of the whole table +---@field displayUnknownColumn boolean? +---@field displayRandomColumn boolean? +---@field displayMultipleFactionColumn boolean? +---@field isRandomEvent boolean? +---@field manualFactionCounts table +---@field factionColumnWidth number +---@field soloAsFactionTable boolean? ---@class ParticipantTableSection ---@field config ParticipantTableConfig @@ -52,16 +59,6 @@ local Types = {} -- todo: resolve those with the refactoring ----@class StarcraftParticipantTableConfig: ParticipantTableConfig ----@field displayUnknownColumn boolean? ----@field displayRandomColumn boolean? ----@field displayMultipleFactionColumn boolean? ----@field showCountByFaction boolean ----@field isRandomEvent boolean ----@field isQualified boolean? ----@field manualFactionCounts table ----@field soloColumnWidth number ----@field soloAsFactionTable boolean ---@class StarcraftParticipantTableEntry: ParticipantTableEntry ---@field isQualified boolean? From 13028da151ce15c53a95b3e1e62df11d1919ba08 Mon Sep 17 00:00:00 2001 From: hjpalpha Date: Sun, 20 Sep 2026 10:18:36 +0000 Subject: [PATCH 03/12] adjust display as per changed types --- .../Features/ParticipantTable/Components/FactionHeader.lua | 4 ++-- .../Features/ParticipantTable/Components/FactionSection.lua | 2 +- .../Features/ParticipantTable/Components/FactionTable.lua | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lua/wikis/commons/Features/ParticipantTable/Components/FactionHeader.lua b/lua/wikis/commons/Features/ParticipantTable/Components/FactionHeader.lua index 1b008c1624a..674d7d5f513 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Components/FactionHeader.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Components/FactionHeader.lua @@ -14,7 +14,7 @@ local Component = Lua.import('Module:Widget/Component') local Html = Lua.import('Module:Widget/Html') local WidgetUtil = Lua.import('Module:Widget/Util') ----@param props {config: StarcraftParticipantTableConfig, factionColumns: string[], +---@param props {config: ParticipantTableConfig, factionColumns: string[], ---factionNumbers: table} ---@return VNode local function ParticipantTableFactionHeader(props) @@ -27,7 +27,7 @@ local function ParticipantTableFactionHeader(props) ' ', Faction.toName(faction), config.isRandomEvent and ' Main' or nil, - config.showCountByFaction and " ''(" .. props.factionNumbers[faction .. 'Display'] .. ")''" or nil + config.count and " ''(" .. props.factionNumbers[faction .. 'Display'] .. ")''" or nil ) return Html.Div{ diff --git a/lua/wikis/commons/Features/ParticipantTable/Components/FactionSection.lua b/lua/wikis/commons/Features/ParticipantTable/Components/FactionSection.lua index 8e84413ffe0..2847a555eac 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Components/FactionSection.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Components/FactionSection.lua @@ -24,7 +24,7 @@ local makeRow = function(children) return Html.Div{classes = {'participantTable-row'}, children = children} end ----@param props {config: StarcraftParticipantTableConfig, section: StarcraftParticipantTableSection, +---@param props {config: ParticipantTableConfig, section: StarcraftParticipantTableSection, ---factionColumns: string[]} ---@return VNode[] local function ParticipantTableFactionSection(props) diff --git a/lua/wikis/commons/Features/ParticipantTable/Components/FactionTable.lua b/lua/wikis/commons/Features/ParticipantTable/Components/FactionTable.lua index 9eb4cabe0aa..617a9d7345d 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Components/FactionTable.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Components/FactionTable.lua @@ -16,7 +16,7 @@ local WidgetUtil = Lua.import('Module:Widget/Util') local Header = Lua.import('Module:Features/ParticipantTable/Components/FactionHeader') local Section = Lua.import('Module:Features/ParticipantTable/Components/FactionSection') ----@param props {config: StarcraftParticipantTableConfig, factionColumns: string[], +---@param props {config: ParticipantTableConfig, factionColumns: string[], ---factionNumbers: table, sections: StarcraftParticipantTableSection[]} ---@return VNode local function ParticipantTableFactionTable(props) @@ -27,7 +27,7 @@ local function ParticipantTableFactionTable(props) classes = {'participantTable', 'participantTable-faction'}, css = { ['grid-template-columns'] = 'repeat(' .. colSpan .. ', 1fr)', - width = (colSpan * config.soloColumnWidth) .. 'px', + width = (colSpan * config.factionColumnWidth) .. 'px', }, children = WidgetUtil.collect( Header{ From 5359ab3bdf1c2007aa9e118cb4ed9430900d1272 Mon Sep 17 00:00:00 2001 From: hjpalpha Date: Sun, 20 Sep 2026 10:18:53 +0000 Subject: [PATCH 04/12] kick stashed args stuff for sections --- lua/wikis/commons/ParticipantTable/Base.lua | 28 --------------------- 1 file changed, 28 deletions(-) diff --git a/lua/wikis/commons/ParticipantTable/Base.lua b/lua/wikis/commons/ParticipantTable/Base.lua index 8f5db8cf696..45301f22689 100644 --- a/lua/wikis/commons/ParticipantTable/Base.lua +++ b/lua/wikis/commons/ParticipantTable/Base.lua @@ -12,18 +12,13 @@ local Lua = require('Module:Lua') local Arguments = Lua.import('Module:Arguments') local Array = Lua.import('Module:Array') local Class = Lua.import('Module:Class') -local DateExt = Lua.import('Module:Date/Ext') local Json = Lua.import('Module:Json') local Logic = Lua.import('Module:Logic') -local Lpdb = Lua.import('Module:Lpdb') -local Namespace = Lua.import('Module:Namespace') local Opponent = Lua.import('Module:Opponent/Custom') local PageVariableNamespace = Lua.import('Module:PageVariableNamespace') local PlayerExt = Lua.import('Module:Player/Ext/Custom') local Table = Lua.import('Module:Table') -local Template = Lua.import('Module:Template') local Tournament = Lua.import('Module:Tournament') -local TournamentStructure = Lua.import('Module:TournamentStructure') local Variables = Lua.import('Module:Variables') local Import = Lua.import('Module:ParticipantTable/Import') @@ -31,7 +26,6 @@ local Parser = Lua.import('Module:Features/ParticipantTable/Lib/ParseInput') local Display = Lua.import('Module:Features/ParticipantTable/Components/Wrapper') -local pageVars = PageVariableNamespace('ParticipantTable') local prizePoolVars = PageVariableNamespace('PrizePool') ---@class ParticipantTable: BaseClass @@ -70,8 +64,6 @@ end function ParticipantTable:fetchSectionsArgs() local args = self.args - pageVars:set('stashArgs', '1') - local sectionsArgs = Array.mapIndexes(function (index) local parsed = Json.parseIfString(args[index]) if type(parsed) == 'table' and parsed.type == 'section' then @@ -79,19 +71,6 @@ function ParticipantTable:fetchSectionsArgs() end end) - if Logic.isNotEmpty(sectionsArgs) then - return sectionsArgs - end - - -- make sure that all sections stashArgs - for _, potentialSection in pairs(args) do - ParticipantTable._stashArgs(potentialSection) - end - - -- retrieve sectionsArgs - sectionsArgs = Template.retrieveReturnValues('ParticipantTable') - pageVars:delete('stashArgs') - --case no sections: use whole table as first section if Logic.isEmpty(sectionsArgs) then return {args} @@ -100,13 +79,6 @@ function ParticipantTable:fetchSectionsArgs() return sectionsArgs end ----access the args so it stashes ----@param potentialSection string ----@return string -function ParticipantTable._stashArgs(potentialSection) - return potentialSection -end - ---@param args table function ParticipantTable:readSection(args) local config = Parser.readConfig(args, self.config) From 8d928b88eb628e05c08bd9a902b8f5a2e06eeaa0 Mon Sep 17 00:00:00 2001 From: hjpalpha Date: Sun, 20 Sep 2026 11:10:42 +0000 Subject: [PATCH 05/12] extract more parsing --- .../Components/FactionSection.lua | 2 +- .../Components/FactionTable.lua | 2 +- .../ParticipantTable/Lib/ParseInput.lua | 110 +++++++++++++++ .../Features/ParticipantTable/Types.lua | 11 -- lua/wikis/commons/ParticipantTable/Base.lua | 133 ++---------------- lua/wikis/commons/ParticipantTable/Import.lua | 27 ++-- .../commons/ParticipantTable/Starcraft.lua | 61 +------- 7 files changed, 144 insertions(+), 202 deletions(-) diff --git a/lua/wikis/commons/Features/ParticipantTable/Components/FactionSection.lua b/lua/wikis/commons/Features/ParticipantTable/Components/FactionSection.lua index 2847a555eac..811ac309dab 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Components/FactionSection.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Components/FactionSection.lua @@ -24,7 +24,7 @@ local makeRow = function(children) return Html.Div{classes = {'participantTable-row'}, children = children} end ----@param props {config: ParticipantTableConfig, section: StarcraftParticipantTableSection, +---@param props {config: ParticipantTableConfig, section: ParticipantTableSection, ---factionColumns: string[]} ---@return VNode[] local function ParticipantTableFactionSection(props) diff --git a/lua/wikis/commons/Features/ParticipantTable/Components/FactionTable.lua b/lua/wikis/commons/Features/ParticipantTable/Components/FactionTable.lua index 617a9d7345d..f7a80f33876 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Components/FactionTable.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Components/FactionTable.lua @@ -17,7 +17,7 @@ local Header = Lua.import('Module:Features/ParticipantTable/Components/FactionHe local Section = Lua.import('Module:Features/ParticipantTable/Components/FactionSection') ---@param props {config: ParticipantTableConfig, factionColumns: string[], ----factionNumbers: table, sections: StarcraftParticipantTableSection[]} +---factionNumbers: table, sections: ParticipantTableSection[]} ---@return VNode local function ParticipantTableFactionTable(props) local config = props.config diff --git a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua index dfa45d4fcec..9db10264e57 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua @@ -7,12 +7,15 @@ local Lua = require('Module:Lua') +local Array = Lua.import('Module:Array') local DateExt = Lua.import('Module:Date/Ext') local Faction = Lua.import('Module:Faction') local Info = Lua.import('Module:Info', {loadData = true}) +local Json = Lua.import('Module:Json') local Logic = Lua.import('Module:Logic') local Lpdb = Lua.import('Module:Lpdb') local Namespace = Lua.import('Module:Namespace') +local Opponent = Lua.import('Module:Opponent/Custom') local Table = Lua.import('Module:Table') local TournamentStructure = Lua.import('Module:TournamentStructure') local Variables = Lua.import('Module:Variables') @@ -69,4 +72,111 @@ function Parser.readConfig(args, parentConfig) return config end +---@param args table +---@param config ParticipantTableConfig +---@return ParticipantTableSection[] +function Parser.readSections(args, config) + local sectionsArgs = Array.mapIndexes(function (index) + local parsed = Json.parseIfString(args[index]) + if type(parsed) == 'table' and parsed.type == 'section' then + return parsed + end + end) + --case no sections: use whole table as first section + if Logic.isEmpty(sectionsArgs) then + sectionsArgs = {args} + end + + return Array.map(sectionsArgs, function(sectionArgs) + local sectionConfig = Parser.readConfig(args, config) + return { + config = sectionConfig, + entries = Parser._readEntries() + } + end) +end + +---@param args table +---@param config ParticipantTableConfig +---@return ParticipantTableEntry[] +function Parser.readEntries(args, config) + local alreadyUsed = {} + + return Table.mapArgumentsByPrefix(args, {'p', 'player'}, function(key, index) + local entry = Parser._readEntry(args, key, index, config) + entry.sortName = Opponent.toName(entry.opponent) + + if entry.opponent and Opponent.isTbd(entry.opponent) then + entry.name = Opponent.toName(entry.opponent) + return entry + end + + entry.opponent = Opponent.resolve(entry.opponent, config.resolveDate, { + syncPlayer = config.syncPlayers, + overwritePageVars = true, + }) + entry.isResolved = true + entry.name = Opponent.toName(entry.opponent) + + if alreadyUsed[entry.name] then + error('Duplicate Input "|' .. key .. '=' .. args[key] .. '"') + end + + alreadyUsed[entry.name] = true + + return entry + end) +end + +---@param sectionArgs table +---@param key string +---@param index integer +---@param config ParticipantTableConfig +---@return ParticipantTableEntry +function Parser._readEntry(sectionArgs, key, index, config) + local prefix = 'p' .. index + local valueFromArgs = function(postfix) + return sectionArgs[key .. postfix] or sectionArgs[prefix .. postfix] + end + + --if not a json assume it is a solo opponent + local opponentArgs = Json.parseIfTable(sectionArgs[key]) or { + type = Opponent.solo, + name = sectionArgs[key], + link = valueFromArgs('link'), + flag = valueFromArgs('flag'), + team = valueFromArgs('team'), + dq = valueFromArgs('dq'), + note = valueFromArgs('note'), + seed = valueFromArgs('seed'), + faction = valueFromArgs('faction') or valueFromArgs('race'), + } + + assert(Opponent.isType(opponentArgs.type), 'Invalid opponent type for "' .. sectionArgs[key] .. '"') + + opponentArgs.seed = tonumber(opponentArgs.seed) + + --unset wiki var for random events to not read players as random if prize pool already sets them as random + if config.isRandomEvent and opponentArgs.type == Opponent.solo then + Variables.varDefine(opponentArgs.name .. '_faction', '') + end + local opponent = Opponent.readOpponentArgs(opponentArgs) + + if config.sortPlayers and opponent.players then + table.sort(opponent.players, function (player1, player2) + local name1 = (player1.displayName or player1.pageName):lower() + local name2 = (player2.displayName or player2.pageName):lower() + return name1 < name2 + end) + end + + return { + dq = Logic.readBool(opponentArgs.dq), + note = opponentArgs.note, + opponent = opponent, + inputIndex = index, + seed = opponentArgs.seed, + } +end + return Parser diff --git a/lua/wikis/commons/Features/ParticipantTable/Types.lua b/lua/wikis/commons/Features/ParticipantTable/Types.lua index 0989a9e764a..8085acf7689 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Types.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Types.lua @@ -56,15 +56,4 @@ local Types = {} ---@field sortName string ---@field seed integer? - - --- todo: resolve those with the refactoring - ----@class StarcraftParticipantTableEntry: ParticipantTableEntry ----@field isQualified boolean? ----@field opponent StarcraftStandardOpponent - ----@class StarcraftParticipantTableSection: ParticipantTableSection ----@field entries StarcraftParticipantTableEntry[] - return Types diff --git a/lua/wikis/commons/ParticipantTable/Base.lua b/lua/wikis/commons/ParticipantTable/Base.lua index 45301f22689..cc824417957 100644 --- a/lua/wikis/commons/ParticipantTable/Base.lua +++ b/lua/wikis/commons/ParticipantTable/Base.lua @@ -48,73 +48,27 @@ end ---@return self function ParticipantTable:read() self.config = Parser.readConfig(self.args) - self:readSections() + self.sections = Parser.readSections(self.args, self.config) - return self -end - -function ParticipantTable:readSections() - self.sections = {} - Array.forEach(self:fetchSectionsArgs(), function(sectionArgs) - self:readSection(sectionArgs) - end) -end - ----@return table[] -function ParticipantTable:fetchSectionsArgs() - local args = self.args - - local sectionsArgs = Array.mapIndexes(function (index) - local parsed = Json.parseIfString(args[index]) - if type(parsed) == 'table' and parsed.type == 'section' then - return parsed - end + Array.forEach(self.sections, function(section) + self:_adjustSectionWithImport(section) + Array.sortInPlaceBy(section.entries, function(entry) + return section.config.sortOpponents and entry.sortName:lower() or entry.inputIndex or -1 + end) end) - --case no sections: use whole table as first section - if Logic.isEmpty(sectionsArgs) then - return {args} - end - - return sectionsArgs + return self end ----@param args table -function ParticipantTable:readSection(args) - local config = Parser.readConfig(args, self.config) - local section = {config = config} - - local entriesByName = {} - local tbds = {} - Table.mapArgumentsByPrefix(args, {'p', 'player'}, function(key, index) - local entry = self:readEntry(args, key, index, config) - entry.sortName = Opponent.toName(entry.opponent) - - if entry.opponent and Opponent.isTbd(entry.opponent) then - entry.name = Opponent.toName(entry.opponent) - table.insert(tbds, entry) - --needed so index is increased - return entry - end - - entry.opponent = Opponent.resolve(entry.opponent, config.resolveDate, { - syncPlayer = config.syncPlayers, - overwritePageVars = true, - }) - entry.isResolved = true - entry.name = Opponent.toName(entry.opponent) - - if entriesByName[entry.name] then - error('Duplicate Input "|' .. key .. '=' .. args[key] .. '"') - end - - entriesByName[entry.name] = entry +function ParticipantTable:_adjustSectionWithImport(section) + local config = section.config + if Logic.isEmpty(config.matchGroupSpec) then + return + end - --needed so index is increased - return entry - end) + local entries = section.entries - section.entries = Array.map(Import.importFromMatchGroupSpec(config, entriesByName), function(entry) + Array.forEach(Import.importFromMatchGroupSpec(config, entries), function(entry) entry.sortName = entry.sortName or Opponent.toName(entry.opponent) entry.opponent = entry.isResolved and entry.opponent or Opponent.resolve(entry.opponent, config.resolveDate, { syncPlayer = config.syncPlayers, @@ -123,16 +77,8 @@ function ParticipantTable:readSection(args) entry.name = entry.name or Opponent.toName(entry.opponent) entry.isResolved = true self:setCustomPageVariables(entry, config) - return entry - end) - - Array.sortInPlaceBy(section.entries, function(entry) - return config.sortOpponents and entry.sortName:lower() or entry.inputIndex or -1 + table.insert(entries, entry) end) - - Array.extendWith(section.entries, tbds) - - table.insert(self.sections, section) end ---@param entry ParticipantTableEntry @@ -140,55 +86,6 @@ end function ParticipantTable:setCustomPageVariables(entry, config) end ----@param sectionArgs table ----@param key string|number ----@param index number ----@param config ParticipantTableConfig ----@return ParticipantTableEntry -function ParticipantTable:readEntry(sectionArgs, key, index, config) - local prefix = 'p' .. index - local valueFromArgs = function(postfix) - return sectionArgs[key .. postfix] or sectionArgs[prefix .. postfix] - end - - --if not a json assume it is a solo opponent - local opponentArgs = Json.parseIfTable(sectionArgs[key]) or { - type = Opponent.solo, - name = sectionArgs[key], - link = valueFromArgs('link'), - flag = valueFromArgs('flag'), - team = valueFromArgs('team'), - dq = valueFromArgs('dq'), - note = valueFromArgs('note'), - seed = valueFromArgs('seed'), - } - - assert(Opponent.isType(opponentArgs.type), 'Invalid opponent type for "' .. sectionArgs[key] .. '"') - - opponentArgs.seed = tonumber(opponentArgs.seed) - if opponentArgs.seed then - self.hasSeeds = true - end - - local opponent = Opponent.readOpponentArgs(opponentArgs) - - if config.sortPlayers and opponent.players then - table.sort(opponent.players, function (player1, player2) - local name1 = (player1.displayName or player1.pageName):lower() - local name2 = (player2.displayName or player2.pageName):lower() - return name1 < name2 - end) - end - - return { - dq = Logic.readBool(opponentArgs.dq), - note = opponentArgs.note, - opponent = opponent, - inputIndex = index, - seed = opponentArgs.seed, - } -end - ---@return self function ParticipantTable:store() if self.config.noStorage then return self end diff --git a/lua/wikis/commons/ParticipantTable/Import.lua b/lua/wikis/commons/ParticipantTable/Import.lua index 4d9353dc1fb..bd5d077cc10 100644 --- a/lua/wikis/commons/ParticipantTable/Import.lua +++ b/lua/wikis/commons/ParticipantTable/Import.lua @@ -18,19 +18,19 @@ local TournamentStructure = Lua.import('Module:TournamentStructure') local ParticipantTableImport = {} ---@param config ParticipantTableConfig ----@param entriesByName table +---@param entries ParticipantTableEntry[] ---@return ParticipantTableEntry[] -function ParticipantTableImport.importFromMatchGroupSpec(config, entriesByName) - if Table.isEmpty(config.matchGroupSpec) then - return Array.extractValues(entriesByName) - end - +function ParticipantTableImport.importFromMatchGroupSpec(config, entries) local matchRecords = ParticipantTableImport._fetchMatchRecords(config.matchGroupSpec) if Table.isEmpty(matchRecords) then - return Array.extractValues(entriesByName) + return {} end + ---@type table + local alreadyProcessed = Table.map(entries, function(key, entry) + return entry.name, true + end) ---@cast matchRecords -nil - return ParticipantTableImport._entriesFromMatchRecords(matchRecords, config, entriesByName) + return ParticipantTableImport._entriesFromMatchRecords(matchRecords, config, alreadyProcessed) end ---@param matchGroupSpec table @@ -46,9 +46,10 @@ end ---@param matchRecords table[] ---@param config ParticipantTableConfig ----@param entriesByName table +---@param alreadyProcessed table ---@return ParticipantTableEntry[] -function ParticipantTableImport._entriesFromMatchRecords(matchRecords, config, entriesByName) +function ParticipantTableImport._entriesFromMatchRecords(matchRecords, config, alreadyProcessed) + local entries = {} Array.forEach(matchRecords, function(matchRecord) Array.forEach(matchRecord.match2opponents, function(opponentRecord, opponentIndex) if not ParticipantTableImport._shouldInclude(opponentIndex, matchRecord, config.importOnlyQualified) then @@ -56,13 +57,13 @@ function ParticipantTableImport._entriesFromMatchRecords(matchRecords, config, e end local entry = ParticipantTableImport._entryFromOpponentRecord(opponentRecord) - if not entry then return end + if not entry or alreadyProcessed[entry.name] then return end - entriesByName[entry.name] = entriesByName[entry.name] or entry + table.insert(entries, entry) end) end) - return Array.extractValues(entriesByName) + return entries end ---@param opponentIndex integer diff --git a/lua/wikis/commons/ParticipantTable/Starcraft.lua b/lua/wikis/commons/ParticipantTable/Starcraft.lua index 565d249b427..3a6c3c1acd9 100644 --- a/lua/wikis/commons/ParticipantTable/Starcraft.lua +++ b/lua/wikis/commons/ParticipantTable/Starcraft.lua @@ -21,7 +21,7 @@ local FactionTable = Lua.import('Module:Features/ParticipantTable/Components/Fac ---@class StarcraftParticipantTable: ParticipantTable ---@operator call(Frame): StarcraftParticipantTable ---@field config ParticipantTableConfig ----@field sections StarcraftParticipantTableSection[] +---@field sections ParticipantTableSection[] local StarcraftParticipantTable = Class.new(ParticipantTable) ---@param frame Frame @@ -30,63 +30,8 @@ function StarcraftParticipantTable.run(frame) return StarcraftParticipantTable(frame):read():store():create() end ----@param sectionArgs table ----@param key string|number ----@param index number ----@param config ParticipantTableConfig ----@return StarcraftParticipantTableEntry -function StarcraftParticipantTable:readEntry(sectionArgs, key, index, config) - local prefix = 'p' .. index - local valueFromArgs = function(postfix) - return sectionArgs[key .. postfix] or sectionArgs[prefix .. postfix] - end - - --if not a json assume it is a solo opponent - local opponentArgs = Json.parseIfTable(sectionArgs[key]) or { - type = Opponent.solo, - name = sectionArgs[key], - link = valueFromArgs('link'), - flag = valueFromArgs('flag'), - team = valueFromArgs('team'), - dq = valueFromArgs('dq'), - note = valueFromArgs('note'), - seed = valueFromArgs('seed'), - faction = valueFromArgs('race') or valueFromArgs('faction'), - } - - assert(Opponent.isType(opponentArgs.type), 'Invalid opponent type for "' .. sectionArgs[key] .. '"') - - opponentArgs.seed = tonumber(opponentArgs.seed) - if opponentArgs.seed then - self.hasSeeds = true - end - - --unset wiki var for random events to not read players as random if prize pool already sets them as random - if config.isRandomEvent and opponentArgs.type == Opponent.solo then - Variables.varDefine(opponentArgs.name .. '_faction', '') - end - - local opponent = Opponent.readOpponentArgs(opponentArgs) - - if config.sortPlayers and opponent.players then - table.sort(opponent.players, function (player1, player2) - local name1 = (player1.displayName or player1.pageName):lower() - local name2 = (player2.displayName or player2.pageName):lower() - return name1 < name2 - end) - end - - return { - dq = Logic.readBool(opponentArgs.dq), - note = opponentArgs.note, - opponent = opponent, - inputIndex = index, - seed = opponentArgs.seed, - } -end - ---@param lpdbData table ----@param entry StarcraftParticipantTableEntry +---@param entry ParticipantTableEntry ---@param config ParticipantTableConfig function StarcraftParticipantTable:adjustLpdbData(lpdbData, entry, config) if config.isRandomEvent then @@ -177,7 +122,7 @@ function StarcraftParticipantTable:_getFactionNumbers() return factionNumbers end ----@param entry StarcraftParticipantTableEntry +---@param entry ParticipantTableEntry ---@param config ParticipantTableConfig function StarcraftParticipantTable:setCustomPageVariables(entry, config) if config.isRandomEvent then From d026e9d5922698fcae72436d9d87975ae4f4f447 Mon Sep 17 00:00:00 2001 From: hjpalpha Date: Sun, 20 Sep 2026 11:12:26 +0000 Subject: [PATCH 06/12] determine hasSeeds again --- lua/wikis/commons/ParticipantTable/Base.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lua/wikis/commons/ParticipantTable/Base.lua b/lua/wikis/commons/ParticipantTable/Base.lua index cc824417957..0e31cd6961e 100644 --- a/lua/wikis/commons/ParticipantTable/Base.lua +++ b/lua/wikis/commons/ParticipantTable/Base.lua @@ -56,6 +56,11 @@ function ParticipantTable:read() return section.config.sortOpponents and entry.sortName:lower() or entry.inputIndex or -1 end) end) + self.hasSeeds = Array.any(self.sections, function(section) + return Array.any(section.entries, function(entry) + return entry.seed ~= nil + end) + end) return self end From 554cc6d5b9fc83669b794fba914f5e8c72353aa4 Mon Sep 17 00:00:00 2001 From: hjpalpha <75081997+hjpalpha@users.noreply.github.com> Date: Sun, 20 Sep 2026 13:16:28 +0200 Subject: [PATCH 07/12] Update Starcraft.lua --- lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua | 2 +- lua/wikis/commons/ParticipantTable/Starcraft.lua | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua index 9db10264e57..7d04c04a7fa 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua @@ -99,7 +99,7 @@ end ---@param args table ---@param config ParticipantTableConfig ---@return ParticipantTableEntry[] -function Parser.readEntries(args, config) +function Parser._readEntries(args, config) local alreadyUsed = {} return Table.mapArgumentsByPrefix(args, {'p', 'player'}, function(key, index) diff --git a/lua/wikis/commons/ParticipantTable/Starcraft.lua b/lua/wikis/commons/ParticipantTable/Starcraft.lua index 3a6c3c1acd9..093b6414c8a 100644 --- a/lua/wikis/commons/ParticipantTable/Starcraft.lua +++ b/lua/wikis/commons/ParticipantTable/Starcraft.lua @@ -9,9 +9,7 @@ local Lua = require('Module:Lua') local Array = Lua.import('Module:Array') local Class = Lua.import('Module:Class') -local Json = Lua.import('Module:Json') local Faction = Lua.import('Module:Faction') -local Logic = Lua.import('Module:Logic') local Opponent = Lua.import('Module:Opponent/Custom') local ParticipantTable = Lua.import('Module:ParticipantTable/Base') local Variables = Lua.import('Module:Variables') From 37f12a0729957e5ed9dbca51c527f960e89d2651 Mon Sep 17 00:00:00 2001 From: hjpalpha Date: Sun, 20 Sep 2026 11:44:41 +0000 Subject: [PATCH 08/12] passing along the args kinda helps... --- .../commons/Features/ParticipantTable/Lib/ParseInput.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua index 7d04c04a7fa..47811fc4e25 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua @@ -77,7 +77,7 @@ end ---@return ParticipantTableSection[] function Parser.readSections(args, config) local sectionsArgs = Array.mapIndexes(function (index) - local parsed = Json.parseIfString(args[index]) + local parsed = Json.parseIfTable(args[index]) if type(parsed) == 'table' and parsed.type == 'section' then return parsed end @@ -88,10 +88,10 @@ function Parser.readSections(args, config) end return Array.map(sectionsArgs, function(sectionArgs) - local sectionConfig = Parser.readConfig(args, config) + local sectionConfig = Parser.readConfig(sectionArgs, config) return { config = sectionConfig, - entries = Parser._readEntries() + entries = Parser._readEntries(sectionArgs, sectionConfig) } end) end From 73d9d484a50c2dbf0eaefe50a17bd38c542b2a2d Mon Sep 17 00:00:00 2001 From: hjpalpha Date: Sun, 20 Sep 2026 13:01:27 +0000 Subject: [PATCH 09/12] import and import parsing --- lua/spec/participant_table_spec.lua | 24 +++-- .../Features/ParticipantTable/Api/Import.lua | 29 ++++++ .../ParticipantTable/Lib/ParseImported.lua | 73 +++++++++++++++ .../ParticipantTable/Lib/ParseInput.lua | 1 - .../Features/ParticipantTable/Lib/Util.lua | 45 +++++++++ .../Features/ParticipantTable/Types.lua | 1 - lua/wikis/commons/ParticipantTable/Base.lua | 40 ++------ lua/wikis/commons/ParticipantTable/Import.lua | 92 ------------------- 8 files changed, 168 insertions(+), 137 deletions(-) create mode 100644 lua/wikis/commons/Features/ParticipantTable/Api/Import.lua create mode 100644 lua/wikis/commons/Features/ParticipantTable/Lib/ParseImported.lua create mode 100644 lua/wikis/commons/Features/ParticipantTable/Lib/Util.lua delete mode 100644 lua/wikis/commons/ParticipantTable/Import.lua diff --git a/lua/spec/participant_table_spec.lua b/lua/spec/participant_table_spec.lua index 8a703e0abe9..7addf2960c9 100644 --- a/lua/spec/participant_table_spec.lua +++ b/lua/spec/participant_table_spec.lua @@ -196,9 +196,9 @@ describe('Participant Table', function() { { entries = { - Table.merge({inputIndex = 1}, parsedBaseEntries.clem), - Table.merge({inputIndex = 2}, parsedBaseEntries.lambo), - Table.merge({inputIndex = 3}, parsedBaseEntries.showtime), + parsedBaseEntries.clem, + parsedBaseEntries.lambo, + parsedBaseEntries.showtime, }, }, }, @@ -208,9 +208,9 @@ describe('Participant Table', function() { { entries = { - Table.merge({inputIndex = 1, seed = 1}, parsedBaseEntries.clem), - Table.merge({inputIndex = 2, seed = 3}, parsedBaseEntries.lambo), - Table.merge({inputIndex = 3, seed = 2}, parsedBaseEntries.showtime), + Table.merge({seed = 1}, parsedBaseEntries.clem), + Table.merge({seed = 3}, parsedBaseEntries.lambo), + Table.merge({seed = 2}, parsedBaseEntries.showtime), }, }, }, @@ -220,15 +220,15 @@ describe('Participant Table', function() { { entries = { - Table.merge({inputIndex = 1}, parsedBaseEntries.clem), - Table.merge({inputIndex = 2}, parsedBaseEntries.lambo), - Table.merge({inputIndex = 3}, parsedBaseEntries.showtime), + parsedBaseEntries.clem, + parsedBaseEntries.lambo, + parsedBaseEntries.showtime, }, }, { entries = { - Table.merge({inputIndex = 2}, parsedBaseEntries.bunny), - Table.merge({inputIndex = 1}, parsedBaseEntries.classic), + parsedBaseEntries.bunny, + parsedBaseEntries.classic, }, }, }, @@ -240,7 +240,6 @@ describe('Participant Table', function() entries = { { dq = false, - inputIndex = 2, isResolved = true, name = 'Classic_(Kim_Doh_Woo) / ShoWTimE', opponent = { @@ -265,7 +264,6 @@ describe('Participant Table', function() }, { dq = false, - inputIndex = 1, isResolved = true, name = 'Clem / Lambo', opponent = { diff --git a/lua/wikis/commons/Features/ParticipantTable/Api/Import.lua b/lua/wikis/commons/Features/ParticipantTable/Api/Import.lua new file mode 100644 index 00000000000..bbbb4b2df08 --- /dev/null +++ b/lua/wikis/commons/Features/ParticipantTable/Api/Import.lua @@ -0,0 +1,29 @@ +--- +-- @Liquipedia +-- page=Module:Features/ParticipantTable/Api/Import +-- +-- Please see https://github.com/Liquipedia/Lua-Modules to contribute +-- + +local Lua = require('Module:Lua') + +local Logic = Lua.import('Module:Logic') +local TournamentStructure = Lua.import('Module:TournamentStructure') + +local Import = {} + +---@param matchGroupSpec MatchGroupsSpec +---@return match2[] +function Import.fromMatchGroupSpec(matchGroupSpec) + if Logic.isEmpty(matchGroupSpec) then + return {} + end + return mw.ext.LiquipediaDB.lpdb('match2', { + conditions = tostring(TournamentStructure.getMatch2Filter(matchGroupSpec)), + query = 'pagename, match2bracketdata, match2opponents, winner', + order = 'date asc', + limit = 5000, + }) +end + +return Import diff --git a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseImported.lua b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseImported.lua new file mode 100644 index 00000000000..a641a55c7fe --- /dev/null +++ b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseImported.lua @@ -0,0 +1,73 @@ +--- +-- @Liquipedia +-- page=Module:Features/ParticipantTable/Lib/ParseImported +-- +-- Please see https://github.com/Liquipedia/Lua-Modules to contribute +-- + +local Lua = require('Module:Lua') + +local Array = Lua.import('Module:Array') +local Logic = Lua.import('Module:Logic') +local Opponent = Lua.import('Module:Opponent/Custom') +local Table = Lua.import('Module:Table') + +local Parser = {} + +---@param config ParticipantTableConfig +---@param entries ParticipantTableEntry[] +---@param matchRecords match2[] +---@return ParticipantTableEntry[] +function Parser.parseImported(config, entries, matchRecords) + if Logic.isEmpty(matchRecords) then + return {} + end + ---@type table + local alreadyProcessed = Table.map(entries, function(key, entry) + return entry.name, true + end) + ---@cast matchRecords -nil + + local newEntries = {} + Array.forEach(matchRecords, function(matchRecord) + Array.forEach(matchRecord.match2opponents, function(opponentRecord, opponentIndex) + if not Parser._shouldInclude(opponentIndex, matchRecord, config.importOnlyQualified) then + return + end + + local entry = Parser._entryFromOpponentRecord(opponentRecord) + if not entry or alreadyProcessed[entry.name] then return end + + alreadyProcessed[entry.name] = true + + table.insert(newEntries, entry) + end) + end) + + return newEntries +end + +---@param opponentIndex integer +---@param matchRecord table +---@param importOnlyQualified boolean? +---@return boolean +function Parser._shouldInclude(opponentIndex, matchRecord, importOnlyQualified) + local bracketData = matchRecord.match2bracketdata + return not importOnlyQualified or Logic.readBool(bracketData.quallose) or + Logic.readBool(bracketData.qualwin) and tonumber(matchRecord.winner) == opponentIndex +end + +---@param opponentRecord table +---@return ParticipantTableEntry? +function Parser._entryFromOpponentRecord(opponentRecord) + local opponent = Opponent.fromMatch2Record(opponentRecord) --[[@as standardOpponent]] + if Opponent.isTbd(opponent) then + return + end + return { + opponent = opponent, + name = opponentRecord.name, + } +end + +return Parser \ No newline at end of file diff --git a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua index 47811fc4e25..2aa493fb816 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua @@ -174,7 +174,6 @@ function Parser._readEntry(sectionArgs, key, index, config) dq = Logic.readBool(opponentArgs.dq), note = opponentArgs.note, opponent = opponent, - inputIndex = index, seed = opponentArgs.seed, } end diff --git a/lua/wikis/commons/Features/ParticipantTable/Lib/Util.lua b/lua/wikis/commons/Features/ParticipantTable/Lib/Util.lua new file mode 100644 index 00000000000..01c79bceca9 --- /dev/null +++ b/lua/wikis/commons/Features/ParticipantTable/Lib/Util.lua @@ -0,0 +1,45 @@ +--- +-- @Liquipedia +-- page=Module:Features/ParticipantTable/Lib/Util +-- +-- Please see https://github.com/Liquipedia/Lua-Modules to contribute +-- + +local Lua = require('Module:Lua') + +local Array = Lua.import('Module:Array') +local Opponent = Lua.import('Module:Opponent/Custom') + +local Util = {} + +---@param section ParticipantTableSection +function Util.backFillEntries(section) + local config = section.config + Array.forEach(section.entries, function(entry) + entry.sortName = entry.sortName or Opponent.toName(entry.opponent) + entry.opponent = entry.isResolved and entry.opponent or Opponent.resolve(entry.opponent, config.resolveDate, { + syncPlayer = config.syncPlayers, + overwritePageVars = true, + }) + entry.name = entry.name or Opponent.toName(entry.opponent) + entry.isResolved = true + end) +end + +---@param section ParticipantTableSection +function Util.sortOpponents(section) + if not section.config.sortOpponents then return end + Array.sortInPlaceBy(section.entries, function(entry) + return entry.sortName:lower() + end) +end + +function Util.hasSeed(sections) + return Array.any(sections, function(section) + return Array.any(section.entries, function(entry) + return entry.seed ~= nil + end) + end) +end + +return Util diff --git a/lua/wikis/commons/Features/ParticipantTable/Types.lua b/lua/wikis/commons/Features/ParticipantTable/Types.lua index 8085acf7689..ccdb4de9f79 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Types.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Types.lua @@ -51,7 +51,6 @@ local Types = {} ---@field name string ---@field note string? ---@field dq boolean ----@field inputIndex integer? ---@field isResolved boolean? ---@field sortName string ---@field seed integer? diff --git a/lua/wikis/commons/ParticipantTable/Base.lua b/lua/wikis/commons/ParticipantTable/Base.lua index 0e31cd6961e..a7c643a4872 100644 --- a/lua/wikis/commons/ParticipantTable/Base.lua +++ b/lua/wikis/commons/ParticipantTable/Base.lua @@ -21,8 +21,10 @@ local Table = Lua.import('Module:Table') local Tournament = Lua.import('Module:Tournament') local Variables = Lua.import('Module:Variables') -local Import = Lua.import('Module:ParticipantTable/Import') +local Import = Lua.import('Module:Features/ParticipantTable/Api/Import') +local ImportParser = Lua.import('Module:Features/ParticipantTable/Lib/ParseImported') local Parser = Lua.import('Module:Features/ParticipantTable/Lib/ParseInput') +local Util = Lua.import('Module:Features/ParticipantTable/Lib/Util') local Display = Lua.import('Module:Features/ParticipantTable/Components/Wrapper') @@ -51,41 +53,19 @@ function ParticipantTable:read() self.sections = Parser.readSections(self.args, self.config) Array.forEach(self.sections, function(section) - self:_adjustSectionWithImport(section) - Array.sortInPlaceBy(section.entries, function(entry) - return section.config.sortOpponents and entry.sortName:lower() or entry.inputIndex or -1 - end) - end) - self.hasSeeds = Array.any(self.sections, function(section) - return Array.any(section.entries, function(entry) - return entry.seed ~= nil + local matchRecords = Import.fromMatchGroupSpec(section.config.matchGroupSpec) + Array.extendWith(section.entries, ImportParser.parseImported(section.config, section.entries, matchRecords)) + Util.backFillEntries(section) + Util.sortOpponents(section) + Array.forEach(section.entries, function(entry) + self:setCustomPageVariables(entry, section.config) end) end) + self.hasSeeds = Util.hasSeed(self.sections) return self end -function ParticipantTable:_adjustSectionWithImport(section) - local config = section.config - if Logic.isEmpty(config.matchGroupSpec) then - return - end - - local entries = section.entries - - Array.forEach(Import.importFromMatchGroupSpec(config, entries), function(entry) - entry.sortName = entry.sortName or Opponent.toName(entry.opponent) - entry.opponent = entry.isResolved and entry.opponent or Opponent.resolve(entry.opponent, config.resolveDate, { - syncPlayer = config.syncPlayers, - overwritePageVars = true, - }) - entry.name = entry.name or Opponent.toName(entry.opponent) - entry.isResolved = true - self:setCustomPageVariables(entry, config) - table.insert(entries, entry) - end) -end - ---@param entry ParticipantTableEntry ---@param config ParticipantTableConfig function ParticipantTable:setCustomPageVariables(entry, config) diff --git a/lua/wikis/commons/ParticipantTable/Import.lua b/lua/wikis/commons/ParticipantTable/Import.lua deleted file mode 100644 index bd5d077cc10..00000000000 --- a/lua/wikis/commons/ParticipantTable/Import.lua +++ /dev/null @@ -1,92 +0,0 @@ ---- --- @Liquipedia --- page=Module:ParticipantTable/Import --- --- Please see https://github.com/Liquipedia/Lua-Modules to contribute --- - -local Lua = require('Module:Lua') - -local Array = Lua.import('Module:Array') -local Logic = Lua.import('Module:Logic') -local Table = Lua.import('Module:Table') - -local Opponent = Lua.import('Module:Opponent/Custom') - -local TournamentStructure = Lua.import('Module:TournamentStructure') - -local ParticipantTableImport = {} - ----@param config ParticipantTableConfig ----@param entries ParticipantTableEntry[] ----@return ParticipantTableEntry[] -function ParticipantTableImport.importFromMatchGroupSpec(config, entries) - local matchRecords = ParticipantTableImport._fetchMatchRecords(config.matchGroupSpec) - if Table.isEmpty(matchRecords) then - return {} - end - ---@type table - local alreadyProcessed = Table.map(entries, function(key, entry) - return entry.name, true - end) - ---@cast matchRecords -nil - return ParticipantTableImport._entriesFromMatchRecords(matchRecords, config, alreadyProcessed) -end - ----@param matchGroupSpec table ----@return table[] -function ParticipantTableImport._fetchMatchRecords(matchGroupSpec) - return mw.ext.LiquipediaDB.lpdb('match2', { - conditions = tostring(TournamentStructure.getMatch2Filter(matchGroupSpec)), - query = 'pagename, match2bracketdata, match2opponents, winner', - order = 'date asc', - limit = 5000, - }) -end - ----@param matchRecords table[] ----@param config ParticipantTableConfig ----@param alreadyProcessed table ----@return ParticipantTableEntry[] -function ParticipantTableImport._entriesFromMatchRecords(matchRecords, config, alreadyProcessed) - local entries = {} - Array.forEach(matchRecords, function(matchRecord) - Array.forEach(matchRecord.match2opponents, function(opponentRecord, opponentIndex) - if not ParticipantTableImport._shouldInclude(opponentIndex, matchRecord, config.importOnlyQualified) then - return - end - - local entry = ParticipantTableImport._entryFromOpponentRecord(opponentRecord) - if not entry or alreadyProcessed[entry.name] then return end - - table.insert(entries, entry) - end) - end) - - return entries -end - ----@param opponentIndex integer ----@param matchRecord table ----@param importOnlyQualified boolean? ----@return boolean -function ParticipantTableImport._shouldInclude(opponentIndex, matchRecord, importOnlyQualified) - local bracketData = matchRecord.match2bracketdata - return not importOnlyQualified or Logic.readBool(bracketData.quallose) or - Logic.readBool(bracketData.qualwin) and tonumber(matchRecord.winner) == opponentIndex -end - ----@param opponentRecord table ----@return ParticipantTableEntry? -function ParticipantTableImport._entryFromOpponentRecord(opponentRecord) - local opponent = Opponent.fromMatch2Record(opponentRecord) --[[@as standardOpponent]] - if Opponent.isTbd(opponent) then - return - end - return { - opponent = opponent, - name = opponentRecord.name, - } -end - -return ParticipantTableImport From c5da081e198349f601595c6d2ee9ddbf9021cd64 Mon Sep 17 00:00:00 2001 From: hjpalpha Date: Wed, 23 Sep 2026 09:06:39 +0000 Subject: [PATCH 10/12] as per review --- .../Features/ParticipantTable/Lib/ParseImported.lua | 4 ++-- .../commons/Features/ParticipantTable/Lib/ParseInput.lua | 9 +++------ lua/wikis/commons/Features/ParticipantTable/Lib/Util.lua | 2 ++ 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseImported.lua b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseImported.lua index a641a55c7fe..52b397fc4f9 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseImported.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseImported.lua @@ -60,7 +60,7 @@ end ---@param opponentRecord table ---@return ParticipantTableEntry? function Parser._entryFromOpponentRecord(opponentRecord) - local opponent = Opponent.fromMatch2Record(opponentRecord) --[[@as standardOpponent]] + local opponent = Opponent.fromMatch2Record(opponentRecord) if Opponent.isTbd(opponent) then return end @@ -70,4 +70,4 @@ function Parser._entryFromOpponentRecord(opponentRecord) } end -return Parser \ No newline at end of file +return Parser diff --git a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua index 2aa493fb816..8d132448c49 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua @@ -14,6 +14,7 @@ local Info = Lua.import('Module:Info', {loadData = true}) local Json = Lua.import('Module:Json') local Logic = Lua.import('Module:Logic') local Lpdb = Lua.import('Module:Lpdb') +local MathUtil = Lua.import('Module:MathUtil') local Namespace = Lua.import('Module:Namespace') local Opponent = Lua.import('Module:Opponent/Custom') local Table = Lua.import('Module:Table') @@ -38,7 +39,7 @@ function Parser.readConfig(args, parentConfig) syncPlayers = Logic.nilOr(Logic.readBoolOrNil(args.syncPlayers), parentConfig.syncPlayers, true), showCountBySection = Logic.readBool(args.showCountBySection or parentConfig.showCountBySection), count = tonumber(args.count), - colSpan = parentConfig.colSpan or tonumber(args.colspan) or 4, + colSpan = parentConfig.colSpan or MathUtil.toInteger(args.colspan) or 4, onlyNotable = Logic.readBool(args.onlyNotable or parentConfig.onlyNotable), resolveDate = args.date or parentConfig.resolveDate or DateExt.getContextualDate(), sortPlayers = Logic.nilOr(Logic.readBoolOrNil(args.sortPlayers), Logic.readBoolOrNil(args.sortPlayers), @@ -163,11 +164,7 @@ function Parser._readEntry(sectionArgs, key, index, config) local opponent = Opponent.readOpponentArgs(opponentArgs) if config.sortPlayers and opponent.players then - table.sort(opponent.players, function (player1, player2) - local name1 = (player1.displayName or player1.pageName):lower() - local name2 = (player2.displayName or player2.pageName):lower() - return name1 < name2 - end) + Array.sortInPlaceBy(opponent.players, function(player) return (player.displayName or player.pageName):lower() end) end return { diff --git a/lua/wikis/commons/Features/ParticipantTable/Lib/Util.lua b/lua/wikis/commons/Features/ParticipantTable/Lib/Util.lua index 01c79bceca9..3cc52611c23 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Lib/Util.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Lib/Util.lua @@ -34,6 +34,8 @@ function Util.sortOpponents(section) end) end +---@param sections ParticipantTableSection[] +---@return boolean function Util.hasSeed(sections) return Array.any(sections, function(section) return Array.any(section.entries, function(entry) From 339e191bcc7a4196a6de533e725d0eb1949e375f Mon Sep 17 00:00:00 2001 From: hjpalpha Date: Wed, 23 Sep 2026 09:22:53 +0000 Subject: [PATCH 11/12] use set --- .../Features/ParticipantTable/Lib/ParseImported.lua | 13 ++++++------- .../Features/ParticipantTable/Lib/ParseInput.lua | 8 +++++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseImported.lua b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseImported.lua index 52b397fc4f9..42f2de208d2 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseImported.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseImported.lua @@ -9,8 +9,9 @@ local Lua = require('Module:Lua') local Array = Lua.import('Module:Array') local Logic = Lua.import('Module:Logic') +local Operator = Lua.import('Module:Operator') local Opponent = Lua.import('Module:Opponent/Custom') -local Table = Lua.import('Module:Table') +local Set = Lua.import('Module:Set') local Parser = {} @@ -22,10 +23,8 @@ function Parser.parseImported(config, entries, matchRecords) if Logic.isEmpty(matchRecords) then return {} end - ---@type table - local alreadyProcessed = Table.map(entries, function(key, entry) - return entry.name, true - end) + ---@type Set + local alreadyProcessed = Set(Array.map(entries, Operator.property('name'))) ---@cast matchRecords -nil local newEntries = {} @@ -36,9 +35,9 @@ function Parser.parseImported(config, entries, matchRecords) end local entry = Parser._entryFromOpponentRecord(opponentRecord) - if not entry or alreadyProcessed[entry.name] then return end + if not entry or alreadyProcessed:contains(entry.name) then return end - alreadyProcessed[entry.name] = true + alreadyProcessed:add(entry.name) table.insert(newEntries, entry) end) diff --git a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua index 8d132448c49..655a8e82656 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua @@ -17,6 +17,7 @@ local Lpdb = Lua.import('Module:Lpdb') local MathUtil = Lua.import('Module:MathUtil') local Namespace = Lua.import('Module:Namespace') local Opponent = Lua.import('Module:Opponent/Custom') +local Set = Lua.import('Module:Set') local Table = Lua.import('Module:Table') local TournamentStructure = Lua.import('Module:TournamentStructure') local Variables = Lua.import('Module:Variables') @@ -101,7 +102,8 @@ end ---@param config ParticipantTableConfig ---@return ParticipantTableEntry[] function Parser._readEntries(args, config) - local alreadyUsed = {} + ---@type Set + local alreadyUsed = Set{} return Table.mapArgumentsByPrefix(args, {'p', 'player'}, function(key, index) local entry = Parser._readEntry(args, key, index, config) @@ -119,11 +121,11 @@ function Parser._readEntries(args, config) entry.isResolved = true entry.name = Opponent.toName(entry.opponent) - if alreadyUsed[entry.name] then + if alreadyUsed:contains(entry.name) then error('Duplicate Input "|' .. key .. '=' .. args[key] .. '"') end - alreadyUsed[entry.name] = true + alreadyUsed:add(entry.name) return entry end) From 28148acc338a719d1f708b7e8a84f5c17f4265ed Mon Sep 17 00:00:00 2001 From: hjpalpha Date: Fri, 2 Oct 2026 15:52:03 +0000 Subject: [PATCH 12/12] as per review --- .../commons/Features/ParticipantTable/Lib/ParseInput.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua index 655a8e82656..8dce6b15230 100644 --- a/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua +++ b/lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua @@ -43,7 +43,7 @@ function Parser.readConfig(args, parentConfig) colSpan = parentConfig.colSpan or MathUtil.toInteger(args.colspan) or 4, onlyNotable = Logic.readBool(args.onlyNotable or parentConfig.onlyNotable), resolveDate = args.date or parentConfig.resolveDate or DateExt.getContextualDate(), - sortPlayers = Logic.nilOr(Logic.readBoolOrNil(args.sortPlayers), Logic.readBoolOrNil(args.sortPlayers), + sortPlayers = Logic.nilOr(Logic.readBoolOrNil(args.sortPlayers), parentConfig.sortPlayers, (Info.config.participants or {}).sortPlayersInTable), sortOpponents = Logic.nilOr(Logic.readBoolOrNil(args.sortOpponents), parentConfig.sortOpponents, true), showTeams = showTeams, @@ -62,6 +62,8 @@ function Parser.readConfig(args, parentConfig) return faction, tonumber(args[Faction.toName(faction):lower()]) end), factionColumnWidth = tonumber(args.entrywidth) or showTeams and 212 or 156, + -- todo: remove the fallback after bot runs (after merge) + showCountByFaction = Logic.readBool(args.countByFaction or args.count), } config.width = parentConfig.width