Jump to content

Module:SemanticAnnotations: Difference between revisions

// via Wikitext Extension for VSCode
 
// via Wikitext Extension for VSCode
Line 161: Line 161:
     -- Generate and return the annotations
     -- Generate and return the annotations
     return p.generateAnnotations(parentArgs, mappings, options)
     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
end


return p
return p

Revision as of 01:18, 31 March 2025

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

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