Module:SemanticAnnotations
Documentation for this module may be created at Module:SemanticAnnotations/doc
-- Module:SemanticAnnotations
-- A dedicated module for generating semantic annotations for templates
-- Compatible with Semantic MediaWiki, Semantic Scribunto, Semantic Drilldown, and DynamicPageList3
-- Annotations via Lua documentation: https://github.com/SemanticMediaWiki/SemanticScribunto/tree/master/docs
local p = {}
-- Private helper function to trim whitespace
local function trim(s)
return (s:gsub("^%s+", ""):gsub("%s+$", ""))
end
--[[
p.generateAnnotations(args, mappings)
Generates semantic annotations for MediaWiki templates using SMW's #set parser function.
Parameters:
args - Table of template parameters.
mappings - Table with mappings from semantic properties to template parameters:
{
["Has property name"] = "template_param_name",
["Has another property"] = "another_param",
...
}
options - Optional table of configuration options:
{
visible = false, -- Whether annotations should be visible (default: false)
prefix = "", -- Optional prefix for all properties
transform = {}, -- Table of transform functions for specific properties
-- e.g. { ["Has date"] = function(val) return format(val) end }
default = {}, -- Default values for properties if arg is missing
-- e.g. { ["Has type"] = "article" }
conditional = {}, -- Conditional property mapping that depend on other args
-- e.g. { ["Has special"] = { param = "type", value = "special" } }
}
Returns:
A string containing the wikitext for the semantic annotations.
]]
function p.generateAnnotations(args, mappings, options)
args = args or {}
mappings = mappings or {}
options = options or {}
-- Set defaults for options
local visible = options.visible or false
local prefix = options.prefix or ""
local transform = options.transform or {}
local default = options.default or {}
local conditional = options.conditional or {}
-- Start building the annotation block
local result = {}
-- Determine if we need the hidden div wrapper
if not visible then
table.insert(result, '<div style="display:none;">')
end
-- Start the #set parser function
table.insert(result, ' {{#set:')
-- Process all property mappings
local propertyCount = 0
-- Handle regular property mappings
for property, param in pairs(mappings) do
local fullPropertyName = prefix .. property
local value = args[param]
-- Apply transform if one exists for this property
if value and transform[property] then
value = transform[property](value)
end
-- Use the value if it exists, otherwise use default if provided
if value and value ~= "" then
table.insert(result, string.format(' |%s=%s', fullPropertyName, value))
propertyCount = propertyCount + 1
elseif default[property] then
table.insert(result, string.format(' |%s=%s', fullPropertyName, default[property]))
propertyCount = propertyCount + 1
end
end
-- Handle conditional properties
for property, condition in pairs(conditional) do
local fullPropertyName = prefix .. property
if args[condition.param] and args[condition.param] == condition.value then
table.insert(result, string.format(' |%s=%s', fullPropertyName, condition.target or "true"))
propertyCount = propertyCount + 1
end
end
-- Close the #set parser function
table.insert(result, ' }}')
-- Close the hidden div if we're using it
if not visible then
table.insert(result, '</div>')
end
-- If no properties were set, return an empty string
if propertyCount == 0 then
return ""
end
-- Join all lines and return
return table.concat(result, "\n")
end
--[[
p.renderWithSemantics(args, config, semanticMappings, semanticOptions)
Renders a table using TemplateStructure and adds semantic annotations.
Parameters:
args - Table of template parameters.
config - Configuration for TemplateStructure.render.
semanticMappings - Mappings from semantic properties to template parameters.
semanticOptions - Optional configuration for semantic annotations.
Returns:
A string containing the rendered template with semantic annotations.
]]
function p.renderWithSemantics(args, config, semanticMappings, semanticOptions)
local TemplateStructure = require('Module:TemplateStructure')
-- Render the table structure
local renderedTable = TemplateStructure.render(args, config)
-- Generate the semantic annotations
local annotations = p.generateAnnotations(args, semanticMappings, semanticOptions)
-- Combine and return
return renderedTable .. "\n" .. annotations
end
-- This function is an alternative to using the full renderWithSemantics.
-- It allows direct template transcusions to just append semantic annotations.
function p.appendToTemplate(frame)
local args = frame.args
local parent = frame:getParent()
local parentArgs = parent and parent.args or {}
-- Mapping is defined as pairs of properties and parameters
local mappings = {}
local i = 1
while args["property" .. i] and args["param" .. i] do
mappings[args["property" .. i]] = args["param" .. i]
i = i + 1
end
-- Extract options
local options = {
visible = args.visible == "true",
prefix = args.prefix or ""
}
-- Generate and return the annotations
return p.generateAnnotations(parentArgs, mappings, options)
end
--[[
p.setSemanticProperties(args, mappings, options)
Sets semantic properties using the native mw.smw API when available,
falling back to the parser function approach if not.
Parameters:
args - Table of template parameters.
mappings - Table with mappings from semantic properties to template parameters.
options - Optional configuration options (same as generateAnnotations).
Returns:
Empty string if properties were set via mw.smw, otherwise the generated annotations.
]]
function p.setSemanticProperties(args, mappings, options)
-- Check if mw.smw is available
if not mw.smw then
-- Fall back to the parser function approach if mw.smw is not available
return p.generateAnnotations(args, mappings, options)
end
options = options or {}
local transform = options.transform or {}
local default = options.default or {}
local prefix = options.prefix or ""
-- Build the property table for mw.smw.set
local properties = {}
-- Process regular mappings
for property, param in pairs(mappings) do
local fullPropertyName = prefix .. property
local value = args[param]
-- Apply transform if one exists
if value and transform[property] then
value = transform[property](value)
end
-- Use value if it exists, otherwise use default
if value and value ~= "" then
properties[fullPropertyName] = value
elseif default[property] then
properties[fullPropertyName] = default[property]
end
end
-- Only set properties if we have some
if next(properties) then
-- Set the properties using the native SMW interface
local success, result = pcall(function()
return mw.smw.set(properties)
end)
-- If successful, return empty string (properties are set behind the scenes)
-- If failed, fall back to parser function approach
if success then
return ""
else
return p.generateAnnotations(args, mappings, options)
end
end
return ""
end
return p