Module:LuaTemplateBlueprint: Difference between revisions

// via Wikitext Extension for VSCode
Tag: Manual revert
MAJOR REVISION: BETTER PROPERTY HANDLING AND LIMITING // via Wikitext Extension for VSCode
Tag: Reverted
Line 901: Line 901:
         transform = transforms
         transform = transforms
     }
     }
   
    -- CRITICAL: Early bounds checking
    local PROPERTY_LIMIT = 150  -- Conservative limit below SMW's 200
    local VALUE_LIMIT = 20 -- Per-property value limit below SMW's 25
    local propertyCount = 0
    local valueCounts = {}
   
    -- Helper function to check if we can add more properties
    local function canAddProperty(propertyName, valueCount)
        valueCount = valueCount or 1
       
        -- Check total property limit
        if propertyCount >= PROPERTY_LIMIT then
            return false, "Property limit reached (" .. PROPERTY_LIMIT .. ")"
        end
       
        -- Check per-property value limit
        local currentCount = valueCounts[propertyName] or 0
        if currentCount + valueCount > VALUE_LIMIT then
            return false, "Value limit reached for " .. propertyName .. " (" .. VALUE_LIMIT .. ")"
        end
       
        return true
    end
   
    -- Helper function to safely add a property
    local function safeAddProperty(allProps, propName, value)
        if not value or value == '' then return end
       
        -- Count values to add
        local valuesToAdd = 1
        if type(value) == "table" then
            valuesToAdd = #value
        end
       
        -- Check if we can add
        local canAdd, reason = canAddProperty(propName, valuesToAdd)
        if not canAdd then
            -- Log warning but don't crash
            if template._errorContext then
                ErrorHandling.addError(
                    template._errorContext,
                    'SemanticPropertyLimit',
                    reason,
                    propName,
                    false
                )
            end
            return
        end
       
        -- Add the property
        if allProps[propName] then
            -- Convert to array if needed
            if type(allProps[propName]) ~= "table" then
                allProps[propName] = {allProps[propName]}
                valueCounts[propName] = 1
            end
           
            -- Add new values with limit checking
            if type(value) == "table" then
                for _, v in ipairs(value) do
                    if valueCounts[propName] < VALUE_LIMIT then
                        table.insert(allProps[propName], v)
                        valueCounts[propName] = valueCounts[propName] + 1
                    end
                end
            else
                if valueCounts[propName] < VALUE_LIMIT then
                    table.insert(allProps[propName], value)
                    valueCounts[propName] = valueCounts[propName] + 1
                end
            end
        else
            -- New property
            allProps[propName] = value
            propertyCount = propertyCount + 1
            valueCounts[propName] = type(value) == "table" and #value or 1
        end
    end
      
      
     -- Collect all properties in a single batch for complete deduplication
     -- Collect all properties in a single batch for complete deduplication
Line 908: Line 988:
     for property, param in pairs(properties) do
     for property, param in pairs(properties) do
         -- Perform case-insensitive lookup for the parameter key
         -- Perform case-insensitive lookup for the parameter key
         local keyName, _ = TemplateHelpers.getFieldValue(args, { key = param })
         local keyName, value = TemplateHelpers.getFieldValue(args, { key = param })
         allProperties[property] = keyName or param
         if value and value ~= '' then
            safeAddProperty(allProperties, property, value)
        end
     end
     end
      
      
Line 922: Line 1,004:
                     local transformed = applyTransform(rawValue, property, transform, args, template)
                     local transformed = applyTransform(rawValue, property, transform, args, template)
                     if transformed and transformed ~= '' then
                     if transformed and transformed ~= '' then
                         local existing = allProperties[property]
                         safeAddProperty(allProperties, property, transformed)
                        if existing == nil then
                            allProperties[property] = transformed
                        else
                            if type(existing) ~= "table" then
                                allProperties[property] = { existing }
                            end
                            -- Add only if not already present
                            local found = false
                            for _, v in ipairs(allProperties[property]) do
                                if v == transformed then
                                    found = true
                                    break
                                end
                            end
                            if not found then
                                table.insert(allProperties[property], transformed)
                            end
                        end
                     end
                     end
                 end
                 end
