Module:SemanticAnnotations: Difference between revisions

// via Wikitext Extension for VSCode
// via Wikitext Extension for VSCode
Line 145: Line 145:
     -- Generate and return the annotations
     -- Generate and return the annotations
     return p.generateAnnotations(parentArgs, mappings, options)
     return p.generateAnnotations(parentArgs, mappings, options)
end
-- Helper function for processing a simple property mapping
local function processSimpleMapping(properties, propertyName, value, transformFunc, defaultValue)
    -- Apply transform if one exists and we have a value
    if value and value ~= "" and transformFunc then
        value = transformFunc(value)
    end
   
    -- Use value if it exists, otherwise use default
    if value and value ~= "" then
        -- If property already exists, convert to array or append
        if properties[propertyName] then
            -- Convert to array if it's the first duplicate
            if type(properties[propertyName]) ~= "table" then
                properties[propertyName] = {properties[propertyName]}
            end
            -- Append new value
            table.insert(properties[propertyName], value)
        else
            -- First value for this property
            properties[propertyName] = value
        end
    elseif defaultValue then
        properties[propertyName] = defaultValue
    end
end
-- Helper function for processing a complex property mapping with metadata
local function processComplexMapping(properties, propertyName, args, mappings, transformFunc)
    for _, mappingEntry in ipairs(mappings) do
        local param = mappingEntry.param
        local metadata = mappingEntry.metadata or {}
        local value = args[param]
       
        -- Process only if value exists
        if value and value ~= "" then
            -- Apply transform if available
            if transformFunc then
                value = transformFunc(value)
            end
           
            -- Add metadata qualifiers to property name if metadata exists
            local qualifiedProperty = propertyName
            if next(metadata) then
                local qualifiers = {}
                for metaKey, metaValue in pairs(metadata) do
                    table.insert(qualifiers, metaKey .. "=" .. metaValue)
                end
                -- Sort for consistency
                table.sort(qualifiers)
                qualifiedProperty = propertyName .. "#" .. table.concat(qualifiers, ";")
            end
           
            -- Set the property with qualified name
            if properties[qualifiedProperty] then
                -- Convert to array if it's the first duplicate
                if type(properties[qualifiedProperty]) ~= "table" then
                    properties[qualifiedProperty] = {properties[qualifiedProperty]}
                end
                -- Append new value
                table.insert(properties[qualifiedProperty], value)
            else
                -- First value for this property
                properties[qualifiedProperty] = value
            end
        end
        -- No need for goto continue - just continue the loop naturally
    end
end
-- Helper function for adding a simple property to parser function result
local function addSimplePropertyToResult(result, propertyName, value, transformFunc, defaultValue)
    -- Apply transform if one exists and we have a value
    if value and value ~= "" and transformFunc then
        value = transformFunc(value)
    end
   
    -- Use value if it exists, otherwise use default
    if value and value ~= "" then
        table.insert(result, string.format('    |%s=%s', propertyName, value))
        return 1
    elseif defaultValue then
        table.insert(result, string.format('    |%s=%s', propertyName, defaultValue))
        return 1
    end
   
    return 0
end
end


--[[
--[[
     Sets semantic properties using mw.smw API when available, with parser function fallback.
     Enhanced version of generateAnnotations that supports complex mappings
    Used as fallback when mw.smw is not available
]]
function p.generateEnhancedAnnotations(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
   
    -- Generate property sets for parser function
    for property, mapping in pairs(mappings) do
        local fullPropertyName = prefix .. property
       
        -- Handle different mapping types
        if type(mapping) == "string" then
            -- Legacy simple string mapping
            propertyCount = propertyCount + addSimplePropertyToResult(result,
                fullPropertyName, args[mapping], transform[property], default[property])
        elseif type(mapping) == "table" then
            if mapping.param then
                -- Single mapping with object structure
                propertyCount = propertyCount + addSimplePropertyToResult(result,
                    fullPropertyName, args[mapping.param], transform[property], default[property])
            elseif mapping.mappings then
                -- Complex mapping with multiple parameters
                for _, mappingEntry in ipairs(mapping.mappings) do
                    local param = mappingEntry.param
                    local metadata = mappingEntry.metadata or {}
                    local value = args[param]
                   
                    -- Process only if value exists
                    if value and value ~= "" then
                        -- Apply transform if available
                        if transform[property] then
                            value = transform[property](value)
                        end
                       
                        -- Add metadata qualifiers to property name if metadata exists
                        local qualifiedProperty = fullPropertyName
                        if next(metadata) then
                            local qualifiers = {}
                            for metaKey, metaValue in pairs(metadata) do
                                table.insert(qualifiers, metaKey .. "=" .. metaValue)
                            end
                            -- Sort for consistency
                            table.sort(qualifiers)
                            qualifiedProperty = fullPropertyName .. "#" .. table.concat(qualifiers, ";")
                        end
                       
                        -- Add the property to result
                        table.insert(result, string.format('    |%s=%s', qualifiedProperty, value))
                        propertyCount = propertyCount + 1
                    end
                    -- No need for goto continue - just continue the loop naturally
                end
            end
        end
    end
   
    -- Handle conditional properties (maintain backwards compatibility)
    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
 
--[[
    Enhanced version of setSemanticProperties that supports complex mappings
      
      
     @param args    - Template parameters
     @param args    - Template parameters
     @param mappings - Property to parameter mappings
     @param mappings - Property to parameter mappings with possible metadata
                      Format can be:
                      1. Simple: {["Property"] = "param_name"}
                      2. Object: {["Property"] = {param = "param_name"}}
                      3. Complex: {["Property"] = {mappings = {{param = "p1", metadata = {...}}, ...}}}
     @param options  - Configuration options (same as generateAnnotations)
     @param options  - Configuration options (same as generateAnnotations)
      
      
Line 159: Line 357:
     -- Check if mw.smw is available
     -- Check if mw.smw is available
     if not mw.smw then
     if not mw.smw then
         -- Fall back to the parser function approach if mw.smw is not available
         -- Fall back to enhanced parser function approach
         return p.generateAnnotations(args, mappings, options)
         return p.generateEnhancedAnnotations(args, mappings, options)
     end
     end
      
      
Line 171: Line 369:
     local properties = {}
     local properties = {}
      
      
     -- Process regular mappings
     -- Process all mappings
     for property, param in pairs(mappings) do
     for property, mapping in pairs(mappings) do
         local fullPropertyName = prefix .. property
         local fullPropertyName = prefix .. property
        local value = args[param]
          
          
         -- Apply transform if one exists
         -- Determine the type of mapping
         if value and transform[property] then
         if type(mapping) == "string" then
             value = transform[property](value)
             -- Legacy simple string mapping
        end
            processSimpleMapping(properties, fullPropertyName, args[mapping], transform[property], default[property])
       
         elseif type(mapping) == "table" then
        -- Use value if it exists, otherwise use default
             if mapping.param then
         if value and value ~= "" then
                -- Single mapping with object structure
             properties[fullPropertyName] = value
                processSimpleMapping(properties, fullPropertyName, args[mapping.param], transform[property], default[property])
        elseif default[property] then
            elseif mapping.mappings then
            properties[fullPropertyName] = default[property]
                -- Complex mapping with multiple parameters
                processComplexMapping(properties, fullPropertyName, args, mapping.mappings, transform[property])
            end
         end
         end
     end
     end
Line 201: Line 400:
             return ""
             return ""
         else
         else
             return p.generateAnnotations(args, mappings, options)
             return p.generateEnhancedAnnotations(args, mappings, options)
         end
         end
     end
     end