This documentation is transcluded from Module:Common/SMW/doc. Changes can be proposed in the talk page.
Module:Common/SMW is shared across the Star Citizen Wikis.
This module is shared across the Star Citizen Wikis. Any changes should also be relayed to the GitHub repository.
Function list |
---|
L 15 — commonSMW.format L 76 — commonSMW.addSmwProperties L 98 — getFromArgs L 247 — commonSMW.addSmwAskProperties L 292 — commonSMW.loadSubobjects L 332 — commonSMW.setFromTable |
Unit tests | |||
---|---|---|---|
Name | Expected | Actual | |
👌 | testFormatNum | ||
👌 | testFormatNumberString | ||
👌 | testFormatNumberStringFail | ||
👌 | testRemoveTypeSuffix | ||
👌 | testRemoveTypeSuffixNoMatch | ||
👌 | testToNumberNum | ||
👌 | testToNumberString | ||
👌 | testToNumberStringFail |
local commonSMW = {}
local common = require( 'Module:Common' )
local libraryUtil = require( 'libraryUtil' )
local checkType = libraryUtil.checkType
local checkTypeMulti = libraryUtil.checkTypeMulti
--- Formats a value to be used by smw.set
---
--- @param datum table An entry from data.json
--- @param val any The value to be formatted
--- @param moduleConfig table Optional, only used for multilingual text (phasing out)
--- @param lang table Content language, uses page language if not set
--- @return any The formatted value
function commonSMW.format( datum, val, moduleConfig, lang )
datum = datum or {}
moduleConfig = moduleConfig or { smw_multilingual_text = false }
-- Format number for SMW
if datum.type == 'number' then
val = common.formatNum( val )
-- Multilingual Text, add a suffix
elseif datum.type == 'multilingual_text' and moduleConfig.smw_multilingual_text == true then
-- FIXME: This is a temp fix to handle tables in val (d280346 in API), need some clean up
if type( val ) == 'table' then
local tmp = {}
for _, valText in ipairs( val ) do
valText = string.format( '%s@%s', valText, moduleConfig.module_lang or mw.getContentLanguage():getCode() )
table.insert( tmp, valText )
end
val = tmp
else
val = string.format( '%s@%s', val, moduleConfig.module_lang or mw.getContentLanguage():getCode() )
end
-- String format
elseif type( datum.format ) == 'string' then
if string.find( datum.format, '%', 1, true ) then
val = string.format( datum.format, val )
elseif datum.format == 'ucfirst' then
lang = lang or mw.getContentLanguage()
val = lang:ucfirst( val )
elseif datum.format == 'replace-dash' then
val = string.gsub( val, '%-', ' ' )
-- Remove part of the value
elseif datum.format:sub( 1, 6 ) == 'remove' then
val = tostring( val ):gsub( mw.text.split( datum.format, ':', true )[ 2 ], '' )
end
-- Min/Max
elseif datum.type == 'minmax' then
val = {
common.formatNum( val.min ),
common.formatNum( val.max ),
}
-- 'Special' boolean case to explicitly set false
elseif datum.type == 'boolean' then
if val == true then
val = 1
else
val = 0
end
end
return val
end
--- Adds SMW properties to a table either from the API or Frame arguments
---
--- @param apiData table Data from the Wiki API
--- @param frameArgs table Frame args processed by Module:Arguments
--- @param smwSetObject table The SMW Object that gets passed to mw.smw.set
--- @param translateFn function The function used to translate argument names
--- @param moduleConfig table Table from config.json
--- @param moduleData table Table from data.json
--- @param moduleName string The module name used to retrieve fallback attribute names
--- @return nil
function commonSMW.addSmwProperties( apiData, frameArgs, smwSetObject, translateFn, moduleConfig, moduleData, moduleName )
checkTypeMulti( 'Module:Common/SMW.addSmwProperties', 1, apiData, { 'table', 'nil' } )
checkType( 'Module:Common/SMW.addSmwProperties', 2, frameArgs, 'table' )
checkType( 'Module:Common/SMW.addSmwProperties', 3, smwSetObject, 'table' )
checkType( 'Module:Common/SMW.addSmwProperties', 4, translateFn, 'function' )
checkType( 'Module:Common/SMW.addSmwProperties', 5, moduleConfig, 'table' )
checkType( 'Module:Common/SMW.addSmwProperties', 6, moduleData, 'table' )
checkType( 'Module:Common/SMW.addSmwProperties', 7, moduleName, 'string' )
local TNT = require( 'Module:Translate' ):new()
local lang
if moduleConfig.module_lang then
lang = mw.getLanguage( moduleConfig.module_lang )
else
lang = mw.getContentLanguage()
end
--- Retrieve value(s) from the frame
---
--- @param datum table An entry from data.smw_data
--- @param argKey string The key to use as an accessor to frameArgs
--- @return string|number|table|nil
local function getFromArgs( datum, argKey )
local value
-- Numbered parameters, e.g. URL1, URL2, URL3, etc.
if datum.type == 'range' and type( datum.max ) == 'number' then
value = {}
for i = 1, datum.max do
local argValue = frameArgs[ argKey .. i ]
if argValue then table.insert( value, argValue ) end
end
-- A "simple" arg
else
value = frameArgs[ argKey ]
end
return value
end
-- Iterate through the list of SMW attributes that shall be filled
for _, datum in ipairs( moduleData.smw_data ) do
-- Retrieve the SMW key and from where the data should be pulled
local smwKey, from
for key, get_from in pairs( datum ) do
if string.sub( key, 1, 3 ) == 'SMW' then
smwKey = key
from = get_from or {}
end
end
if type( from ) ~= 'table' then
from = { from }
end
-- Iterate the list of data sources in order, later sources override previous ones
-- I.e. if the list is Frame Args, API; The api will override possible values set from the frame
for _, key in ipairs( from ) do
local parts = mw.text.split( key, '_', true )
local value
-- Re-assemble keys with multiple '_'
if #parts > 2 then
local tmp = parts[ 1 ]
table.remove( parts, 1 )
parts = {
tmp,
table.concat( parts, '_' )
}
end
--mw.logObject( parts, '✂️ [Common/SMW] Found data key parts' )
-- safeguard check if we have two parts
if #parts == 2 then
-- Retrieve data from frameArgs
if parts[ 1 ] == 'ARG' then
value = getFromArgs( datum, translateFn( key ) or '<UNSET>' )
-- Use EN lang as fallback for arg names that are empty
if value == nil then
local success, translation = pcall(
TNT.formatInLanguage,
'en',
string.format( 'Module:%s/i18n.json', moduleName ),
key
)
if success then
value = getFromArgs( datum, translation )
end
end
-- Retrieve data from API
elseif parts[ 1 ] == 'API' and apiData ~= nil then
--mw.logObject(
-- {
-- key_access = parts[2],
-- value = apiData:get( parts[ 2 ] )
-- },
-- '📡 [Common/SMW] Retrieved API data'
--)
value = apiData:get( parts[ 2 ] )
end
end
-- Transform value based on 'format' key
if value ~= nil then
if type( value ) ~= 'table' then
value = { value }
end
if datum.type == 'table' then
local api = require( 'Module:Common/Api' )
local output = {}
for _, data in ipairs( value ) do
if type( datum.data_key ) == 'string' then
table.insert( output, commonSMW.format( datum, api.makeAccessSafe( data ):get( datum.data_key ), moduleConfig, lang ) )
elseif type( data ) ~= 'table' then -- Format each value if its a normal array
table.insert( output, commonSMW.format( datum, data, moduleConfig, lang ) )
end
end
value = output
elseif datum.type == 'subobject' then
local api = require( 'Module:Common/Api' )
for _, data in ipairs( value ) do
local subobject = {}
data = api.makeAccessSafe( data )
commonSMW.addSmwProperties( data, {}, subobject, translateFn, moduleConfig, datum, moduleName )
mw.smw.subobject( subobject )
end
else
for index, val in ipairs( value ) do
local newValue = mw.clone( val )
if type( newValue ) == 'table' and datum.type ~= 'table' and datum.type ~= 'minmax' and datum.type ~= 'subobject' and datum.type ~= 'multilingual_text' then
newValue = string.format( '!ERROR! Key %s is a table value; please fix', key )
else
newValue = commonSMW.format( datum, newValue, moduleConfig, lang )
end
table.remove( value, index )
table.insert( value, index, newValue )
end
end
if datum.type ~= 'subobject' and type( smwKey ) == 'string' then
if type( value ) == 'table' and #value == 1 then
value = value[ 1 ]
end
-- i18n should be present for SMW property name, but sometimes it doesn't
local smwPropName = translateFn( smwKey ) or smwKey
smwSetObject[ smwPropName ] = value
end
end
end
end
end
--- Adds SMW ask properties to the ask object, based on the keys defined in data.json (moduleData)
---
--- @param smwAskObject table The table that gets passed to mw.smw.ask
--- @param translateFn function The translate function used to translate argument names
--- @param moduleConfig table The module config from config.json
--- @param moduleData table The module data from data.json
--- @return nil
function commonSMW.addSmwAskProperties( smwAskObject, translateFn, moduleConfig, moduleData )
checkType( 'Module:Common/SMW.addSmwAskProperties', 1, smwAskObject, 'table' )
checkType( 'Module:Common/SMW.addSmwAskProperties', 2, translateFn, 'function' )
checkType( 'Module:Common/SMW.addSmwAskProperties', 3, moduleConfig, 'table' )
checkType( 'Module:Common/SMW.addSmwAskProperties', 4, moduleData, 'table' )
local langSuffix = ''
if moduleConfig.smw_multilingual_text == true then
langSuffix = '+lang=' .. ( moduleConfig.module_lang or mw.getContentLanguage():getCode() )
end
for _, queryPart in ipairs( moduleData.smw_data ) do
local smwKey
for key, _ in pairs( queryPart ) do
if string.sub( key, 1, 3 ) == 'SMW' then
smwKey = key
break
end
end
local formatString = '?%s'
if queryPart.smw_format then
formatString = formatString .. queryPart.smw_format
end
-- safeguard
if smwKey ~= nil and translateFn( smwKey ) ~= nil then
table.insert( smwAskObject, string.format( formatString, translateFn( smwKey ) ) )
if queryPart.type == 'multilingual_text' then
table.insert( smwAskObject, langSuffix )
end
end
end
end
--- Retrieve subobjects
---
--- @param pageName string
--- @param identifierPropKey string SMW property key used to identify subobjects
--- @param propKeys table table of SMW property keys
--- @param translateFn function The translate function used to translate argument names
--- @return table
function commonSMW.loadSubobjects( pageName, identifierPropKey, propKeys, translateFn )
checkType( 'Module:Common/SMW.loadSubobjects', 1, pageName, 'string' )
checkType( 'Module:Common/SMW.loadSubobjects', 2, identifierPropKey, 'string' )
checkType( 'Module:Common/SMW.loadSubobjects', 3, propKeys, 'table' )
checkType( 'Module:Common/SMW.loadSubobjects', 4, translateFn, 'function' )
local askQuery = {
'[[-Has subobject::' .. pageName .. ']]',
'[[' .. translateFn( identifierPropKey ) .. '::+]]'
}
for _, propKey in ipairs( propKeys ) do
table.insert( askQuery, string.format( '?%s', translateFn( propKey ) ) )
end
table.insert( askQuery, 'mainlabel=-' )
local subobjects = mw.smw.ask( askQuery )
if subobjects == nil then return {} end
local subobjectTable = {}
for _, subobject in ipairs( subobjects ) do
if subobject[ translateFn( identifierPropKey ) ] then
table.insert( subobjectTable, subobject )
end
end
return subobjectTable
end
--- @param setData table Array data to be set
--- @param tableData table|nil Array data from API
--- @param nameKey string Key of the value being used as name in the SMW property
--- @param valueKey string Key of the value being used as value in the SMW property
--- @param prefix string Prefix of the SMW property name
--- @param translateFn function The translate function used to translate argument names
--- @param formatConfig table An optional format definition in the style of data.json, used for formatting
function commonSMW.setFromTable( setData, tableData, nameKey, valueKey, prefix, translateFn, formatConfig )
checkType( 'Module:Common/SMW.setFromTable', 1, setData, 'table' )
checkTypeMulti( 'Module:Common/SMW.setFromTable', 2, tableData, { 'table', 'nil' } )
checkType( 'Module:Common/SMW.setFromTable', 3, nameKey, 'string' )
checkType( 'Module:Common/SMW.setFromTable', 4, valueKey, 'string' )
checkType( 'Module:Common/SMW.setFromTable', 5, prefix, 'string' )
checkType( 'Module:Common/SMW.setFromTable', 6, translateFn, 'function' )
if tableData == nil or type( tableData ) ~= 'table' then
return
end
for _, data in pairs( tableData ) do
local name = data[nameKey] or ''
name = 'SMW_' .. prefix .. name:gsub('^%l', string.upper):gsub( ' ', '' )
if translateFn( name ) ~= nil then
local value
value = data[valueKey]
-- Handle percentage such as 10% used in modifiers
if type( value ) == 'string' and value:find( '%d+%%' ) then
value = string.gsub( value, '%%', '' ) / 100
end
setData[ translateFn( name ) ] = commonSMW.format( formatConfig, value )
end
end
end
return commonSMW