Line 965: Line 1,029:
                 -- Skip if explicitly marked to skip (double-check)
                 -- Skip if explicitly marked to skip (double-check)
                 if not skipProperties[property] then
                 if not skipProperties[property] then
                     if not allProperties[property] then
                     safeAddProperty(allProperties, property, values)
                        -- Property doesn't exist yet, add directly
                        allProperties[property] = values
                    else
                        -- Property already exists, merge with existing values
                        if type(allProperties[property]) ~= "table" then
                            -- Convert existing value to array
                            allProperties[property] = {allProperties[property]}
                        end
                       
                        -- Add unique values
                        local seenValues = {}
                        for _, v in ipairs(allProperties[property]) do
                            seenValues[v] = true
                        end
                       
                        for _, v in ipairs(values) do
                            if not seenValues[v] then
                                seenValues[v] = true
                                table.insert(allProperties[property], v)
                            end
                        end
                    end
                 end
                 end
             end
             end
Line 1,010: Line 1,052:
                     -- Skip properties marked to skip
                     -- Skip properties marked to skip
                     if not skipProperties[property] then
                     if not skipProperties[property] then
                         if type(value) == "table" then
                         safeAddProperty(allProperties, property, value)
                            -- Provider returned an array of values
                            if allProperties[property] then
                                -- Property already exists, merge arrays with deduplication
                                if type(allProperties[property]) ~= "table" then
                                    -- Convert existing value to array
                                    allProperties[property] = {allProperties[property]}
                                end
                               
                                -- Track seen values
                                local seenValues = {}
                                for _, v in ipairs(allProperties[property]) do
                                    seenValues[v] = true
                                end
                               
                                -- Add unique values from provider
                                for _, v in ipairs(value) do
                                    if not seenValues[v] then
                                        seenValues[v] = true
                                        table.insert(allProperties[property], v)
                                    end
                                end
                            else
                                -- Property doesn't exist yet, add with internal deduplication
                                local seenValues = {}
                                local uniqueValues = {}
                               
                                for _, v in ipairs(value) do
                                    if not seenValues[v] then
                                        seenValues[v] = true
                                        table.insert(uniqueValues, v)
                                    end
                                end
                               
                                allProperties[property] = uniqueValues
                            end
                        else
                            -- Provider returned a single value
                            if allProperties[property] then
                                -- Property already exists
                                if type(allProperties[property]) == "table" then
                                    -- Existing property is an array, add value if unique
                                    local seen = false
                                    for _, v in ipairs(allProperties[property]) do
                                        if v == value then
                                            seen = true
                                            break
                                        end
                                    end
                                   
                                    if not seen then
                                        table.insert(allProperties[property], value)
                                    end
                                elseif allProperties[property] ~= value then
                                    -- Convert to array with both values
                                    allProperties[property] = {allProperties[property], value}
                                end
                                -- If existing value equals new value, no change needed
                            else
                                -- Property doesn't exist yet, add directly
                                allProperties[property] = value
                            end
                        end
                     end
                     end
                 end
                 end
Line 1,088: Line 1,068:
     ]]
     ]]
     -- Override raw country/region with normalized names
     -- Override raw country/region with normalized names
     local cr = require('Module:ConfigRepository')
     if args.country and args.country ~= '' then
    local cd = require('Module:CountryData')
        local cr = require('Module:ConfigRepository')
    local norm = p.protectedExecute(
        local cd = require('Module:CountryData')
        template,
        local norm = p.protectedExecute(
        'CountryData_Override',
            template,
        function() return cd.getSemanticCountryRegionProperties(args.country) end,
            'CountryData_Override',
        {},
            function() return cd.getSemanticCountryRegionProperties(args.country) end,
        args.country
            {},
    )
            args.country
    local countryKey = cr.semanticProperties.country
        )
    local regionKey = cr.semanticProperties.region
        local countryKey = cr.semanticProperties.country
    allProperties[countryKey] = norm[countryKey]
        local regionKey = cr.semanticProperties.region
    allProperties[regionKey] = norm[regionKey]
       
        -- Use safe property addition for the override
        if norm[countryKey] then
            -- Remove existing values first to ensure clean override
            allProperties[countryKey] = nil
            valueCounts[countryKey] = nil
            propertyCount = propertyCount - 1
            safeAddProperty(allProperties, countryKey, norm[countryKey])
        end
       
        if norm[regionKey] then
            -- Remove existing values first to ensure clean override
            allProperties[regionKey] = nil
            valueCounts[regionKey] = nil
            propertyCount = propertyCount - 1
            safeAddProperty(allProperties, regionKey, norm[regionKey])
        end
    end
   
     local semanticOutput = SemanticAnnotations.setSemanticProperties(
     local semanticOutput = SemanticAnnotations.setSemanticProperties(
         args,
         args,