Module:TemplateHelpers: Difference between revisions
Appearance
// via Wikitext Extension for VSCode |
Separation // via Wikitext Extension for VSCode |
||
| Line 10: | Line 10: | ||
local dateNormalization = require('Module:DateNormalization') | local dateNormalization = require('Module:DateNormalization') | ||
local CanonicalForms = require('Module:CanonicalForms') | local CanonicalForms = require('Module:CanonicalForms') | ||
local SemanticCategoryHelpers = require('Module:SemanticCategoryHelpers') | |||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
| Line 247: | Line 248: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
-- Category Utilities | -- Category and Semantic Utilities | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
-- | -- These functions have been moved to Module:SemanticCategoryHelpers | ||
-- | -- Wrapper functions are provided for backward compatibility | ||
-- Generic function to split multi-value strings with various delimiters | -- Generic function to split multi-value strings with various delimiters | ||
function p.splitMultiValueString(...) | |||
function p.splitMultiValueString( | return SemanticCategoryHelpers.splitMultiValueString(...) | ||
end | end | ||
-- Splits a region string that may contain "and" conjunctions | -- Splits a region string that may contain "and" conjunctions | ||
function p.splitRegionCategories(...) | |||
return SemanticCategoryHelpers.splitRegionCategories(...) | |||
function p.splitRegionCategories( | |||
return | |||
end | end | ||
-- Builds a category string from a table of category names | -- Builds a category string from a table of category names | ||
function p.buildCategories(...) | |||
function p.buildCategories( | return SemanticCategoryHelpers.buildCategories(...) | ||
end | end | ||
-- Adds categories based on a canonical mapping | -- Adds categories based on a canonical mapping | ||
function p.addMappingCategories( | function p.addMappingCategories(...) | ||
return SemanticCategoryHelpers.addMappingCategories(...) | |||
end | end | ||
-- Generic function to add multi-value semantic properties | -- Generic function to add multi-value semantic properties | ||
function p.addMultiValueSemanticProperties(...) | |||
function p.addMultiValueSemanticProperties( | return SemanticCategoryHelpers.addMultiValueSemanticProperties(...) | ||
end | end | ||
-- Generic function to add multi-value categories | -- Generic function to add multi-value categories | ||
function p.addMultiValueCategories(...) | |||
function p.addMultiValueCategories( | return SemanticCategoryHelpers.addMultiValueCategories(...) | ||
end | end | ||
-- Adds semantic properties for multiple countries | -- Adds semantic properties for multiple countries | ||
function p.addMultiCountrySemanticProperties(...) | |||
return SemanticCategoryHelpers.addMultiCountrySemanticProperties(...) | |||
function p.addMultiCountrySemanticProperties( | |||
return | |||
end | end | ||
-- Adds semantic properties for multiple regions | -- Adds semantic properties for multiple regions | ||
function p.addMultiRegionSemanticProperties(...) | |||
return SemanticCategoryHelpers.addMultiRegionSemanticProperties(...) | |||
function p.addMultiRegionSemanticProperties( | |||
end | end | ||
-- Adds semantic properties for multiple languages | -- Adds semantic properties for multiple languages | ||
function p.addMultiLanguageSemanticProperties(...) | |||
return SemanticCategoryHelpers.addMultiLanguageSemanticProperties(...) | |||
function p.addMultiLanguageSemanticProperties( | |||
return | |||
end | end | ||
-- Helper function to process additional properties with multi-value support | -- Helper function to process additional properties with multi-value support | ||
function p.processAdditionalProperties(...) | |||
function p.processAdditionalProperties( | return SemanticCategoryHelpers.processAdditionalProperties(...) | ||
end | end | ||
-- Helper function to check if a field contains multiple values | -- Helper function to check if a field contains multiple values | ||
function p.isMultiValueField( | function p.isMultiValueField(...) | ||
return SemanticCategoryHelpers.isMultiValueField(...) | |||
end | end | ||
-- Generates semantic properties based on configuration | -- Generates semantic properties based on configuration | ||
function p.generateSemanticProperties(...) | |||
return SemanticCategoryHelpers.generateSemanticProperties(...) | |||
function p.generateSemanticProperties( | |||
end | end | ||
Revision as of 18:26, 10 April 2025
Documentation for this module may be created at Module:TemplateHelpers/doc
-- Module:TemplateHelpers
-- Common helper functions for template modules promoting code reuse and consistency.
-- Provides utilities for string processing, field handling, normalization, and block rendering.
local p = {}
-- Dependencies
local linkParser = require('Module:LinkParser')
local MultiCountryDisplay = require('Module:MultiCountryDisplay')
local dateNormalization = require('Module:DateNormalization')
local CanonicalForms = require('Module:CanonicalForms')
local SemanticCategoryHelpers = require('Module:SemanticCategoryHelpers')
--------------------------------------------------------------------------------
-- String Processing Functions
--------------------------------------------------------------------------------
-- Normalizes template arguments to be case-insensitive
-- Returns a new table with lowercase keys while preserving original keys as well
-- Also handles empty numeric parameters that can occur with {{Template|}} syntax
function p.normalizeArgumentCase(args)
local normalized = {}
-- Process all keys
for key, value in pairs(args) do
-- Skip empty numeric parameters (created by leading pipes after template name)
if type(key) == "number" and (value == nil or value == "") then
-- Do nothing with empty numeric parameters
else
-- For all other parameters, add lowercase version
if type(key) == "string" then
normalized[key:lower()] = value
end
-- Preserve original key as well
normalized[key] = value
end
end
return normalized
end
-- 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
-- This is now a wrapper around splitMultiValueString for backward compatibility
function p.splitSemicolonValues(value)
-- For backward compatibility, maintain the same behavior
return p.splitMultiValueString(value, {
{pattern = ";%s*", replacement = ";"}
})
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
-- Now supports case-insensitive lookup by default
function p.getFieldValue(args, field)
if field.keys then
for _, key in ipairs(field.keys) do
-- First try exact match to maintain backward compatibility
if args[key] and args[key] ~= "" then
return key, args[key]
end
-- Then try lowercase version
local lowerKey = key:lower()
if args[lowerKey] and args[lowerKey] ~= "" and lowerKey ~= key then
return lowerKey, args[lowerKey]
end
end
return nil, nil
end
-- First try exact match
if args[field.key] and args[field.key] ~= "" then
return field.key, args[field.key]
end
-- Then try lowercase version
local lowerKey = field.key:lower()
if args[lowerKey] and args[lowerKey] ~= "" and lowerKey ~= field.key then
return lowerKey, args[lowerKey]
end
return field.key, nil
end
-- Processes multiple values with a given processor function
-- Uses splitMultiValueString for more flexible delimiter handling
-- Pre-allocates result table for better performance
function p.processMultipleValues(values, processor)
if not values or values == "" then return {} end
local items = p.splitMultiValueString(values)
-- Pre-allocate results table based on input size
local results = {}
local resultIndex = 1
for _, item in ipairs(items) do
local processed = processor(item)
if processed and processed ~= "" then
results[resultIndex] = processed
resultIndex = resultIndex + 1
end
end
return results
end
--------------------------------------------------------------------------------
-- Normalization Wrappers
--------------------------------------------------------------------------------
-- Formats website URLs as either a single link or an HTML unordered list of links
-- Uses splitMultiValueString for more flexible delimiter handling
-- Optimized to avoid unnecessary table creation for single websites
function p.normalizeWebsites(value)
if not value or value == "" then return "" end
-- Quick check for single website (no delimiters)
if not value:match(";") and not value:match("%s+and%s+") then
-- Single website case - avoid table creation entirely
return string.format("[%s %s]", value, linkParser.strip(value))
end
-- Multiple websites case
local websites = p.splitMultiValueString(value)
if #websites > 1 then
-- Pre-allocate listItems table based on number of websites
local listItems = {}
local index = 1
for _, site in ipairs(websites) do
local formattedLink = string.format("[%s %s]", site, linkParser.strip(site))
listItems[index] = string.format("<li>%s</li>", formattedLink)
index = index + 1
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
-- Enhanced to support achievement integration with options
function p.renderTitleBlock(args, titleClass, titleText, options)
options = options or {}
titleClass = titleClass or "template-title"
-- Basic title block without achievement integration
if not options.achievementSupport then
return string.format('|-\n! colspan="2" class="%s" | %s', titleClass, titleText)
end
-- With achievement support
local achievementClass = options.achievementClass or ""
local achievementId = options.achievementId or ""
local achievementName = options.achievementName or ""
-- Only add achievement attributes if they exist
if achievementClass ~= "" and achievementId ~= "" then
return string.format(
'|-\n! colspan="2" class="%s %s" data-achievement-id="%s" data-achievement-name="%s" | %s',
titleClass, achievementClass, achievementId, achievementName, titleText
)
else
-- Clean row with no achievement data
return string.format('|-\n! colspan="2" class="%s" | %s', titleClass, titleText)
end
end
-- Renders a standard fields block based on field definitions and processors
-- Enhanced to support complete HTML blocks and custom field rendering
-- Pre-allocates output table for better performance
function p.renderFieldsBlock(args, fields, processors)
processors = processors or {}
-- Pre-allocate output table - estimate based on number of fields
-- Not all fields may be present in args, but this gives us a reasonable upper bound
local out = {}
local outIndex = 1
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
local processedValue = processors[key](value, args)
-- Handle the case where a processor returns complete HTML
if type(processedValue) == "table" and processedValue.isCompleteHtml then
-- Add the complete HTML as is
out[outIndex] = processedValue.html
outIndex = outIndex + 1
elseif processedValue ~= nil and processedValue ~= false then
-- Standard field rendering
out[outIndex] = string.format("|-\n| '''%s''':\n| %s", field.label, processedValue)
outIndex = outIndex + 1
end
else
-- Standard field rendering without processor
out[outIndex] = string.format("|-\n| '''%s''':\n| %s", field.label, value)
outIndex = outIndex + 1
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 and Semantic Utilities
--------------------------------------------------------------------------------
-- These functions have been moved to Module:SemanticCategoryHelpers
-- Wrapper functions are provided for backward compatibility
-- Generic function to split multi-value strings with various delimiters
function p.splitMultiValueString(...)
return SemanticCategoryHelpers.splitMultiValueString(...)
end
-- Splits a region string that may contain "and" conjunctions
function p.splitRegionCategories(...)
return SemanticCategoryHelpers.splitRegionCategories(...)
end
-- Builds a category string from a table of category names
function p.buildCategories(...)
return SemanticCategoryHelpers.buildCategories(...)
end
-- Adds categories based on a canonical mapping
function p.addMappingCategories(...)
return SemanticCategoryHelpers.addMappingCategories(...)
end
-- Generic function to add multi-value semantic properties
function p.addMultiValueSemanticProperties(...)
return SemanticCategoryHelpers.addMultiValueSemanticProperties(...)
end
-- Generic function to add multi-value categories
function p.addMultiValueCategories(...)
return SemanticCategoryHelpers.addMultiValueCategories(...)
end
-- Adds semantic properties for multiple countries
function p.addMultiCountrySemanticProperties(...)
return SemanticCategoryHelpers.addMultiCountrySemanticProperties(...)
end
-- Adds semantic properties for multiple regions
function p.addMultiRegionSemanticProperties(...)
return SemanticCategoryHelpers.addMultiRegionSemanticProperties(...)
end
-- Adds semantic properties for multiple languages
function p.addMultiLanguageSemanticProperties(...)
return SemanticCategoryHelpers.addMultiLanguageSemanticProperties(...)
end
-- Helper function to process additional properties with multi-value support
function p.processAdditionalProperties(...)
return SemanticCategoryHelpers.processAdditionalProperties(...)
end
-- Helper function to check if a field contains multiple values
function p.isMultiValueField(...)
return SemanticCategoryHelpers.isMultiValueField(...)
end
-- Generates semantic properties based on configuration
function p.generateSemanticProperties(...)
return SemanticCategoryHelpers.generateSemanticProperties(...)
end
--------------------------------------------------------------------------------
-- Configuration Standardization
--------------------------------------------------------------------------------
-- Creates a standardized configuration structure for template modules
function p.createStandardConfig(config)
config = config or {}
-- Initialize with defaults
local standardConfig = {
meta = config.meta or {
description = "Template module configuration"
},
mappings = config.mappings or {},
fields = config.fields or {},
semantics = config.semantics or {
properties = {},
transforms = {},
additionalProperties = {}
},
constants = config.constants or {},
patterns = config.patterns or {}
}
return standardConfig
end
return p