Jump to content

Module:TemplateHelpers: Difference between revisions

// via Wikitext Extension for VSCode
Tag: Reverted
// via Wikitext Extension for VSCode
Tag: Manual revert
Line 180: Line 180:
      
      
     return categories
     return categories
end
--------------------------------------------------------------------------------
-- Semantic Property Utilities
--------------------------------------------------------------------------------
-- Generates semantic properties based on a configuration and arguments
function p.generateSemanticProperties(args, semanticConfig)
    if not semanticConfig or not semanticConfig.properties then
        return ""
    end
   
    local output = ""
   
    -- Process basic property mappings
    for property, fieldKey in pairs(semanticConfig.properties) do
        if args[fieldKey] and args[fieldKey] ~= "" then
            local value = args[fieldKey]
           
            -- Apply transformation if available
            if semanticConfig.transforms and semanticConfig.transforms[property] then
                value = semanticConfig.transforms[property](value)
            end
           
            -- Add the property
            if mw.smw then
                local propSet = {}
                propSet[property] = value
                mw.smw.set(propSet)
            else
                output = output .. "\n" ..
                    '<div style="display:none;">\n  {{#set: ' .. property .. '=' ..
                    value .. ' }}\n</div>'
            end
        end
    end
   
    -- Process multi-value properties if configured
    if semanticConfig.multiValueProperties then
        for property, config in pairs(semanticConfig.multiValueProperties) do
            local fieldKey = config.field
            local delimiter = config.delimiter or ";"
            local transform = config.transform
           
            if args[fieldKey] and args[fieldKey] ~= "" then
                local values = p.splitSemicolonValues(args[fieldKey])
                for _, value in ipairs(values) do
                    if transform then
                        value = transform(value)
                    end
                   
                    if value and value ~= "" then
                        if mw.smw then
                            local propSet = {}
                            propSet[property] = value
                            mw.smw.set(propSet)
                        else
                            output = output .. "\n" ..
                                '<div style="display:none;">\n  {{#set: ' .. property .. '=' ..
                                value .. ' }}\n</div>'
                        end
                    end
                end
            end
        end
    end
   
    return output
end
-- Creates a standard config structure for templates
function p.createStandardConfig(config)
    -- Ensure all standard sections exist
    config = config or {}
    config.meta = config.meta or {
        description = "Template module"
    }
   
    -- Handle mappings
    config.mappings = config.mappings or {}
   
    -- For backward compatibility, copy mappings to top-level
    if config.mappings.type then
        config.typeMapping = config.mappings.type
    end
    if config.mappings.subtype then
        config.subtypeMapping = config.mappings.subtype
    end
    if config.mappings.community then
        config.communityMapping = config.mappings.community
    end
   
    config.fields = config.fields or {}
    config.semantics = config.semantics or {
        properties = {},
        multiValueProperties = {}
    }
    config.constants = config.constants or {}
    config.patterns = config.patterns or {}
   
    return config
end
end


return p
return p

Revision as of 00:31, 6 April 2025

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

-- Module:TemplateHelpers
-- Common helper functions for template modules to promote code reuse and consistency. This module provides utilities for string processing, field handling, normalization, and standardized block rendering to be used across multiple template types.

local p = {}

-- Dependencies
local linkParser = require('Module:LinkParser')
local MultiCountryDisplay = require('Module:MultiCountryDisplay')
local dateNormalization = require('Module:DateNormalization')
local CanonicalForms = require('Module:CanonicalForms')

--------------------------------------------------------------------------------
-- String Processing Functions
--------------------------------------------------------------------------------

-- Trims leading and trailing whitespace from a string
function p.trim(s)
    return (s:gsub("^%s+", ""):gsub("%s+$", ""))
end

-- Splits a semicolon-delimited string into a table of trimmed non-empty values
function p.splitSemicolonValues(value)
    if not value or value == "" then return {} end
    local items = {}
    for item in string.gmatch(value, "[^;]+") do
        local trimmed = item:match("^%s*(.-)%s*$")
        if trimmed and trimmed ~= "" then
            table.insert(items, trimmed)
        end
    end
    return items
end

-- Joins a table of values with the specified delimiter
function p.joinValues(values, delimiter)
    delimiter = delimiter or "; "
    if not values or #values == 0 then return "" end
    return table.concat(values, delimiter)
end

--------------------------------------------------------------------------------
-- Field Processing Functions
--------------------------------------------------------------------------------

