Module:Crafting usage: Difference between revisions
Mastergalen (talk | contribs) No edit summary |
CraftSpider (talk | contribs) mNo edit summary |
||
(49 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
local i18n = { | |||
emptyCategory = 'Empty crafting usage', | |||
moduleCrafting = [[Module:Crafting]], | |||
moduleSlot = [[Module:Inventory slot]], | |||
queryCategory = 'Recipe using $1', | |||
templateCrafting = 'Crafting', | |||
} | |||
p.i18n = i18n | |||
local slot = require( i18n.moduleSlot ) | |||
local crafting = require( i18n.moduleCrafting ) | |||
local argList = { | |||
'ignoreusage', 'upcoming', 'name', 'ingredients', 'arggroups', | |||
1, 2, 3, 4, 5, 6, 7, 8, 9, | |||
'A1', 'B1', 'C1', 'A2', 'B2', 'C2', 'A3', 'B3', 'C3', | |||
'Output', 'description', 'fixed', 'notfixed', | |||
'A1title', 'A1link', 'B1title', 'B1link', 'C1title', 'C1link', | |||
'A2title', 'A2link', 'B2title', 'B2link', 'C2title', 'C2link', | |||
'A3title', 'A3link', 'B3title', 'B3link', 'C3title', 'C3link', | |||
'Otitle', 'Olink', | |||
} | |||
local prefixes = slot.i18n.prefixes | |||
--[[Escapes the parenthesis in ingredient names, and returns the correct | |||
pattern depending on the match type | |||
--]] | |||
local function createIngredientPatterns( ingredients, matchTypes ) | |||
local patterns = {} | |||
for i, ingredient in ipairs( ingredients ) do | |||
local escaped = ingredient:gsub( '([()])', '%%%1' ) | |||
if not matchTypes then | |||
patterns[i] = '^' .. escaped .. '$' | |||
else | |||
local matchType = matchTypes[i] or matchTypes | |||
if matchType == 'start' then | |||
patterns[i] = '^' .. escaped | |||
elseif matchType == 'end' then | |||
patterns[i] = escaped .. '$' | |||
else | |||
patterns[i] = escaped | |||
end | |||
end | |||
end | |||
return patterns | |||
end | |||
--[[Extracts the anonymous pipe-delimited arguments from the | |||
DPL query into a table with the corresponding keys, skipping | |||
templates with `ignoreusage` set, and skipping duplicate templates | |||
--]] | |||
local extractArgs | |||
do | |||
local seen = {} | |||
extractArgs = function( template ) | |||
-- Check for duplicate template or `ignoreusage` arg | |||
if seen[template] or not template:find( '^\n|' ) then | |||
return | |||
end | |||
seen[template] = true | |||
local tArgs = {} | |||
local i = 1 | |||
for arg in mw.text.gsplit( template, '\n|' ) do | |||
if arg ~= '' then | |||
tArgs[argList[i]] = arg | |||
end | |||
i = i + 1 | |||
end | |||
tArgs.nocat = '1' | |||
return tArgs | |||
end | |||
end | |||
--[[Loops through the crafting args and parses them, with alias reference data | |||
Identical slots reuse the same table, to allow them to be compared like strings | |||
--]] | |||
local function parseCraftingArgs( cArgs ) | |||
local parsedFrameText = {} | |||
local parsedCArgs = {} | |||
for arg, frameText in pairs( cArgs ) do | |||
if frameText then | |||
local randomise = arg == 'Output' and 'never' or nil | |||
local frames = not randomise and parsedFrameText[frameText] | |||
if not frames then | |||
frames = slot.parseFrameText( frameText, randomise, true ) | |||
parsedFrameText[frameText] = frames | |||
end | |||
parsedCArgs[arg] = frames | |||
end | |||
end | |||
return parsedCArgs | |||
end | |||
-- Loops through the wanted ingredients, and checks if the name contains it | |||
local function containsIngredients( name, ingredientPatterns ) | |||
for _, ingredient in pairs( ingredientPatterns ) do | |||
if name:find( ingredient ) then | |||
return true | |||
end | |||
end | |||
return false | |||
end | |||
--[[Loops through the crafting ingredients and find which parameters and | |||
frames contain the wanted ingredients | |||
Returns a table if any matches are found, the table contains tables of | |||
required frame numbers, or true if all of them are required | |||
--]] | |||
local function findRequiredFrameNums( parsedCArgs, ingredientPatterns ) | |||
local requiredFrameNums = {} | |||
local hasRequiredFrames | |||
for arg, frames in pairs( parsedCArgs ) do | |||
if arg ~= 'Output' then | |||
local requiredFrames = {} | |||
local count = 0 | |||
for i, frame in ipairs( frames ) do | |||
if containsIngredients( frame.name or frame[1].name, ingredientPatterns ) then | |||
requiredFrames[i] = true | |||
count = count + 1 | |||
end | |||
end | |||
if count > 0 then | |||
if count == #frames then | |||
return true | |||
end | |||
hasRequiredFrames = true | |||
requiredFrames.count = count | |||
requiredFrameNums[arg] = requiredFrames | |||
end | |||
end | |||
end | |||
return hasRequiredFrames and requiredFrameNums | |||
end | |||
--[[Generates the argument groups, either using the template's specified | |||
groups, or automatically based on the number of frames in each slot | |||
--]] | |||
local function generateArgGroups( predefinedArgGroups, parsedCArgs ) | |||
local argGroups = {} | |||
if predefinedArgGroups or '' ~= '' then | |||
local i = 1 | |||
for argGroup in mw.text.gsplit( predefinedArgGroups, '%s*;%s*' ) do | |||
local groupData = { args = {} } | |||
for arg in mw.text.gsplit( argGroup, '%s*,%s*' ) do | |||
arg = tonumber( arg ) or arg | |||
if not groupData.count then | |||
groupData.count = #parsedCArgs[arg] | |||
end | |||
groupData.args[arg] = true | |||
end | |||
argGroups[i] = groupData | |||
i = i + 1 | |||
end | |||
else | |||
for arg, frames in pairs( parsedCArgs ) do | |||
local framesLen = #frames | |||
if framesLen > 0 then | |||
local groupName = framesLen | |||
local alias = frames.aliasReference and frames.aliasReference[1] | |||
if alias and alias.length == framesLen and | |||
alias.frame.name:find( '^' .. prefixes.any .. ' ' ) | |||
then | |||
groupName = alias.frame.name | |||
end | |||
local groupData = argGroups[groupName] | |||
if not groupData then | |||
groupData = { | |||
args = {}, | |||
count = framesLen | |||
} | |||
argGroups[groupName] = groupData | |||
end | |||
groupData.args[arg] = true | |||
end | |||
end | |||
end | |||
return argGroups | |||
end | |||
--[[Adds together the required frames from each slot in this group | |||
to get the total amount of frames which are relevant | |||
Returns a table with the relevant frame numbers, if any are relevant | |||
--]] | |||
local function findRelevantFrameNums( requiredFrameNumData, group ) | |||
local relevantFrameNums = {} | |||
local hasRelevantFrames | |||
for arg in pairs( group ) do | |||
local requiredFrameNums = requiredFrameNumData[arg] | |||
if requiredFrameNums and arg ~= 'Output' then | |||
for frameNum in pairs( requiredFrameNums ) do | |||
-- Have to use pairs as it contains a non-sequential set of numbers | |||
-- so we have to skip over the extra data in the table | |||
if frameNum ~= 'count' then | |||
hasRelevantFrames = true | |||
relevantFrameNums[frameNum] = true | |||
end | |||
end | |||
relevantFrameNums.count = math.max( | |||
requiredFrameNums.count or 0, | |||
relevantFrameNums.count or 0 | |||
) | |||
end | |||
end | |||
return hasRelevantFrames and relevantFrameNums | |||
end | |||
--[[Loops through the relevant frame numbers and extracts them | |||
into a new table, taking care of moving any alias references | |||
and cleaning up any unnecessary subframes | |||
--]] | |||
function p.extractRelevantFrames( relevantFrameNums, frames ) | |||
local relevantFrames = { randomise = frames.randomise } | |||
local newFrameNum = 1 | |||
for frameNum, frame in ipairs( frames ) do | |||
local relevantFrame = relevantFrameNums == true or relevantFrameNums[frameNum] | |||
if relevantFrame then | |||
if not frame[1] then | |||
local alias = frames.aliasReference and frames.aliasReference[frameNum] | |||
local moveAlias = true | |||
if alias and relevantFrameNums ~= true then | |||
for i = frameNum, alias.length do | |||
if not relevantFrameNums[i] then | |||
moveAlias = false | |||
break | |||
end | |||
end | |||
end | |||
if alias and moveAlias then | |||
if not relevantFrames.aliasReference then | |||
relevantFrames.aliasReference = {} | |||
end | |||
relevantFrames.aliasReference[newFrameNum] = alias | |||
end | |||
end | |||
relevantFrames[newFrameNum] = frame | |||
newFrameNum = newFrameNum + 1 | |||
end | |||
end | |||
-- Move frames in subframe to main frames, if the subframe | |||
-- is the only frame | |||
if not relevantFrames[2] and relevantFrames[1][1] then | |||
relevantFrames = relevantFrames[1] | |||
end | |||
return relevantFrames | |||
end | |||
--[[Works out what data is relevant to the requested ingredients | |||
If the template contains any of the ingredients, returns it with any | |||
necessary modifications, and with the crafting arguments parsed | |||
--]] | |||
function p.processTemplate( tArgs, ingredientPatterns ) | |||
local cArgs = {} | |||
for i, v in pairs( crafting.cArgVals ) do | |||
cArgs[i] = tArgs[i] or tArgs[v] | |||
end | |||
cArgs.Output = tArgs.Output | |||
local parsedCArgs = parseCraftingArgs( cArgs ) | |||
local requiredFrameNumData = findRequiredFrameNums( parsedCArgs, ingredientPatterns ) | |||
if not requiredFrameNumData then | |||
return | |||
end | |||
local newCArgs | |||
local modified | |||
if requiredFrameNumData == true then | |||
newCArgs = parsedCArgs | |||
else | |||
local argGroups = generateArgGroups( tArgs.arggroups, parsedCArgs ) | |||
newCArgs = {} | |||
for _, groupData in pairs( argGroups ) do | |||
local group = groupData.args | |||
local relevantFrameNums = findRelevantFrameNums( requiredFrameNumData, group ) | |||
if not relevantFrameNums then | |||
for arg in pairs( group ) do | |||
newCArgs[arg] = parsedCArgs[arg] | |||
end | |||
else | |||
modified = true | |||
for arg in pairs( group ) do | |||
newCArgs[arg] = p.extractRelevantFrames( relevantFrameNums, parsedCArgs[arg] ) | |||
end | |||
end | |||
end | |||
end | |||
-- Convert arguments back to shapeless format if they were originally | |||
if tArgs[1] then | |||
local i = 1 | |||
for argNum = 1, 9 do | |||
tArgs[argNum] = nil | |||
local cArg = newCArgs[argNum] | |||
if cArg then | |||
tArgs[i] = cArg | |||
i = i + 1 | |||
end | |||
end | |||
else | |||
for i, arg in pairs( crafting.cArgVals ) do | |||
tArgs[arg] = newCArgs[i] | |||
end | |||
end | |||
tArgs.Output = newCArgs.Output | |||
tArgs.parsed = true | |||
-- Let Module:Recipe table generate these | |||
-- with the modified crafting args | |||
if modified then | |||
tArgs.name = nil | |||
tArgs.ingredients = nil | |||
end | |||
return tArgs | |||
end | |||
--[[Works out which frame is the first frame, and returns its | |||
name, or alias name, for sorting purposes | |||
--]] | |||
function p.getFirstFrameName( frames, subframe ) | |||
local frame = frames[1] | |||
if not subframe and frame[1] then | |||
return p.getFirstFrameName( frame[1], true ) | |||
end | |||
local alias = frames.aliasReference and frames.aliasReference[1] | |||
return alias and alias.frame.name or frame.name | |||
end | |||
--[[Performs the DPL query which retrieves the arguments from the crafting | |||
templates on the pages within the requested categories | |||
--]] | |||
function dplQuery( category, ignore ) | |||
test = mw.title.new(category, "Category") | |||
test = test.exists | |||
if test then | |||
return mw.getCurrentFrame():callParserFunction( '#dpl:', { | |||
category = category, | |||
-- nottitleregexp = ignore, | |||
include = '{' .. i18n.templateCrafting .. '}:' .. table.concat( argList, ':' ), | |||
mode = 'userformat', | |||
secseparators = '====', | |||
multisecseparators = '====' | |||
} ) | |||
end | |||
return nil | |||
end | |||
--[[The main body, which retrieves the data, and returns the relevant | |||
crafting templates, sorted alphabetically | |||
--]] | |||
function p.dpl( f ) | |||
local args = f | |||
if f == mw.getCurrentFrame() then | |||
args = f:getParent().args | |||
else | |||
f = mw.getCurrentFrame() | |||
end | |||
local ingredients = args[1] and mw.text.split( args[1], '%s*,%s*' ) or { mw.title.getCurrentTitle().text } | |||
local matchTypes = args.match and args.match:find( ',' ) and mw.text.split( args.match, '%s*,%s*' ) or args.match | |||
local ingredientPatterns = createIngredientPatterns( ingredients, matchTypes ) | |||
local data | |||
if args.category then | |||
data = dplQuery( args.category, args.ignore ) | |||
else | |||
-- DPL has a limit of four categories, so do it in chunks | |||
data = {} | |||
local dataNum = 1 | |||
local ingredientCount = #ingredients | |||
local catParts = mw.text.split( i18n.queryCategory, '%$1' ) | |||
for i = 1, ingredientCount, 4 do | |||
data[dataNum] = dplQuery( | |||
catParts[1] .. table.concat( | |||
ingredients, | |||
catParts[2] .. '|' .. catParts[1], | |||
i, | |||
math.min( i + 3, ingredientCount ) | |||
) .. catParts[2], | |||
args.ignore | |||
) | |||
dataNum = dataNum + 1 | |||
end | |||
data = table.concat( data ) | |||
end | |||
if data == nil or data == "" then | |||
return "Recipe Category not found" | |||
end | |||
local showDescription | |||
local templates = {} | |||
local i = 1 | |||
for templateArgs in mw.text.gsplit( data:sub( 5 ), '====' ) do | |||
local tArgs = extractArgs( templateArgs ) | |||
local newArgs = tArgs and p.processTemplate( tArgs, ingredientPatterns ) | |||
if newArgs then | |||
if tArgs.description then | |||
showDescription = '1' | |||
end | |||
templates[i] = { | |||
args = newArgs, | |||
sortKey = mw.ustring.lower( | |||
( newArgs.name or p.getFirstFrameName( newArgs.Output ) ) | |||
:gsub( '^' .. prefixes.any .. ' ', '' ) | |||
:gsub( '^' .. prefixes.matching .. ' ', '' ) | |||
:gsub( '^%[%[', '' ) | |||
:gsub( '^[^|]+|', '' ) | |||
), | |||
} | |||
i = i + 1 | |||
end | |||
end | |||
local templateCount = #templates | |||
if templateCount == 0 then | |||
return f:expandTemplate{ title = 'Translation category', args = { i18n.emptyCategory, project = '0' } } | |||
end | |||
table.sort( templates, function( a, b ) | |||
return a.sortKey < b.sortKey | |||
end ) | |||
local initialArgs = templates[1].args | |||
initialArgs.head = '1' | |||
initialArgs.showname = '1' | |||
initialArgs.showdescription = showDescription | |||
if not args.continue then | |||
templates[templateCount].args.foot = '1' | |||
end | |||
local out = {} | |||
for i, template in ipairs( templates ) do | |||
out[i] = crafting.table( template.args ) | |||
end | |||
return table.concat( out, '\n' ) | |||
end | end | ||
return p | return p |
Latest revision as of 00:32, 15 May 2017
This module implements {{Crafting usage}}.
Dependencies
The above documentation is transcluded from Module:Crafting usage/doc.
This module implements {{Crafting usage}}.
Dependencies
local p = {}
local i18n = {
emptyCategory = 'Empty crafting usage',
moduleCrafting = [[Module:Crafting]],
moduleSlot = [[Module:Inventory slot]],
queryCategory = 'Recipe using $1',
templateCrafting = 'Crafting',
}
p.i18n = i18n
local slot = require( i18n.moduleSlot )
local crafting = require( i18n.moduleCrafting )
local argList = {
'ignoreusage', 'upcoming', 'name', 'ingredients', 'arggroups',
1, 2, 3, 4, 5, 6, 7, 8, 9,
'A1', 'B1', 'C1', 'A2', 'B2', 'C2', 'A3', 'B3', 'C3',
'Output', 'description', 'fixed', 'notfixed',
'A1title', 'A1link', 'B1title', 'B1link', 'C1title', 'C1link',
'A2title', 'A2link', 'B2title', 'B2link', 'C2title', 'C2link',
'A3title', 'A3link', 'B3title', 'B3link', 'C3title', 'C3link',
'Otitle', 'Olink',
}
local prefixes = slot.i18n.prefixes
--[[Escapes the parenthesis in ingredient names, and returns the correct
pattern depending on the match type
--]]
local function createIngredientPatterns( ingredients, matchTypes )
local patterns = {}
for i, ingredient in ipairs( ingredients ) do
local escaped = ingredient:gsub( '([()])', '%%%1' )
if not matchTypes then
patterns[i] = '^' .. escaped .. '$'
else
local matchType = matchTypes[i] or matchTypes
if matchType == 'start' then
patterns[i] = '^' .. escaped
elseif matchType == 'end' then
patterns[i] = escaped .. '$'
else
patterns[i] = escaped
end
end
end
return patterns
end
--[[Extracts the anonymous pipe-delimited arguments from the
DPL query into a table with the corresponding keys, skipping
templates with `ignoreusage` set, and skipping duplicate templates
--]]
local extractArgs
do
local seen = {}
extractArgs = function( template )
-- Check for duplicate template or `ignoreusage` arg
if seen[template] or not template:find( '^\n|' ) then
return
end
seen[template] = true
local tArgs = {}
local i = 1
for arg in mw.text.gsplit( template, '\n|' ) do
if arg ~= '' then
tArgs[argList[i]] = arg
end
i = i + 1
end
tArgs.nocat = '1'
return tArgs
end
end
--[[Loops through the crafting args and parses them, with alias reference data
Identical slots reuse the same table, to allow them to be compared like strings
--]]
local function parseCraftingArgs( cArgs )
local parsedFrameText = {}
local parsedCArgs = {}
for arg, frameText in pairs( cArgs ) do
if frameText then
local randomise = arg == 'Output' and 'never' or nil
local frames = not randomise and parsedFrameText[frameText]
if not frames then
frames = slot.parseFrameText( frameText, randomise, true )
parsedFrameText[frameText] = frames
end
parsedCArgs[arg] = frames
end
end
return parsedCArgs
end
-- Loops through the wanted ingredients, and checks if the name contains it
local function containsIngredients( name, ingredientPatterns )
for _, ingredient in pairs( ingredientPatterns ) do
if name:find( ingredient ) then
return true
end
end
return false
end
--[[Loops through the crafting ingredients and find which parameters and
frames contain the wanted ingredients
Returns a table if any matches are found, the table contains tables of
required frame numbers, or true if all of them are required
--]]
local function findRequiredFrameNums( parsedCArgs, ingredientPatterns )
local requiredFrameNums = {}
local hasRequiredFrames
for arg, frames in pairs( parsedCArgs ) do
if arg ~= 'Output' then
local requiredFrames = {}
local count = 0
for i, frame in ipairs( frames ) do
if containsIngredients( frame.name or frame[1].name, ingredientPatterns ) then
requiredFrames[i] = true
count = count + 1
end
end
if count > 0 then
if count == #frames then
return true
end
hasRequiredFrames = true
requiredFrames.count = count
requiredFrameNums[arg] = requiredFrames
end
end
end
return hasRequiredFrames and requiredFrameNums
end
--[[Generates the argument groups, either using the template's specified
groups, or automatically based on the number of frames in each slot
--]]
local function generateArgGroups( predefinedArgGroups, parsedCArgs )
local argGroups = {}
if predefinedArgGroups or '' ~= '' then
local i = 1
for argGroup in mw.text.gsplit( predefinedArgGroups, '%s*;%s*' ) do
local groupData = { args = {} }
for arg in mw.text.gsplit( argGroup, '%s*,%s*' ) do
arg = tonumber( arg ) or arg
if not groupData.count then
groupData.count = #parsedCArgs[arg]
end
groupData.args[arg] = true
end
argGroups[i] = groupData
i = i + 1
end
else
for arg, frames in pairs( parsedCArgs ) do
local framesLen = #frames
if framesLen > 0 then
local groupName = framesLen
local alias = frames.aliasReference and frames.aliasReference[1]
if alias and alias.length == framesLen and
alias.frame.name:find( '^' .. prefixes.any .. ' ' )
then
groupName = alias.frame.name
end
local groupData = argGroups[groupName]
if not groupData then
groupData = {
args = {},
count = framesLen
}
argGroups[groupName] = groupData
end
groupData.args[arg] = true
end
end
end
return argGroups
end
--[[Adds together the required frames from each slot in this group
to get the total amount of frames which are relevant
Returns a table with the relevant frame numbers, if any are relevant
--]]
local function findRelevantFrameNums( requiredFrameNumData, group )
local relevantFrameNums = {}
local hasRelevantFrames
for arg in pairs( group ) do
local requiredFrameNums = requiredFrameNumData[arg]
if requiredFrameNums and arg ~= 'Output' then
for frameNum in pairs( requiredFrameNums ) do
-- Have to use pairs as it contains a non-sequential set of numbers
-- so we have to skip over the extra data in the table
if frameNum ~= 'count' then
hasRelevantFrames = true
relevantFrameNums[frameNum] = true
end
end
relevantFrameNums.count = math.max(
requiredFrameNums.count or 0,
relevantFrameNums.count or 0
)
end
end
return hasRelevantFrames and relevantFrameNums
end
--[[Loops through the relevant frame numbers and extracts them
into a new table, taking care of moving any alias references
and cleaning up any unnecessary subframes
--]]
function p.extractRelevantFrames( relevantFrameNums, frames )
local relevantFrames = { randomise = frames.randomise }
local newFrameNum = 1
for frameNum, frame in ipairs( frames ) do
local relevantFrame = relevantFrameNums == true or relevantFrameNums[frameNum]
if relevantFrame then
if not frame[1] then
local alias = frames.aliasReference and frames.aliasReference[frameNum]
local moveAlias = true
if alias and relevantFrameNums ~= true then
for i = frameNum, alias.length do
if not relevantFrameNums[i] then
moveAlias = false
break
end
end
end
if alias and moveAlias then
if not relevantFrames.aliasReference then
relevantFrames.aliasReference = {}
end
relevantFrames.aliasReference[newFrameNum] = alias
end
end
relevantFrames[newFrameNum] = frame
newFrameNum = newFrameNum + 1
end
end
-- Move frames in subframe to main frames, if the subframe
-- is the only frame
if not relevantFrames[2] and relevantFrames[1][1] then
relevantFrames = relevantFrames[1]
end
return relevantFrames
end
--[[Works out what data is relevant to the requested ingredients
If the template contains any of the ingredients, returns it with any
necessary modifications, and with the crafting arguments parsed
--]]
function p.processTemplate( tArgs, ingredientPatterns )
local cArgs = {}
for i, v in pairs( crafting.cArgVals ) do
cArgs[i] = tArgs[i] or tArgs[v]
end
cArgs.Output = tArgs.Output
local parsedCArgs = parseCraftingArgs( cArgs )
local requiredFrameNumData = findRequiredFrameNums( parsedCArgs, ingredientPatterns )
if not requiredFrameNumData then
return
end
local newCArgs
local modified
if requiredFrameNumData == true then
newCArgs = parsedCArgs
else
local argGroups = generateArgGroups( tArgs.arggroups, parsedCArgs )
newCArgs = {}
for _, groupData in pairs( argGroups ) do
local group = groupData.args
local relevantFrameNums = findRelevantFrameNums( requiredFrameNumData, group )
if not relevantFrameNums then
for arg in pairs( group ) do
newCArgs[arg] = parsedCArgs[arg]
end
else
modified = true
for arg in pairs( group ) do
newCArgs[arg] = p.extractRelevantFrames( relevantFrameNums, parsedCArgs[arg] )
end
end
end
end
-- Convert arguments back to shapeless format if they were originally
if tArgs[1] then
local i = 1
for argNum = 1, 9 do
tArgs[argNum] = nil
local cArg = newCArgs[argNum]
if cArg then
tArgs[i] = cArg
i = i + 1
end
end
else
for i, arg in pairs( crafting.cArgVals ) do
tArgs[arg] = newCArgs[i]
end
end
tArgs.Output = newCArgs.Output
tArgs.parsed = true
-- Let Module:Recipe table generate these
-- with the modified crafting args
if modified then
tArgs.name = nil
tArgs.ingredients = nil
end
return tArgs
end
--[[Works out which frame is the first frame, and returns its
name, or alias name, for sorting purposes
--]]
function p.getFirstFrameName( frames, subframe )
local frame = frames[1]
if not subframe and frame[1] then
return p.getFirstFrameName( frame[1], true )
end
local alias = frames.aliasReference and frames.aliasReference[1]
return alias and alias.frame.name or frame.name
end
--[[Performs the DPL query which retrieves the arguments from the crafting
templates on the pages within the requested categories
--]]
function dplQuery( category, ignore )
test = mw.title.new(category, "Category")
test = test.exists
if test then
return mw.getCurrentFrame():callParserFunction( '#dpl:', {
category = category,
-- nottitleregexp = ignore,
include = '{' .. i18n.templateCrafting .. '}:' .. table.concat( argList, ':' ),
mode = 'userformat',
secseparators = '====',
multisecseparators = '===='
} )
end
return nil
end
--[[The main body, which retrieves the data, and returns the relevant
crafting templates, sorted alphabetically
--]]
function p.dpl( f )
local args = f
if f == mw.getCurrentFrame() then
args = f:getParent().args
else
f = mw.getCurrentFrame()
end
local ingredients = args[1] and mw.text.split( args[1], '%s*,%s*' ) or { mw.title.getCurrentTitle().text }
local matchTypes = args.match and args.match:find( ',' ) and mw.text.split( args.match, '%s*,%s*' ) or args.match
local ingredientPatterns = createIngredientPatterns( ingredients, matchTypes )
local data
if args.category then
data = dplQuery( args.category, args.ignore )
else
-- DPL has a limit of four categories, so do it in chunks
data = {}
local dataNum = 1
local ingredientCount = #ingredients
local catParts = mw.text.split( i18n.queryCategory, '%$1' )
for i = 1, ingredientCount, 4 do
data[dataNum] = dplQuery(
catParts[1] .. table.concat(
ingredients,
catParts[2] .. '|' .. catParts[1],
i,
math.min( i + 3, ingredientCount )
) .. catParts[2],
args.ignore
)
dataNum = dataNum + 1
end
data = table.concat( data )
end
if data == nil or data == "" then
return "Recipe Category not found"
end
local showDescription
local templates = {}
local i = 1
for templateArgs in mw.text.gsplit( data:sub( 5 ), '====' ) do
local tArgs = extractArgs( templateArgs )
local newArgs = tArgs and p.processTemplate( tArgs, ingredientPatterns )
if newArgs then
if tArgs.description then
showDescription = '1'
end
templates[i] = {
args = newArgs,
sortKey = mw.ustring.lower(
( newArgs.name or p.getFirstFrameName( newArgs.Output ) )
:gsub( '^' .. prefixes.any .. ' ', '' )
:gsub( '^' .. prefixes.matching .. ' ', '' )
:gsub( '^%[%[', '' )
:gsub( '^[^|]+|', '' )
),
}
i = i + 1
end
end
local templateCount = #templates
if templateCount == 0 then
return f:expandTemplate{ title = 'Translation category', args = { i18n.emptyCategory, project = '0' } }
end
table.sort( templates, function( a, b )
return a.sortKey < b.sortKey
end )
local initialArgs = templates[1].args
initialArgs.head = '1'
initialArgs.showname = '1'
initialArgs.showdescription = showDescription
if not args.continue then
templates[templateCount].args.foot = '1'
end
local out = {}
for i, template in ipairs( templates ) do
out[i] = crafting.table( template.args )
end
return table.concat( out, '\n' )
end
return p