Skip to content
24 changes: 11 additions & 13 deletions lua/spec/participant_table_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
},
},
Expand All @@ -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),
},
},
},
Expand All @@ -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,
},
},
},
Expand All @@ -240,7 +240,6 @@ describe('Participant Table', function()
entries = {
{
dq = false,
inputIndex = 2,
isResolved = true,
name = 'Classic_(Kim_Doh_Woo) / ShoWTimE',
opponent = {
Expand All @@ -265,7 +264,6 @@ describe('Participant Table', function()
},
{
dq = false,
inputIndex = 1,
isResolved = true,
name = 'Clem / Lambo',
opponent = {
Expand Down
29 changes: 29 additions & 0 deletions lua/wikis/commons/Features/ParticipantTable/Api/Import.lua
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, number>}
---@return VNode
local function ParticipantTableFactionHeader(props)
Expand All @@ -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{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: ParticipantTableSection,
---factionColumns: string[]}
---@return VNode[]
local function ParticipantTableFactionSection(props)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ 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[],
---factionNumbers: table<string, integer>, sections: StarcraftParticipantTableSection[]}
---@param props {config: ParticipantTableConfig, factionColumns: string[],
---factionNumbers: table<string, integer>, sections: ParticipantTableSection[]}
---@return VNode
local function ParticipantTableFactionTable(props)
local config = props.config
Expand All @@ -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{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
-- @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 Operator = Lua.import('Module:Operator')
local Opponent = Lua.import('Module:Opponent/Custom')
local Set = Lua.import('Module:Set')

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 Set<string>
local alreadyProcessed = Set(Array.map(entries, Operator.property('name')))
---@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:contains(entry.name) then return end

alreadyProcessed:add(entry.name)

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)
if Opponent.isTbd(opponent) then
return
end
return {
opponent = opponent,
name = opponentRecord.name,
}
end

return Parser
182 changes: 182 additions & 0 deletions lua/wikis/commons/Features/ParticipantTable/Lib/ParseInput.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
---
-- @Liquipedia
-- page=Module:Features/ParticipantTable/Lib/ParseInput
--
-- Please see https://github.com/Liquipedia/Lua-Modules to contribute
--

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 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')

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),
Comment thread
hjpalpha marked this conversation as resolved.
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), parentConfig.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,
-- todo: remove the fallback after bot runs (after merge)
showCountByFaction = Logic.readBool(args.countByFaction or args.count),
}

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

---@param args table
---@param config ParticipantTableConfig
---@return ParticipantTableSection[]
function Parser.readSections(args, config)
local sectionsArgs = Array.mapIndexes(function (index)
local parsed = Json.parseIfTable(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(sectionArgs, config)
return {
config = sectionConfig,
entries = Parser._readEntries(sectionArgs, sectionConfig)
}
end)
end

---@param args table
---@param config ParticipantTableConfig
---@return ParticipantTableEntry[]
function Parser._readEntries(args, config)
---@type Set<string>
local alreadyUsed = Set{}

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:contains(entry.name) then
error('Duplicate Input "|' .. key .. '=' .. args[key] .. '"')
end

alreadyUsed:add(entry.name)

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'),
}
Comment thread
ElectricalBoy marked this conversation as resolved.

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
Array.sortInPlaceBy(opponent.players, function(player) return (player.displayName or player.pageName):lower() end)
end

return {
dq = Logic.readBool(opponentArgs.dq),
note = opponentArgs.note,
opponent = opponent,
seed = opponentArgs.seed,
}
end

return Parser
Loading
Loading