-- Retrieves a field value from args using either multiple possible keys or a single key
function p.getFieldValue(args, field)
    if field.keys then
        for _, key in ipairs(field.keys) do
            if args[key] and args[key] ~= "" then
                return key, args[key]
            end
        end
        return nil, nil
    end
    return field.key, (args[field.key] and args[field.key] ~= "") and args[field.key] or nil
end

-- Processes multiple values with a given processor function
function p.processMultipleValues(values, processor)
    if not values or values == "" then return {} end
    local items = p.splitSemicolonValues(values)
    local results = {}
    for _, item in ipairs(items) do
        local processed = processor(item)
        if processed and processed ~= "" then
            table.insert(results, processed)
        end
    end
    return results
end

--------------------------------------------------------------------------------
-- Normalization Wrappers
--------------------------------------------------------------------------------

-- Formats website URLs as either a single link or an HTML unordered list of links
function p.normalizeWebsites(value)
    if not value or value == "" then return "" end
    local websites = p.splitSemicolonValues(value)
    if #websites > 1 then
        local listItems = {}
        for _, site in ipairs(websites) do
            local formattedLink = string.format("[%s %s]", site, linkParser.strip(site))
            table.insert(listItems, string.format("<li>%s</li>", formattedLink))
        end
        return string.format("<ul class=\"template-list template-list-website\" style=\"margin:0; padding-left:1em;\">%s</ul>", table.concat(listItems, ""))
    elseif #websites == 1 then
        return string.format("[%s %s]", websites[1], linkParser.strip(websites[1]))
    end
    return ""
end

-- Wrapper around MultiCountryDisplay for consistent country formatting
function p.normalizeCountries(value)
    if not value or value == "" then return "" end
    return MultiCountryDisplay.formatCountries(value)
end

-- Wrapper around DateNormalization for consistent date formatting
function p.normalizeDates(value)
    if not value or value == "" then return "" end
    return tostring(dateNormalization.formatDate(value))
end

--------------------------------------------------------------------------------
-- Block Generation Helpers
--------------------------------------------------------------------------------

-- Generates a standard title block with configurable class and text
function p.renderTitleBlock(args, titleClass, titleText)
    titleClass = titleClass or "template-title"
    return string.format('|-\n! colspan="2" class="%s" | %s', titleClass, titleText)
end

-- Renders a standard fields block based on field definitions and processors
function p.renderFieldsBlock(args, fields, processors)
    processors = processors or {}
    local out = {}
    
    for _, field in ipairs(fields) do
        local key, value = p.getFieldValue(args, field)
        if value then
            -- Apply processor if available for this field
            if key and processors[key] and type(processors[key]) == "function" then
                value = processors[key](value, args)
            end
            
            -- Skip insertion if processor returned nil or false
            if value ~= nil and value ~= false then
                table.insert(out, string.format("|-\n| '''%s''':\n| %s", field.label, value))
            end
        end
    end
    
    return table.concat(out, "\n")
end

-- Renders a standard divider block with optional label
function p.renderDividerBlock(label)
    if label and label ~= "" then
        return string.format('|-\n| colspan="2" class="template-divider" |\n|-\n| colspan="2" class="icannwiki-centered" | <span class="icannwiki-bold">%s</span>', label)
    else
        return '|-\n| colspan="2" class="template-divider" |'
    end
end

--------------------------------------------------------------------------------
-- Category Utilities
--------------------------------------------------------------------------------

-- Builds a category string from a table of category names
function p.buildCategories(categories)
    if not categories or #categories == 0 then return "" end
    local formatted = {}
    for _, cat in ipairs(categories) do
        -- Check if the category already has the [[ ]] wrapper
        if not string.match(cat, "^%[%[Category:") then
            table.insert(formatted, string.format("[[Category:%s]]", cat))
        else
            table.insert(formatted, cat)
        end
    end
    return table.concat(formatted, "\n")
end

-- Adds categories based on a canonical mapping
function p.addMappingCategories(value, mapping)
    if not value or value == "" or not mapping then return {} end
    local categories = {}
    local canonical = select(1, CanonicalForms.normalize(value, mapping))
    
    if canonical then
        for _, group in ipairs(mapping) do
            if group.canonical == canonical and group.category then
                table.insert(categories, group.category)
                break
            end
        end
    end
    
    return categories
end

return p