Jump to content

Module:Icon: Difference between revisions

From The Petit Planet Wiki
No edit summary
No edit summary
 
(5 intermediate revisions by the same user not shown)
Line 1: Line 1:
-- Source: https://coralisland.fandom.com/wiki/Module:Icon
--- A library that other modules can use to create icon images with automatic prefix/suffix settings for items, characters, and weapons.
--  (Other icon types must have their types/suffixes specified manually.)
--
--  '''Note:''' this module is (currently) NOT related to [[Template:Icon]].
--
--  @script Icon
 
local TemplateData = require('Module:TemplateData')


local p = {}
local p = {}
local lib = require('Module:Feature')
local LL = require('Module:Link label')._main


function p.main(frame)
local FOOD_PREFIXES = {
local args = require('Module:Arguments').getArgs(frame, {
['Suspicious '] = 1,
parentFirst = true,
['Delicious '] = 1,
removeBlanks = false,
}
wrapper = { 'Template:Icon' }
 
})
-- icon arg defaults for template data
return p._main(args)
-- uses list format to ensure that the order is the same when added to another list of args using `p.addIconArgs`
local ICON_ARGS = {
{name='name',
label='Name',
description='The name of the {labelPrefix}image.',
example={'Furnishing Blueprint', 'Fruit Paste Bait', 'Anemo'}
},
{name='link', displayType='wiki-page-name', defaultFrom='name',
label='Link',
description='The page that the {labelPrefix}image links to.'
},
{name='extension', alias='ext', default='png',
label='File Extension',
description='The file extension for the {labelPrefix}image.',
example={'png', 'jpg', 'jpeg', 'gif'},
},
{name='type', displayDefault='determined based on {labelPrefix}Name; "Item" if unknown',
label='File Prefix',
description='The file prefix to prepend to {labelPrefix}Name.',
example={'Item', 'Weapon', 'Character', 'Icon'}
},
{name='suffix', displayDefault='determined based on {labelPrefix}Name/{labelPrefix}Type',
label='File Suffix',
description='The file suffix to append to {labelPrefix}Name.',
example={'Icon', 'Thumb', '2nd', 'White'}
},
{name='size', default='20',
label='Size',
description='The height and width of the {labelPrefix}image in pixels. A single number will be used for both height and width; to specify them separately, use \'wxh\' format.',
example={'20', '20x10', '20x', 'x20'}
},
{name='alt', defaultFrom='name', displayDefault='determined based on {labelPrefix}Name, and updated based on {labelPrefix}Character Outfit and {labelPrefix}Weapon Ascension Phase',
label='Alt Text',
description='The alt text of the {labelPrefix}image.',
},
{name='outfit', alias='o',
label='Character Outfit',
description='Name of the Outfit equipped on the character in the {labelPrefix}image. (Ignored if not a character.)',
example='Sea Breeze Dandelion'
},
{name='ascension', alias='a', type='number', default=0,
label='Weapon Ascension Phase',
description='Ascension Phase of the weapon in the {labelPrefix}image. (Weapon image changes for ascension 2 or higher. Ignored if not a weapon.)',
example={'1', '2'}
},
}
 
--- Returns a table version of the input.
--  @param v A table or an item that belongs in a table.
--  @return {table}
local function ensureTable(v)
if type(v) == 'table' then return v end
return {v}
end
 
--- A special constant that can be used as a value in the `overrides` parameter for `addIconArgs`
--  to disable the given base config or TemplateData key.
p.EXCLUDE = {};
 
--- Copy entries from b into a, excluding values that are `p.EXCLUDE`.
--  @param {table} a Table to insert into.
--  @param {table} b Table to copy from.
local function copyTable(a, b)
for k, v in pairs(b) do
if v == p.EXCLUDE then
v = nil
end
a[k] = v
end
end
end


