Module:SemanticAnnotations: Difference between revisions
// via Wikitext Extension for VSCode |
// via Wikitext Extension for VSCode |
||
| (31 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
-- | --[[ | ||
* Name: SemanticAnnotations | |||
* Author: Mark W. Datysgeld | |||
* Description: Primary semantic integration module for generating semantic properties with transformation support and property limits | |||
* Notes: Implements batching, deduplication and property limits (200 total, 25 per property); supports simple, object, complex, and subobject mappings; falls back to parser functions when mw.smw unavailable; includes pruning to prevent server crashes | |||
]] | |||
local p = {} | local p = {} | ||
local TemplateHelpers = require('Module:TemplateHelpers') | |||
local NormalizationText = require('Module:NormalizationText') | |||
-- | -- Limits to prevent server crashes | ||
local | local TOTAL_LIMIT = 200 -- per page render, tune later | ||
local VALUE_LIMIT = 25 -- per individual property | |||
--[[ | --[[ Fallback for mw.smw.set using the #set parser function. | ||
@param args - Template parameters | @param args - Template parameters | ||
@param mappings - Property mappings: {["Property"] = "param"} or complex format | @param mappings - Property mappings: {["Property"] = "param"} or complex format | ||
| Line 42: | Line 48: | ||
if type(param) == "string" then | if type(param) == "string" then | ||
local fullPropertyName = prefix .. property | local fullPropertyName = prefix .. property | ||
local value = args | local _, value = TemplateHelpers.getFieldValue(args, { key = param }) | ||
-- Apply transform if needed | -- Apply transform if needed | ||
| Line 61: | Line 67: | ||
for property, condition in pairs(conditional) do | for property, condition in pairs(conditional) do | ||
local fullPropertyName = prefix .. property | local fullPropertyName = prefix .. property | ||
local _, condValue = TemplateHelpers.getFieldValue(args, { key = condition.param }) | |||
if condValue == condition.value then | |||
table.insert(result, string.format(' |%s=%s', fullPropertyName, condition.target or "true")) | table.insert(result, string.format(' |%s=%s', fullPropertyName, condition.target or "true")) | ||
propertyCount = propertyCount + 1 | propertyCount = propertyCount + 1 | ||
| Line 75: | Line 82: | ||
end | end | ||
-- | -- Prune properties to prevent server crashes | ||
function | local function prune(properties) | ||
local | local total = 0 | ||
local TemplateHelpers = require('Module:TemplateHelpers') | |||
-- | for prop,val in pairs(properties) do | ||
if type(val)=='table' then | |||
-- dedup array using centralized removeDuplicates function | |||
properties[prop] = TemplateHelpers.removeDuplicates(val) | |||
end | |||
-- per-property cap | |||
if type(properties[prop])=='table' and #properties[prop] > VALUE_LIMIT then | |||
properties[prop] = { unpack(properties[prop],1,VALUE_LIMIT) } | |||
end | |||
-- global counter | |||
total = total + (type(properties[prop])=='table' and #properties[prop] or 1) | |||
end | end | ||
if total > TOTAL_LIMIT then return nil, "SMW limit hit: "..total end | |||
return properties | |||
return | |||
end | end | ||
| Line 131: | Line 129: | ||
local param = mappingEntry.param | local param = mappingEntry.param | ||
local metadata = mappingEntry.metadata or {} | local metadata = mappingEntry.metadata or {} | ||
local value = args[param] | -- Case-insensitive lookup: try exact match first, then lowercase | ||
local value = args[param] or args[param:lower()] | |||
if value and value ~= "" then | if value and value ~= "" then | ||
| Line 175: | Line 174: | ||
end | end | ||
-- Enhanced | -- Enhanced fallback for mw.smw.set with complex mapping support. | ||
function p.generateEnhancedAnnotations(args, mappings, options) | function p.generateEnhancedAnnotations(args, mappings, options) | ||
args = args or {} | args = args or {} | ||
| Line 199: | Line 198: | ||
if type(mapping) == "string" then | if type(mapping) == "string" then | ||
-- Simple string mapping | -- Simple string mapping with case-insensitive lookup | ||
local value = args[mapping] or args[mapping:lower()] | |||
propertyCount = propertyCount + addSimplePropertyToResult(result, | propertyCount = propertyCount + addSimplePropertyToResult(result, | ||
fullPropertyName, | fullPropertyName, value, transform[property], default[property]) | ||
elseif type(mapping) == "table" then | elseif type(mapping) == "table" then | ||
if mapping.param then | if mapping.param then | ||
-- Object with param structure | -- Object with param structure with case-insensitive lookup | ||
local value = args[mapping.param] or args[mapping.param:lower()] | |||
propertyCount = propertyCount + addSimplePropertyToResult(result, | propertyCount = propertyCount + addSimplePropertyToResult(result, | ||
fullPropertyName, | fullPropertyName, value, transform[property], default[property]) | ||
elseif mapping.mappings then | elseif mapping.mappings then | ||
-- Complex mapping with multiple parameters | -- Complex mapping with multiple parameters | ||
| Line 212: | Line 213: | ||
local param = mappingEntry.param | local param = mappingEntry.param | ||
local metadata = mappingEntry.metadata or {} | local metadata = mappingEntry.metadata or {} | ||
local value = args[param] | -- Case-insensitive lookup | ||
local value = args[param] or args[param:lower()] | |||
if value and value ~= "" then | if value and value ~= "" then | ||
| Line 255: | Line 257: | ||
end | end | ||
--[[ Sets semantic properties | --[[ Sets semantic properties using the native mw.smw API. | ||
This is the primary function for setting semantic data. | |||
@param args - Template parameters | @param args - Template parameters | ||
@param mappings - Property mappings in formats: | @param mappings - Property mappings in formats: | ||
| Line 281: | Line 284: | ||
if type(mapping) == "string" then | if type(mapping) == "string" then | ||
-- Simple string mapping | -- Simple string mapping with case-insensitive lookup | ||
processSimpleMapping(properties, fullPropertyName, | -- Try exact match first, then lowercase | ||
local value = args[mapping] or args[mapping:lower()] | |||
processSimpleMapping(properties, fullPropertyName, value, transform[property], default[property]) | |||
elseif type(mapping) == "table" then | elseif type(mapping) == "table" then | ||
if mapping.is_subobject then | if mapping.is_subobject then | ||
| Line 339: | Line 344: | ||
end | end | ||
elseif mapping.param then | elseif mapping.param then | ||
-- Single mapping with object structure | -- Single mapping with object structure with case-insensitive lookup | ||
processSimpleMapping(properties, fullPropertyName, | local value = args[mapping.param] or args[mapping.param:lower()] | ||
processSimpleMapping(properties, fullPropertyName, value, transform[property], default[property]) | |||
elseif mapping.mappings then | elseif mapping.mappings then | ||
-- Complex mapping with multiple parameters | -- Complex mapping with multiple parameters | ||
processComplexMapping(properties, fullPropertyName, args, mapping.mappings, transform[property]) | processComplexMapping(properties, fullPropertyName, args, mapping.mappings, transform[property]) | ||
else | |||
-- Direct array of values: add each value as a property | |||
for _, value in ipairs(mapping) do | |||
processSimpleMapping(properties, fullPropertyName, value, transform[property], default[property]) | |||
end | |||
end | end | ||
end | end | ||
end | |||
-- Before setting properties, prune them | |||
local pruned, err = prune(properties) | |||
if not pruned then | |||
-- Add HTML comment with error message | |||
semanticOutput = semanticOutput .. "\n<!-- " .. err .. " -->" | |||
return semanticOutput | |||
end | end | ||
-- Set properties if any exist | -- Set properties if any exist | ||
if next( | if next(pruned) then | ||
local success, result = pcall(function() return mw.smw.set( | local success, result = pcall(function() return mw.smw.set(pruned) end) | ||
if success then return semanticOutput | if success then return semanticOutput | ||
else return p.generateEnhancedAnnotations(args, mappings, options) .. semanticOutput | else return p.generateEnhancedAnnotations(args, mappings, options) .. semanticOutput | ||
| Line 373: | Line 392: | ||
return result | return result | ||
end | end | ||
return p | return p | ||