function p._main(args)
--- A function that other modules can use to append Icon arguments to their template data.
local item = args.name or args[1]
--  @param {TemplateData#ArgumentConfigList} base The template data to append to.
if not item then return mw.html.create() end -- if no input then return blank
--        If any configs have a `name` that matches an Icon argument's (with `namePrefix`)
local nolink = lib.isNotEmpty(args.nolink) or false
--         and a property `placeholderFor` set to `'Module:Icon'`, then the
local notext = lib.isNotEmpty(args.notext) or false
--        corresponding Icon argument will replace it instead of being appended.
local link = nolink and '' or (args.link or item)
--        (This allows argument order to be changed for [[Module:TemplateData]]'s
local size = tonumber(args.size or args.s or '30')
--        documentation generation.)
local M_size = size
--  @param {string} namePrefix A string to prepend to all parameter names.
local upscale
--  @param {string} labelPrefix A string to prepend to all parameter labels
if M_size < 51 then
--    (the names displayed in documentation).
M_size = 51
--  @param {TemplateData#ArgumentConfigMap} overrides A table of overrides to configure the template data.
--    Keys should be parameter names, and values are tables of TemplateData
--figure out what to size to default back down to
--    configuration objects to merge with the default configuration.
--  multiples of 8 as they wont become decimal in any screen density
--    These configuration objects can use @{Icon.EXCLUDE} as values to disable
if     size < 24 then upscale = '16'
--    the corresponding default configuration key (e.g., to disable a default value
elseif size < 32 then upscale = '24'
--    or alias without adding a new one).
elseif size < 40 then upscale = '32'
function p.addIconArgs(baseConfigs, namePrefix, labelPrefix, overrides)
elseif size < 48 then upscale = '40'
-- preprocessing: save position of each placeholder config
else                  upscale = '48'
local argLocations = {}
for i, config in ipairs(baseConfigs) do
if config.placeholderFor == 'Module:Icon' then
argLocations[config.name] = i
end
end
end -- 50px and below gets autoformatted into infoicon
end
local ext = args.ext or 'png'
local amount = args.amount or args.x or args[2]
local text = args.text or args[3]
local note = args.note
-- mw.logObject(args)
local prefix = args.prefix or ''
local suffix = args.suffix or ''
prefix = prefix:gsub('{space}', ' ')
suffix = suffix:gsub('{space}', ' ')
local icon = mw.html.create():tag('span'):addClass('custom-icon')
-- main loop: prepend namePrefix and labelPrefix where needed
local icon_image = icon:tag('span'):addClass('custom-icon-image desktop-only')
-- and add configs to baseConfigs
local M_icon_image = icon:tag('span'):addClass('custom-icon-image mobile-only hidden noborder')
for _, config in ipairs(ICON_ARGS) do
local icon_text = icon:tag('span'):addClass('custom-icon-text')
local override = overrides[config.name]
if override ~= false and override ~= p.EXCLUDE then
local c = {}
copyTable(c, config)
c.name = namePrefix .. c.name
c.label = labelPrefix .. c.label
if c.defaultFrom then
c.defaultFrom = namePrefix .. c.defaultFrom
end
if c.alias then
local aliases = {}
for _, a in ipairs(ensureTable(c.alias)) do
table.insert(aliases, namePrefix .. a)
end
c.alias = aliases
end
if override then
copyTable(c, override)
end
if c.description then
c.description = c.description:gsub('{labelPrefix}', labelPrefix)
end
if c.displayDefault then
c.displayDefault = c.displayDefault:gsub('{labelPrefix}', labelPrefix)
end
local placeholderIndex = argLocations[c.name]
if placeholderIndex then
baseConfigs[placeholderIndex] = c
else
table.insert(baseConfigs, c)
end
end
end
end
 
local function extendTable(base, extra)
out = {}
setmetatable(out, {
__index = function(t, key)
-- be defensive: base or extra may be nil
local val
if base ~= nil then
val = base[key]
end
if val ~= nil then
return val
end
if extra ~= nil then
return extra[key]
end
return nil
end
})
return out
end
 
local neighbors = mw.loadData('Module:Card/neighbors')
local ALL_DATA = {-- list of {type, data} in the order that untyped items should get checked
{'Neighbor', neighbors},
{'Creature', mw.loadData('Module:Card/creatures')},
{'Dish', mw.loadData('Module:Card/dishes')},
{'Plant', mw.loadData('Module:Card/plants')},
{'Furniture', mw.loadData('Module:Card/furnitures')},
{'Outfit', mw.loadData('Module:Card/outfits')},
{'Item', extendTable(characters, mw.loadData('Module:Card/items'))} -- allow characters to be items
}
 
--- A basic image type with filename prefix/suffix support.
--  Extends @{TemplateData#TableWithDefaults} with image-related properties,
--  allowing default property values to be customized after creation.
--
--  Image objects are created by @{Icon.createIcon}.
--  Use @{Image:buildString} to convert to wikitext.
--  @type Image
local IMAGE_ARGS = {
size = {default=''},
name = {default='', alias=1},
prefix = {default=''},
prefixSeparator = {default=' '},
suffix = {default=''},
suffixSeparator = {default=' '},
extension = {default='png', alias='ext'},
link = {defaultFrom='name'},
alt = {defaultFrom='name'},
}
 
local function buildImageFullPrefix(img)
local prefix = img.prefix
if prefix ~= '' then
return prefix .. img.prefixSeparator
end
return ''
end
local function buildImageFullSuffix(img)
local suffix = img.suffix
if suffix ~= '' then
return img.suffixSeparator .. suffix
end
return ''
end
local function buildImageFilename(img)
if img.name == '' then return '' end
return 'File:' .. buildImageFullPrefix(img) .. img.name .. buildImageFullSuffix(img) .. '.' .. img.extension
end
local function buildImageSizeString(img)
local size = img.size
if size == nil or size == '' then
return ''
end
size = tostring(size)
if size:find('x', 1, true) then
return size .. 'px'
end
return size .. 'x' .. size .. 'px'
end
--[[
Returns wikitext that will display this image.
@return {string} Wikitext
@function Image:buildString
--]]
local function buildImageString(img)
local filename = buildImageFilename(img)
if filename == '' then return '' end
return '[[' .. filename .. '|' .. buildImageSizeString(img) .. '|link=' .. img.link .. '|alt=' .. img.alt .. ']]'
end
 
--[[
Creates an `Image` object with the given properties.
@param {table} args A table of `Image` properties that to assign to the new `Image`.
@see @{Image} for property documentation
@return {Image} The new `Image` object.
@constructor
--]]
local function createImage(args)
local out
if type(args) == 'table' then
out = TemplateData.processArgs(args, IMAGE_ARGS, {preserveDefaults=true})
else
out = {name = args}
end
-- add buildString function to image directly, not to image.nonDefaults
if upscale then
rawset(out, 'buildString', buildImageString)
M_icon_image:addClass('upscaled upscaled-' .. upscale)
return out
end
 
--- The name of the image. Used to determine filename.
--  @property {string} Image.name
 
--- Maximum image size using wiki image syntax.
--  Unlike regular wiki image syntax, a single number specifies both height and width.
--  @property {string} Image.size
 
--- Image file prefix.
--  @property {string} Image.prefix
 
--- Appended to `prefix` if `prefix` is not empty. Defaults to a single space.
--  @property[opt] {string} Image.prefixSeparator
 
--- Image file suffix.
--  @property {string} Image.suffix
 
--- Prepended to `suffix` if `suffix` is not empty. Defaults to a single space.
--  @property {string} Image.suffixSeparator
 
--- Image file extension. (Alias: `ext`.)
--  @property {string} Image.extension
 
--- Image link. Also sets title (hover tooltip). Defaults to `name`.
--  @property {string} Image.link
 
--- Image alt text. Defaults to `name`.
--  @property {string} Image.alt
 
 
--- A helper function for other modules to get icon args with a prefix from the given table.
--  @param {table} args A table containing icon args (and probably other args).
--  @param {string} prefix Prefix for keys to use when looking up entries from `args`.
--    If not specified, no prefix is used.
--  @return {table} A table containing only the extracted args, with the prefix removed from its keys.
function p.extractIconArgs(args, prefix)
prefix = prefix or ''
local out = TemplateData.createObjectWithDefaults()
for _, config in pairs(ICON_ARGS) do
out.defaults[config.name] = args.defaults[prefix .. config.name]
out.nonDefaults[config.name] = args.nonDefaults[prefix .. config.name]
end
end
return out
-- main icon image
end
local filename = table.concat({prefix, item, suffix})
 
icon_image:wikitext('[[File:', filename, ' Icon.', ext, '|', size, 'px|link=', link, ']]')
--- A helper function that removes one of the given prefixes from the given string.
M_icon_image:wikitext('[[File:', filename, ' Icon.', ext, '|', M_size, 'px|link=', link, ']]')
-- @param {string} str The string from which to strip a prefix
--  @param {table} prefixes A table whose keys are the possible prefixes to strip from `str`
-- auto link unless disable
--  @return {string} The string with the prefix removed.
if not notext then
--  @return[opt] {string} The prefix that was removed, or `nil` if no prefix was found.
if link == '' then icon_text:wikitext(' ', item)
function p.stripPrefixes(str, prefixes)
elseif link == item then icon_text:wikitext(' ', LL(item))
for prefix, _ in pairs(prefixes) do
else icon_text:wikitext(' [[', link, '|', item, ']]')
if string.sub(str, 1, string.len(prefix)) == prefix then
return string.sub(str, string.len(prefix) + 1), prefix
end
end
end
end
return str
end
--[[
    The main entry point for other modules.
    Creates and returns an Image object with the given arguments.
    Infers `args.type` if `args.name` matches a known item/character/weapon.
    @param {table} args Table containing the arguments:
    @param[opt] {string} args.name The name of the image.
                        Used to determine file name and set the default link and alt text.
                        If not specified, the output `Image` will produce empty wikitext.
    @param[opt] {string} args.link Image link. Also sets title (hover tooltip).
                        Defaults to `name`.
    @param[opt] {string} args.extension (alias: `ext`) Image file extension.
                        Defaults to 'png'.
    @param[opt] {string} args.type Image type. Used to determine file prefix and default file suffix.
                        If not specified, type will be inferred if `args.name`
                        is a known item; otherwise, defaults to 'Item'.
    @param[opt] {string} args.suffix File suffix override.
    @param[opt] {string} args.size Maximum image size using wiki image syntax.
                        Unlike regular wiki image syntax, specifying a single number will
                        set both height and width.
    @param[opt] {string} args.alt Image alt text. Defaults to `args.name`, but
                        also changes with `args.outfit` or `args.ascension`.
    @param[opt] {string} args.outfit Character outfit. Only applies to character images.
    @param[opt] {number} args.ascension Weapon ascension level. Only applies to weapon images.
    @param[opt] {string} prefix Prefix to use when looking up arguments in `args`.
    @return {Image} The image for given arguments.
      Use `Image:buildString()` to get the wikitext for the image.
    @return {string} The image type.
    @return {TableWithDefaults} Associated data for given item (e.g., rarity, display name).
--]]
function p.createIcon(args, prefix)
if prefix then
args = p.extractIconArgs(args, prefix)
end
args = TemplateData.processArgs(args, ICON_ARGS, {preserveDefaults=true})
local baseName, prefix = p.stripPrefixes(args.name or '', FOOD_PREFIXES)
-- append text if any
-- determine type by checking for data
if lib.isNotEmpty(text) then
local image_type, data
icon_text:wikitext(' ', text)
for i, v in ipairs(ALL_DATA) do
image_type = v[1]
if args.type == nil or args.type == image_type then
data = v[2][baseName]
if data then break end
end
end
end
image_type = args.type or image_type -- in case args.type isn't in ALL_DATA (e.g., Enemy, Wildlife)
-- amount if any
local image = createImage(args)
if lib.isNotEmpty(amount) then
image.suffix = 'Icon'
amount = tonumber(amount) ~= nil and lib.thousandsSeparator(amount) or amount
image.defaults.suffix = 'Icon'
icon_text:wikitext(' × ', amount)
end
-- ending note if any
    return image, image_type, data
if lib.isNotEmpty(note) then
icon_text:wikitext(' (', note, ')')
end
-- mw.logObject(icon) -- debug
return icon
end
end


return p
return p

Latest revision as of 09:33, 10 November 2025

Documentation for this module may be created at Module:Icon/doc

--- A library that other modules can use to create icon images with automatic prefix/suffix settings for items, characters, and weapons.
--  (Other icon types must have their types/suffixes specified manually.)
--
--  '''Note:''' this module is (currently) NOT related to [[Template:Icon]].
--
--  @script Icon

local TemplateData = require('Module:TemplateData')

local p = {}

local FOOD_PREFIXES = {
	['Suspicious '] = 1,
	['Delicious '] = 1,
}

-- icon arg defaults for template data
-- uses list format to ensure that the order is the same when added to another list of args using `p.addIconArgs`
local ICON_ARGS = {
	{name='name',
		label='Name',
		description='The name of the {labelPrefix}image.',
		example={'Furnishing Blueprint', 'Fruit Paste Bait', 'Anemo'}
	},
	{name='link', displayType='wiki-page-name', defaultFrom='name',
		label='Link',
		description='The page that the {labelPrefix}image links to.'
	},
	{name='extension', alias='ext', default='png',
		label='File Extension',
		description='The file extension for the {labelPrefix}image.',
		example={'png', 'jpg', 'jpeg', 'gif'},
	},
	{name='type', displayDefault='determined based on {labelPrefix}Name; "Item" if unknown',
		label='File Prefix',
		description='The file prefix to prepend to {labelPrefix}Name.',
		example={'Item', 'Weapon', 'Character', 'Icon'}
	},
	{name='suffix', displayDefault='determined based on {labelPrefix}Name/{labelPrefix}Type',
		label='File Suffix',
		description='The file suffix to append to {labelPrefix}Name.',
		example={'Icon', 'Thumb', '2nd', 'White'}
	},
	{name='size', default='20',
		label='Size',
		description='The height and width of the {labelPrefix}image in pixels. A single number will be used for both height and width; to specify them separately, use \'wxh\' format.',
		example={'20', '20x10', '20x', 'x20'}
	},
	{name='alt', defaultFrom='name', displayDefault='determined based on {labelPrefix}Name, and updated based on {labelPrefix}Character Outfit and {labelPrefix}Weapon Ascension Phase',
		label='Alt Text',
		description='The alt text of the {labelPrefix}image.',
	},
	{name='outfit', alias='o',
		label='Character Outfit',
		description='Name of the Outfit equipped on the character in the {labelPrefix}image. (Ignored if not a character.)',
		example='Sea Breeze Dandelion'
	},
	{name='ascension', alias='a', type='number', default=0,
		label='Weapon Ascension Phase',
		description='Ascension Phase of the weapon in the {labelPrefix}image. (Weapon image changes for ascension 2 or higher. Ignored if not a weapon.)',
		example={'1', '2'}
	},
}

--- Returns a table version of the input.
--  @param v A table or an item that belongs in a table.
--  @return {table}
local function ensureTable(v)
	if type(v) == 'table' then return v end
	return {v}
end

--- A special constant that can be used as a value in the `overrides` parameter for `addIconArgs`
--  to disable the given base config or TemplateData key.
p.EXCLUDE = {};

--- Copy entries from b into a, excluding values that are `p.EXCLUDE`.
--  @param {table} a Table to insert into.
--  @param {table} b Table to copy from.
local function copyTable(a, b)
	for k, v in pairs(b) do 
		if v == p.EXCLUDE then
			v = nil
		end
		a[k] = v
	end
end

--- A function that other modules can use to append Icon arguments to their template data.
--  @param {TemplateData#ArgumentConfigList} base The template data to append to.
--         If any configs have a `name` that matches an Icon argument's (with `namePrefix`)
--         and a property `placeholderFor` set to `'Module:Icon'`, then the
--         corresponding Icon argument will replace it instead of being appended.
--         (This allows argument order to be changed for [[Module:TemplateData]]'s
--         documentation generation.)
--  @param {string} namePrefix A string to prepend to all parameter names.
--  @param {string} labelPrefix A string to prepend to all parameter labels
--    (the names displayed in documentation).
--  @param {TemplateData#ArgumentConfigMap} overrides A table of overrides to configure the template data.
--    Keys should be parameter names, and values are tables of TemplateData
--    configuration objects to merge with the default configuration.
--    These configuration objects can use @{Icon.EXCLUDE} as values to disable
--    the corresponding default configuration key (e.g., to disable a default value
--    or alias without adding a new one).
function p.addIconArgs(baseConfigs, namePrefix, labelPrefix, overrides)
	-- preprocessing: save position of each placeholder config
	local argLocations = {}
	for i, config in ipairs(baseConfigs) do
		if config.placeholderFor == 'Module:Icon' then
			argLocations[config.name] = i
		end
	end
	
	-- main loop: prepend namePrefix and labelPrefix where needed
	-- and add configs to baseConfigs
	for _, config in ipairs(ICON_ARGS) do
		local override = overrides[config.name]
		if override ~= false and override ~= p.EXCLUDE then
			local c = {}
			copyTable(c, config)
			c.name = namePrefix .. c.name
			c.label = labelPrefix .. c.label
			if c.defaultFrom then
				c.defaultFrom = namePrefix .. c.defaultFrom
			end
			if c.alias then
				local aliases = {}
				for _, a in ipairs(ensureTable(c.alias)) do
					table.insert(aliases, namePrefix .. a)
				end
				c.alias = aliases
			end
			
			if override then
				copyTable(c, override)
			end
			
			if c.description then
				c.description = c.description:gsub('{labelPrefix}', labelPrefix)
			end
			if c.displayDefault then
				c.displayDefault = c.displayDefault:gsub('{labelPrefix}', labelPrefix)
			end
			
			local placeholderIndex = argLocations[c.name]
			if placeholderIndex then
				baseConfigs[placeholderIndex] = c
			else
				table.insert(baseConfigs, c)
			end
		end
	end
end

local function extendTable(base, extra)
	out = {}
	setmetatable(out, {
		__index = function(t, key)
			-- be defensive: base or extra may be nil
			local val
			if base ~= nil then
				val = base[key]
			end
			if val ~= nil then
				return val
			end
			if extra ~= nil then
				return extra[key]
			end
			return nil
		end
	})
	return out
end

local neighbors = mw.loadData('Module:Card/neighbors')
local ALL_DATA = {-- list of {type, data} in the order that untyped items should get checked
	{'Neighbor', neighbors},
	{'Creature', mw.loadData('Module:Card/creatures')},
	{'Dish', mw.loadData('Module:Card/dishes')},
	{'Plant', mw.loadData('Module:Card/plants')},
	{'Furniture', mw.loadData('Module:Card/furnitures')},
	{'Outfit', mw.loadData('Module:Card/outfits')},
	{'Item', extendTable(characters, mw.loadData('Module:Card/items'))} -- allow characters to be items
}

--- A basic image type with filename prefix/suffix support.
--  Extends @{TemplateData#TableWithDefaults} with image-related properties,
--  allowing default property values to be customized after creation.
--
--  Image objects are created by @{Icon.createIcon}.
--  Use @{Image:buildString} to convert to wikitext.
--  @type Image
local IMAGE_ARGS = {
	size = {default=''},
	name = {default='', alias=1},
	prefix = {default=''},
	prefixSeparator = {default=' '},
	suffix = {default=''},
	suffixSeparator = {default=' '},
	extension = {default='png', alias='ext'},
	link = {defaultFrom='name'},
	alt = {defaultFrom='name'},
}

local function buildImageFullPrefix(img)
	local prefix = img.prefix
	if prefix ~= '' then
		return prefix .. img.prefixSeparator
	end
	return ''
end
local function buildImageFullSuffix(img)
	local suffix = img.suffix
	if suffix ~= '' then
		return img.suffixSeparator .. suffix
	end
	return ''
end
local function buildImageFilename(img)
	if img.name == '' then return '' end
	return 'File:' .. buildImageFullPrefix(img) .. img.name .. buildImageFullSuffix(img) .. '.' .. img.extension
end
local function buildImageSizeString(img)
	local size = img.size
	if size == nil or size == '' then
		return ''
	end
	size = tostring(size)
	if size:find('x', 1, true) then
		return size .. 'px'
	end
	return size .. 'x' .. size .. 'px'
end
--[[
Returns wikitext that will display this image.
@return {string} Wikitext
@function Image:buildString
--]]
local function buildImageString(img)
	local filename = buildImageFilename(img)
	if filename == '' then return '' end
	return '[[' .. filename .. '|' .. buildImageSizeString(img) .. '|link=' .. img.link .. '|alt=' .. img.alt .. ']]'
end

--[[
Creates an `Image` object with the given properties.
@param {table} args A table of `Image` properties that to assign to the new `Image`.
@see @{Image} for property documentation
@return {Image} The new `Image` object.
@constructor
--]]
local function createImage(args)
	local out
	if type(args) == 'table' then
		out = TemplateData.processArgs(args, IMAGE_ARGS, {preserveDefaults=true})
	else
		out = {name = args}
	end
	-- add buildString function to image directly, not to image.nonDefaults
	
	rawset(out, 'buildString', buildImageString)
	return out
end

--- The name of the image. Used to determine filename.
--  @property {string} Image.name

--- Maximum image size using wiki image syntax.
--  Unlike regular wiki image syntax, a single number specifies both height and width.
--  @property {string} Image.size

--- Image file prefix.
--  @property {string} Image.prefix

--- Appended to `prefix` if `prefix` is not empty. Defaults to a single space.
--  @property[opt] {string} Image.prefixSeparator

--- Image file suffix.
--  @property {string} Image.suffix

--- Prepended to `suffix` if `suffix` is not empty. Defaults to a single space.
--  @property {string} Image.suffixSeparator

--- Image file extension. (Alias: `ext`.)
--  @property {string} Image.extension

--- Image link. Also sets title (hover tooltip). Defaults to `name`.
--  @property {string} Image.link

--- Image alt text. Defaults to `name`.
--  @property {string} Image.alt


--- A helper function for other modules to get icon args with a prefix from the given table.
--  @param {table} args A table containing icon args (and probably other args).
--  @param {string} prefix Prefix for keys to use when looking up entries from `args`.
--    If not specified, no prefix is used.
--  @return {table} A table containing only the extracted args, with the prefix removed from its keys.
function p.extractIconArgs(args, prefix)
	prefix = prefix or ''
	local out = TemplateData.createObjectWithDefaults()
	for _, config in pairs(ICON_ARGS) do
		out.defaults[config.name] = args.defaults[prefix .. config.name]
		out.nonDefaults[config.name] = args.nonDefaults[prefix .. config.name]
	end
	return out
end

--- A helper function that removes one of the given prefixes from the given string.
--  @param {string} str The string from which to strip a prefix
--  @param {table} prefixes A table whose keys are the possible prefixes to strip from `str`
--  @return {string} The string with the prefix removed.
--  @return[opt] {string} The prefix that was removed, or `nil` if no prefix was found.
function p.stripPrefixes(str, prefixes)
	for prefix, _ in pairs(prefixes) do
		if string.sub(str, 1, string.len(prefix)) == prefix then
			return string.sub(str, string.len(prefix) + 1), prefix
		end
	end
	return str
end

--[[
    The main entry point for other modules.
    Creates and returns an Image object with the given arguments.
    Infers `args.type` if `args.name` matches a known item/character/weapon.
    @param {table} args Table containing the arguments:
    @param[opt] {string} args.name The name of the image.
                         Used to determine file name and set the default link and alt text.
                         If not specified, the output `Image` will produce empty wikitext.
    @param[opt] {string} args.link Image link. Also sets title (hover tooltip).
                         Defaults to `name`.
    @param[opt] {string} args.extension (alias: `ext`) Image file extension.
                         Defaults to 'png'.
    @param[opt] {string} args.type Image type. Used to determine file prefix and default file suffix.
                         If not specified, type will be inferred if `args.name`
                         is a known item; otherwise, defaults to 'Item'.
    @param[opt] {string} args.suffix File suffix override.
    @param[opt] {string} args.size Maximum image size using wiki image syntax.
                         Unlike regular wiki image syntax, specifying a single number will
                         set both height and width.
    @param[opt] {string} args.alt Image alt text. Defaults to `args.name`, but
                         also changes with `args.outfit` or `args.ascension`.
    @param[opt] {string} args.outfit Character outfit. Only applies to character images.
    @param[opt] {number} args.ascension Weapon ascension level. Only applies to weapon images.
    @param[opt] {string} prefix Prefix to use when looking up arguments in `args`.
    @return {Image} The image for given arguments.
      Use `Image:buildString()` to get the wikitext for the image.
    @return {string} The image type.
    @return {TableWithDefaults} Associated data for given item (e.g., rarity, display name).
--]]
function p.createIcon(args, prefix)
	if prefix then
		args = p.extractIconArgs(args, prefix)
	end
	args = TemplateData.processArgs(args, ICON_ARGS, {preserveDefaults=true})
	local baseName, prefix = p.stripPrefixes(args.name or '', FOOD_PREFIXES)
	
	-- determine type by checking for data
	local image_type, data
	for i, v in ipairs(ALL_DATA) do
		image_type = v[1]
		if args.type == nil or args.type == image_type then
			data = v[2][baseName]
			if data then break end
		end
	end
	image_type = args.type or image_type -- in case args.type isn't in ALL_DATA (e.g., Enemy, Wildlife)
	
	local image = createImage(args)
	image.suffix = 'Icon'
	image.defaults.suffix = 'Icon'
	
    return image, image_type, data
end

return p